From 842b4978292048b323ee93f5dbf369d806cd05b5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 14 Feb 2023 01:44:02 +0300 Subject: [PATCH 01/41] Show RSSI in weather station app and in pocsag pager app --- .../scenes/pocsag_pager_receiver.c | 4 +++ .../views/pocsag_pager_receiver.c | 35 +++++++++++++++++-- .../views/pocsag_pager_receiver.h | 2 ++ .../scenes/weather_station_receiver.c | 4 +++ .../views/weather_station_receiver.c | 34 ++++++++++++++++-- .../views/weather_station_receiver.h | 2 ++ 6 files changed, 77 insertions(+), 4 deletions(-) diff --git a/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c b/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c index 3f41b9b5d2..658b70fea2 100644 --- a/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c +++ b/applications/plugins/pocsag_pager/scenes/pocsag_pager_receiver.c @@ -195,6 +195,10 @@ bool pocsag_pager_scene_receiver_on_event(void* context, SceneManagerEvent event pcsg_hopper_update(app); pocsag_pager_scene_receiver_update_statusbar(app); } + // Get current RSSI + float rssi = furi_hal_subghz_get_rssi(); + pcsg_receiver_rssi(app->pcsg_receiver, rssi); + if(app->txrx->txrx_state == PCSGTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); } diff --git a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c index 76545b2389..62a2b29685 100644 --- a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c +++ b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.c @@ -12,6 +12,8 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f + typedef struct { FuriString* item_str; uint8_t type; @@ -58,8 +60,24 @@ typedef struct { uint16_t list_offset; uint16_t history_item; PCSGReceiverBarShow bar_show; + uint8_t u_rssi; } PCSGReceiverModel; +void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + PCSGReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock lock) { furi_assert(pcsg_receiver); pcsg_receiver->lock_count = 0; @@ -167,13 +185,23 @@ static void pcsg_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scr canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void pcsg_view_rssi_draw(Canvas* canvas, PCSGReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -207,10 +235,13 @@ void pcsg_view_receiver_draw(Canvas* canvas, PCSGReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } + // Draw RSSI + pcsg_view_rssi_draw(canvas, model); + switch(model->bar_show) { case PCSGReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); diff --git a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h index 5ea2d48597..a13f5cdc78 100644 --- a/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h +++ b/applications/plugins/pocsag_pager/views/pocsag_pager_receiver.h @@ -8,6 +8,8 @@ typedef struct PCSGReceiver PCSGReceiver; typedef void (*PCSGReceiverCallback)(PCSGCustomEvent event, void* context); +void pcsg_receiver_rssi(PCSGReceiver* instance, float rssi); + void pcsg_view_receiver_set_lock(PCSGReceiver* pcsg_receiver, PCSGLock keyboard); void pcsg_view_receiver_set_callback( diff --git a/applications/plugins/weather_station/scenes/weather_station_receiver.c b/applications/plugins/weather_station/scenes/weather_station_receiver.c index 670c8c3861..3b62a15129 100644 --- a/applications/plugins/weather_station/scenes/weather_station_receiver.c +++ b/applications/plugins/weather_station/scenes/weather_station_receiver.c @@ -195,6 +195,10 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev ws_hopper_update(app); weather_station_scene_receiver_update_statusbar(app); } + // Get current RSSI + float rssi = furi_hal_subghz_get_rssi(); + ws_receiver_rssi(app->ws_receiver, rssi); + if(app->txrx->txrx_state == WSTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); } diff --git a/applications/plugins/weather_station/views/weather_station_receiver.c b/applications/plugins/weather_station/views/weather_station_receiver.c index de5d7b1a36..8cdfcdd815 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.c +++ b/applications/plugins/weather_station/views/weather_station_receiver.c @@ -12,6 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -59,8 +60,24 @@ typedef struct { uint16_t list_offset; uint16_t history_item; WSReceiverBarShow bar_show; + uint8_t u_rssi; } WSReceiverModel; +void ws_receiver_rssi(WSReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + WSReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock lock) { furi_assert(ws_receiver); ws_receiver->lock_count = 0; @@ -164,13 +181,23 @@ static void ws_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrol canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void ws_view_rssi_draw(Canvas* canvas, WSReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -203,10 +230,13 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); + //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } + // Draw RSSI + ws_view_rssi_draw(canvas, model); + switch(model->bar_show) { case WSReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); diff --git a/applications/plugins/weather_station/views/weather_station_receiver.h b/applications/plugins/weather_station/views/weather_station_receiver.h index 30c6516d53..abe2c62555 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.h +++ b/applications/plugins/weather_station/views/weather_station_receiver.h @@ -8,6 +8,8 @@ typedef struct WSReceiver WSReceiver; typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context); +void ws_receiver_rssi(WSReceiver* instance, float rssi); + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard); void ws_view_receiver_set_callback( From 34f0aced2fe9f349a64efe72c690072094231b94 Mon Sep 17 00:00:00 2001 From: Willy-JL Date: Wed, 15 Feb 2023 02:04:16 +0000 Subject: [PATCH 02/41] Autolock with pin code --- applications/services/desktop/desktop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 848f5cb636..7995ac80d8 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -62,6 +62,9 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { return true; case DesktopGlobalAutoLock: if(!loader_is_locked(desktop->loader)) { + if(desktop->settings.pin_code.length > 0) { + desktop_pin_lock(&desktop->settings); + } desktop_lock(desktop); } return true; From 25e89472821701624def0553b4cb4de171a67ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Wed, 15 Feb 2023 19:05:08 +0900 Subject: [PATCH 03/41] Dolphin: drop holiday animation (#2398) --- .../L1_Happy_holidays_128x64/frame_0.png | Bin 1787 -> 0 bytes .../L1_Happy_holidays_128x64/frame_1.png | Bin 1795 -> 0 bytes .../L1_Happy_holidays_128x64/frame_10.png | Bin 1791 -> 0 bytes .../L1_Happy_holidays_128x64/frame_11.png | Bin 1814 -> 0 bytes .../L1_Happy_holidays_128x64/frame_12.png | Bin 1779 -> 0 bytes .../L1_Happy_holidays_128x64/frame_2.png | Bin 1774 -> 0 bytes .../L1_Happy_holidays_128x64/frame_3.png | Bin 1801 -> 0 bytes .../L1_Happy_holidays_128x64/frame_4.png | Bin 1799 -> 0 bytes .../L1_Happy_holidays_128x64/frame_5.png | Bin 1797 -> 0 bytes .../L1_Happy_holidays_128x64/frame_6.png | Bin 1789 -> 0 bytes .../L1_Happy_holidays_128x64/frame_7.png | Bin 1804 -> 0 bytes .../L1_Happy_holidays_128x64/frame_8.png | Bin 1809 -> 0 bytes .../L1_Happy_holidays_128x64/frame_9.png | Bin 1816 -> 0 bytes .../L1_Happy_holidays_128x64/meta.txt | 23 ------------------ assets/dolphin/external/manifest.txt | 7 ------ 15 files changed, 30 deletions(-) delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_1.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_3.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_5.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_8.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png delete mode 100644 assets/dolphin/external/L1_Happy_holidays_128x64/meta.txt diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_0.png deleted file mode 100644 index 909cc330392b999e38b0326b5381344c952380b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1787 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 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_10.png deleted file mode 100644 index 3a43c6b844541f9be3cadc2aa78864e9147919c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1791 zcmVnvyf3eBg-+&c%%cGpOsw&ZJ*b5*$z;l?5Yi0jy7XFZ9XH9ar)E7M=0e0a+Ci( z*H%Q2(@-5?W+Nw@07V4tJf0gn{`g#T0?YV)Y^APuj|?se z%wo3_XlwL;BVyKdU19uBz)K3K-u#Yqz>+ZSnT!yhp3gOSd--#KNP{F|$U6{2D@90T zb^8>D(e!+21hHjLCR{RkI08$a|KbQkCoyWq)1?u(OR=_A+r`sG&SQhH~mDq%3O>Yy?=Ilw#UdV2kEcJ z|1^18l+nhqE#sYidTXyypvp&LSs93c8Z^vU`HW33+N~ewYdpf5TLtFEvk_5(A@*Ax zU_8V~)uEMY?0V=K(+ynN%V6bMPFsO;2k?kg#tA&e?aA;C%St~hk#!~+rDh$W+ySiH zYE=)O6KKYX8jLwCuVs9<&k3p=A@pfrl$6Nv5u(+J%or`?YfqjRDY7JM7L}<)b~B?$ zeHJ9wP4(ivowkk6{ul2ybEWQm(Or>;k2p2`8(5al&q zytyY}m73^%IlsCRkUB)(mtfk{BVHna)kHx+<38a7k_;lwi!K9dUyt)MH=B)0bQLg` zaoT%*(X1jTfeaL#!yxl{N{01^8bNILE7L8zqZ4GKlSUrLTWVDvRdxGJ`8Vp=Uq41+ z+5(<12}`l46L=jtZ;n?9>~Kir5S5NFBkN%u#F%%ydYkQ4drt6)oWaZQ5>Y`OJ`Mn=e{w+ykX)}gf)|3=W?M5VVMTKHz1U>5SSNYaeXh&e;lruO8> z=c8_E2VfQV=CjZ?V9BvI>!mD|v$e6Bj;LCaGFU`pF-}nC02N@!COiK0SjGV~c?eAU z_2y_}`?HsC1@C|t$}BD+390pgk2TifDM+q2R@(#8Ym~#nBj6sa>Z#8^@`Vt2h+em> zk74AW9y_9HUr2srUG40*{y+pGji|xl9g;V;-(1PMQD{YLL=Yu+Rbchq{tF>qpP)7F zv*HjVa-%#ZvsTp}Wo1JBT>#tYVaG8F&eXP++>RA;vz=2-hQ>WsaWt0$j7p)- zpj3WFX|{gW=2>9s=#1P5G$+u~*NmeIijt zavZC>sNqDDO@q{vasVcj&xCt#E;7Enxd>zAis&|j*;JSXb7rlzc0C8pR@J1IBHEhr zJx%FM5b(1ifW2JSLpy=7s*me8ViMIt;}IDYy9Zk$huWcpK9WX%1ZTX z;c|jB{%oZ1Zi6I56$Z4{V-MT96fALLQ`GKM@#X-Uf!W&~!OGHyG4Kq5Wudj7EnQBL z#3KfsGTv0Ro-b4V~63n$)d(UL0@Fx)i~~L9UKs%_C951OJANj` zX^kRFmgYPwdM)05-u^BCEk2_NLItn51ES8XMTtoH>|x{~*7-iP2?)ru**u4{!{KzqK5I3i?oWoFz;UKB+%t#*AMY#DSS0<6A? zOam&Sd!zwX|23?V1N7HYc9otUqD~w!tn95s)`_fzWdBtGmREX)l8cPv zR&oHOr}r$P6JqKXSi{JQDiRr@%`R)s%MV0U8mb~cqEgc13Dq9FFv!TPESbD9cQJg&%8T&wSwN;2(4m!TUKxmF hpSXqJX8hJ#`vpJ+v^_(~quc-h002ovPDHLkV1n0aQh)#e diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_11.png deleted file mode 100644 index 20ea12eb06d4e6d10d9dcea9f1d2c69277765e1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1814 zcmV+x2kH2UP)F$kQo{QqB`eacqE2AWGUy4zKj8gn6mK!ct= z=W!g@@y~Ew_Lk4{+$72Uc-$?(Zd}*(uN3UzJpPdfm~Z}ho~9?*X(XOU>cYI|vA-uX zkQMNbn`J50Q?l&C^tWWN#%Jg50#g2QI0jG^c;$wXu~n3Z#xwIVMt`^REwplgPu=7y zba;=up&CGTGtvd`fVPfC_%vnxRdT4g|KlJzKos-A@31*0d|A~mV}`;=^?&7o+EgB`89yZh9k=Sgo9)aF>9pX zVleO`9HJ1!=FQPf%Ujj~8Sk~W(Jt3UGO_z&Gk~gbFh=PWv@`;E90?Mbjg@0u=WRhe zBSP?yK`?DQ5VzC%6O}}z4_2Qch0!k)!!a6GFXOe zfsuWy0n7?O!Z8&+?*P0o!;nO2oU1qhJ9pG*BltCdt_dx7DsMA;yCRHx%)27n_=F0f zG}5X}?HoWOAzJppq@Ck=eyz1>pR;R7*}9FX3mL+P5Hf)1VisAOf!gKaqt{w~n@Lr7 zD!DrquJDw{m?VPeVx4IpyPkaZvWai0=4r?p!5az8RKi$f*(?i`DOgo7OFm|;IbUB@ z@yoJ)b{xzCsz$(A<4%v@fhi`ff~T;kLK(6=)}jkftY>kaOPr6BaaYSS1qE@Bs-~kLObpTj=yRPeE z+_<+ntu$-(`72vk>H2Y-U5> zsALN)$@7X=-7>KAzx^U;Oy~{-xpoA9EgV=i2n~_5tAvFp8=etV>JGd6A_HJc?Y5u zMkFDX&t6{{gPD1~zGx4~qs)&?K_}8~0eQ1qeh?xL(IZl$4>SMWeP?JjkuhgSK}l=( zLe#)k4`9VctH9wMl-GAI|7tOvkv#$?<=t75){y#Da0Omv@i@4zkLNOU=OJe1^*Dis zNLZ-sQS-Lfb#Wnpy*1g}HNzrMvY%Yjn-|Gx^<(DuhiBGgFn<&(4?`m`=;n7C0Yc@FDz`C<$a(Bc#VHb~ zvGxk7Vt|aGa_cS3u|G0zl!JT%@tZ;akti$wt=x2Wtd`cWeIxUFDd|{St1d>@-Ff4s zoKHpoEACf~fN_n86v~6IDxK-ON>Sb6Ml)(;tWVh~GO285Zxiw)=nyoav$rmb&f<+W z_exlDKP_cw?GlmCxYK05mJ_c7qX8SDlwxV}){Lri3!5yP^KW5X5-r*Odc9?tbU(=y2s0 zBB|u+eS6u;n*mrJz^Vjh1)JAEuhIMH{7BwPDD%iN!&6og%Q63~FHM#Qa#IMM9AFkw zYmdfQ2}VX)++s0v6HPwvhF6Tw3L{#!q-Fu5qsQF4J-{sF>S`i`4x>h4)5?0}xNJSf z0@B+o(?d2`i=)>as488%$-7xM%AT~xal9(t^Q@JNXN9DAHZYBGB5X1Dya~Z-=lcSuA?DySWym8!P?~1d2T=P8;!m}nhrs@GKcm`v&q4C~2S{{wS?p0<~k#mZiCzS?vD+n1x zWe(ZqrJ+_^cApXBVO%r%obd*ox^g{07noZku|k$;_{g~Cxj$10^u~6b0}7wZJOEle z^4SXFXQi!3o{lrAdK>v#o0I8-u*CyZvw)T8;0fKxcqxYeAiVvNsEn&-1Vm$5QiaB3 zz^wCW`TT0Ud>7zt-1;0<4ZSqbnmg;#D!5bmcU4M%0Cc+*>zlWu!2kdN07*qoM6N<$ Ef-Tf;h5!Hn diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_12.png deleted file mode 100644 index a05abd80f1bbcf8c4c31985df242787246776d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1779 zcmV0r&z%C3U6&)&Q402Ruv+OXzmGsctVBk~ZZKW%&qr8NNGen&b$i!kXm9wELxpG)xe@^*j-K@u_K6AD8uMQ~(w z`xb|h^t=&4Xxozsmq;FtK$FL706JcC#tfH$b^uxD@SG8qsp)wmf+7lLbEQ-hMA!D@ zY587rTFD_iW3Pnfyxv#|sJ^Kpu*zty>9-JB3oSGy<0ChHSGvkv22WR1_n+Ol%d5z( zjr87cUy?j2%1Gl-%6M1jGP_Pz#*udeJtyE}sllcBk`o{|nvRnk&C_ibD^g2T-ZCCQ z0^M+=>yTPCbUo`egbiH9WoQvkL#9qcQ0@R;A(e3gui~C9h@!@rMaGe=E=rPzo^81U zXt!1C9y~=Q<3tUHL=TTLu5ylS6tP;^?Af*!bbx3W=HsnG3-xfRde`K6UBYfssxpO0 zyhjG9A~3qBR8*}55+QaJc{?!ML3}vC3Obn1S?LV)FzELctsGBv-kx@mNl}O?09Do_ zUc9*{prs7!IiLSTLuPSvfK1Edktp99S}jDJz@yHq+Q2MD4;O(_QAM9=N`8YAX!=EJ zi0qotf_k8WIqaQ$C{#17#=4>7>0(bp_5h{g(Q3ss8JRcJBt0?&(Jkd&*L6wk7+)Yt zz#uH!Z-I420}>Hd0Vy)0Z+i9K+e0+HN<4a%%e0<<8%{ela;BCIO&-AWY|cg@ z2K+`NTX;fxn>o|)CxYG+CqvrlL#sw44Xi>m4cv;rC}#6n^yYXQ^2YMqhsgED@^RK# zaCS0!*(9Lczh$ebH-oBLk;obr&FhV|YL$#!1e(Dk9fS2O`^M6HzwLht*p-{nTPAfO z<9B|mk+GT%mRxTv)!AETC#;%{N3kOx2;quYksuN>pD>ord1ArK_1gN8Fe?{nH=qBk z$+gCgc6NMuW4$#_0!=^YxUCVOHH;@fl(%wr1u}Uac~(_7MdeUED0>P0T>wh-pyMn^ zxxE5b1z#Z-rN(Dc12tR~+!UY{Sk|~%<4J`bI!^;n0abFNb7+)9qg`t`$3dc`nF9D> zX=I0%w^#54*&K~Jl~s#Gp`Agdtz1=u^vjTp^v&AyF=mz((+C{8uGRKP@Wy(qUepOI zoGF5cLqSEL70%EFrMa0_4AE=0fb-JaSle?>KDMGpiU6s5AO}EhYejKmJ?G#Dk9vJ1 z@1k-M@RYVX>`Q4!bat8oR<%?dmS^&3(hbW*9!V}b-%CMUR}IniGC(hrngX+$EBgJg}b$+bY+FHgTLP7zJw$HJ}fQPH1!1>`tv-hF8EqlmDK)|y<;mGf8O z!vQoekAyk|)eM;?YefMY1&tu9jc#2~>GdNKfF3?V&P3O%$hB2YPK(qi`7^t=_4@!+ z1JI(WDgs!!|5RS3Iw3kBtf)74W%x(-@bRHgWK*l0fWD6CWXVMJo7s=l&1ATN6X{^! zXAB(QwOmzQ15hQc-z#KB##il)UYICL>dB3y5pRv3Arx6y`nduptKdp#T!k0qP=oSf z($fJ+Gar8&=o!Oe(@-bLKJ#>{0xHkrG*Ds)Bo}K zv5Udv$mlwtkxSC$sxZDb|HT(T3o|;;>Kd%YpNiEEWf@c|AZIRu=RE2sg190cKOnun zqtfNbtc4nU6%8z*au1ecywEo2LBG^ zCriHd9ChMIAzHr>)FmU?^ z5tW9L9AZWWf6Z${t=DE#64KrwYe+3MGPlZBy>~wXRKfG`N<+=)p^cB|fjVo?8It25(No$3 zV$Y9%5|s(n9=uzC$gIkF$e1S(SCs{)h1+`p87^ReGgn?Gz&Ez?7NU5H@dtK9z<;d< Vp()s7p}_zE002ovPDHLkV1hccKn4H+ diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_2.png deleted file mode 100644 index fc7e0364afbfa0c0750a59c1d546dc9211c42161..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1774 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 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_4.png deleted file mode 100644 index bcc7f28a9eb40eda4f9d472409a93fab7f0d98ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1799 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 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_6.png deleted file mode 100644 index c0b1a4fe24af639bddda8ca7f69d2bee8aed8689..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1789 zcmVgl@z3GiqHRtsLHW&}w z$K$%L*Y(Trdf_EM9*<3yoX5{;19s!}di^Q~M|fPnCh;4e0%<>@HZ&zpfwvW({7sU@O>WoM*ky$YX;3wDS>KIlx^P zxe6WG<22j=s4hmQ;2rSvc!bY$*8fTlz4U)wBnQYsZv2ju;RW66^)iFNbN-myY46=L zgBbuF2Ja36OV9Wk5wl_I3g>?Vmi7U5Tn8)(v&M9W`1bqULbR5D0gzd6#+i56NH!3w zLHaELV;+P{HGIlE|m$~vI$dv9!vYu%Pj?7G+rU?w=&fQ%Yi9s#_r0tu|%mE*n6 z(_-|tR@u7@`cz`i(JB91`l0F&M==j*xADc%8jKr(wg=1We)+PtI; zM9`;pjA?kO+fDt!$)p!L!f1Q)dEumY`;ANHu~yl9cI^&0Gn)QFWr%r9@?J zC&8TQ16Y1|N?{!ad4^?!05MwT#G?KHl2Nhk1enGcgJ;x!WfgR!q&sqk2$hn!yAOc6 zuaQpJ2#TVtauUAL$q0A2-ezq0_=%t)FnrOdwNr|3kVZQZ^&OCt*mgMj9*gza)A4o{ zUc~^=3M;6VHCk`9SmYceH=1kd^qdvd{A>_tRLXJ~0J~Fk6a+JUhda#G?{yv+ritXu zA9J?<51jNN+9Y{liRgMpRJj{HD~-bA!9nR@rc+&hw5 zZ$GWQ-Jzd&Jy}{l*tuvBq*@@<{b5Wlpsz{Iy#B(x0dl?3RjB-SRydL?i z!EC^F&DHCTGfPvME2;f+U8mE9C6pS|-l&YvY{hyY7lES{vtyKL&h2MI*wi~d|i z^u8u6GtHeb-y%R6=nQ1pCJkX)m*}v;;zOA}g7t5;4aYKo)`Q68Z2IfIgR^AW%Md$YU4PQX zAAJfVw%> z_YZpL3GZG=2hoW>-vOsfKeL3ruJ~sHbqREG5lDYEOR?8m<~h>8q6x%wZ6(H>k1GHX zFnt|Fcb`6u*0thYKa3s^m5t4E0FR?Ea>hHiX#~j=BiVj*@=-6myL4QMQ`ZL52qNYlB>4-2RpLIZ{Qet5>g0gF=l+D8@Pp?L`0z!}JlkSaI>)>d^XAwDU z#^x*{#*S=^o}*_UB(MWI16T%1!?gAO?GHq(Dod)e&AJs_3+z~RogL*{HI?hRUA_u4 zKo^)(qp`x4?DestX1Cy-((bIOqnfmwyPBhEjejXrNIC}1-DpUp{*(>it f52u`evP=30f`%HTZ&_~;00000NkvXXu0mjfZU|{H diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_7.png deleted file mode 100644 index 19c8181d0369a8edf52ef2124d403f5472c8e280..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1804 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 diff --git a/assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png b/assets/dolphin/external/L1_Happy_holidays_128x64/frame_9.png deleted file mode 100644 index 929a207ef58a63e946d60e4413e5ad96a75d7c0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1816 zcmV+z2j}>SP)fcfU1=V^L^okrq$q%O>R9{YPT z16cv@xLKA`JtfONOn*xTYkYR@E+FL}hhqR$fmd!A8CykpXgo6?WAt|`-$E+~_|#3V zLWlRb8>#_hHzQr}4ruFWgilk}UnPf{`#%nn14J<&{EnNU8QpbV&H>04*8V+c=`X^PI)Dc$9Ae?JuZ*{v+nW!~bLWhkUH$1HBZFng z78u#L8o;aoBpg%G^A5lZGYm*!ARZFPr$5YMzFy5xkMWOeKs(md&z2nSxaXv*csen)CHl z6~8R&XUD-TplSq+HSY8X9++a%DtHQuDwHA1GagJ41ufw9Lw!F1l>$o!)@5KSep#~D zUI>!u+i07AXT8DQuoQ&eR}H&DQX?{i3PBo4id4xeAz?SNO4O>99Xx%CDJnrPb%#ID>}>*x=e)Jj(o&DdH)0SXcaiTgYx>$o*Ya@V0pjMUO7(-t^v$KS(QPp zMxKGRQct#dT(z&hR2(4Ca?Y51-BVb%3B8Bqct4e43u2NKYxY3Ln8S7JaicBio+1rFX2|5H#X!h251rZjV z#T#wzm9XSKujz@EetE2z^#b~_J?aurViZW`j3P2# zo3rvPwU5f!q|riW{SC zJQHK1huA>~E%`hn%$}haMzm~6ljGMPhoXa*M6BClwc=6~Rbtr9Ydiy!=`JJxID7U| zNIB5Bhb5$39KG&9mqBF|s*TAOwd8y2Qq5k%^Q@JNXBp#LA&5zrG>c`8B>Rj(CPY~- z907&PsB*N-$}5OfA@}tb0xSY1!+{mU<#R2pXyJ!hN5c+g9d*SsEQQYAAWFJ3MXFZ_ zkVb&gG^;*<+E=DptFYR5SX2xwg4c&ZQkl{vc@;v`-kmyn$gaa0roCFh>c@7GttJVkicB*#=efCbNBtTr^>TZgUiY3pip&s-~VPLcDZ(!g#7 zA%m#QA=|t()N0G_Gh#e!CD7tkU7^W>>jApJ+!~1$vP8p2#x>9VnM$BHw(A^F_*~`z z(BhG2D~O+!wjy~t&ZO#XSL4@b0p7-~=csDvrGeJmS(jG9oyxzfQu+f7>@m9|qN_##0000 Date: Wed, 15 Feb 2023 19:56:25 +0300 Subject: [PATCH 04/41] [FL-3098] Up toolchain to version 20 (#2397) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Up toolchain to 20 * Python reformat, add version info into fbtenv Co-authored-by: あく --- scripts/flipper/assets/dolphin.py | 2 -- scripts/flipper/utils/cdc.py | 1 + scripts/flipper/utils/templite.py | 2 ++ scripts/toolchain/fbtenv.cmd | 5 ++++- scripts/toolchain/fbtenv.sh | 11 ++++++++++- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/flipper/assets/dolphin.py b/scripts/flipper/assets/dolphin.py index 096d31629f..cbd1320b65 100644 --- a/scripts/flipper/assets/dolphin.py +++ b/scripts/flipper/assets/dolphin.py @@ -22,7 +22,6 @@ def _convert_image(source_filename: str): class DolphinBubbleAnimation: - FILE_TYPE = "Flipper Animation" FILE_VERSION = 1 @@ -243,7 +242,6 @@ def process(self): class DolphinManifest: - FILE_TYPE = "Flipper Animation Manifest" FILE_VERSION = 1 diff --git a/scripts/flipper/utils/cdc.py b/scripts/flipper/utils/cdc.py index 7047db2a68..7c73516702 100644 --- a/scripts/flipper/utils/cdc.py +++ b/scripts/flipper/utils/cdc.py @@ -1,5 +1,6 @@ import serial.tools.list_ports as list_ports + # Returns a valid port or None, if it cannot be found def resolve_port(logger, portname: str = "auto"): if portname != "auto": diff --git a/scripts/flipper/utils/templite.py b/scripts/flipper/utils/templite.py index 8af57d7f8f..2d958bd77a 100644 --- a/scripts/flipper/utils/templite.py +++ b/scripts/flipper/utils/templite.py @@ -173,12 +173,14 @@ def render(self, **namespace): """Renders the template according to the given namespace.""" stack = [] namespace["__file__"] = self.file + # add write method def write(*args): for value in args: stack.append(str(value)) namespace["write"] = write + # add include method def include(file): if not os.path.isabs(file): diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 9fbd8fd9b6..5dff4b25e6 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=19" +set "FLIPPER_TOOLCHAIN_VERSION=20" if ["%FBT_TOOLCHAIN_ROOT%"] == [""] ( set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows" @@ -31,9 +31,12 @@ if not exist "%FBT_TOOLCHAIN_VERSION_FILE%" ( set /p REAL_TOOLCHAIN_VERSION=<"%FBT_TOOLCHAIN_VERSION_FILE%" if not "%REAL_TOOLCHAIN_VERSION%" == "%FLIPPER_TOOLCHAIN_VERSION%" ( + echo FBT: starting toolchain upgrade process.. powershell -ExecutionPolicy Bypass -File "%FBT_ROOT%\scripts\toolchain\windows-toolchain-download.ps1" %flipper_toolchain_version% "%FBT_TOOLCHAIN_ROOT%" + set /p REAL_TOOLCHAIN_VERSION=<"%FBT_TOOLCHAIN_VERSION_FILE%" ) +echo FBT: using toolchain version %REAL_TOOLCHAIN_VERSION% set "HOME=%USERPROFILE%" set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" set "PYTHONPATH=" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index dd5484aa9a..bedb3450a0 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"19"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"20"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; fbtenv_show_usage() @@ -35,6 +35,7 @@ fbtenv_restore_env() PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/bin://g")"; PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/protobuf\/bin://g")"; PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/openocd\/bin://g")"; + PATH="$(echo "$PATH" | /usr/bin/sed "s/$TOOLCHAIN_ARCH_DIR_SED\/openssl\/bin://g")"; if [ -n "${PS1:-""}" ]; then PS1="$(echo "$PS1" | sed 's/\[fbt\]//g')"; elif [ -n "${PROMPT:-""}" ]; then @@ -248,6 +249,7 @@ fbtenv_check_download_toolchain() elif [ ! -f "$TOOLCHAIN_ARCH_DIR/VERSION" ]; then fbtenv_download_toolchain || return 1; elif [ "$(cat "$TOOLCHAIN_ARCH_DIR/VERSION")" -ne "$FBT_TOOLCHAIN_VERSION" ]; then + echo "FBT: starting toolchain upgrade process.." fbtenv_download_toolchain || return 1; fi return 0; @@ -269,6 +271,11 @@ fbtenv_download_toolchain() return 0; } +fbtenv_print_version() +{ + echo "FBT: using toolchain version $(cat "$TOOLCHAIN_ARCH_DIR/VERSION")"; +} + fbtenv_main() { fbtenv_check_sourced || return 1; @@ -281,10 +288,12 @@ fbtenv_main() fbtenv_check_script_path || return 1; fbtenv_check_download_toolchain || return 1; fbtenv_set_shell_prompt; + fbtenv_print_version; PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH"; + PATH="$TOOLCHAIN_ARCH_DIR/openssl/bin:$PATH"; SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; SAVED_PYTHONPATH="${PYTHONPATH:-""}"; From 4aae197cf72687ba916ae99f65a27662e5c13c3b Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:32:40 +0000 Subject: [PATCH 05/41] Updated ac.ir new additions --- assets/resources/infrared/assets/ac.ir | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 9d5e119806..e55c27f30a 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 13th Jan, 2023 -# Last Checked 8th Feb, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: raw @@ -1542,3 +1542,21 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3110 1567 551 1031 550 356 471 1032 550 356 471 356 445 1084 497 355 472 357 497 356 472 1058 523 1058 523 356 471 356 470 357 469 357 470 357 474 357 470 1063 519 357 470 1063 518 1063 519 1063 518 357 470 357 471 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3087 1607 488 1064 517 335 492 1087 484 315 512 340 487 1091 490 336 491 338 489 1089 492 333 494 332 485 341 486 340 487 338 489 336 491 339 488 1090 491 334 493 1085 486 340 487 1091 490 1088 493 333 484 343 484 44227 178 +# +name: TIMER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3092 1602 492 1059 512 341 486 1092 489 337 490 336 491 1087 494 332 485 344 493 1085 486 1093 488 1064 517 1061 520 333 494 332 484 341 486 343 484 1094 487 1091 490 336 491 335 492 334 493 333 484 1094 487 340 487 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8838 3941 624 1427 514 500 515 497 541 473 540 1487 540 474 539 474 538 476 512 1538 514 1516 544 466 514 497 514 501 514 499 514 500 513 499 513 501 487 525 514 499 512 502 487 526 512 1517 542 470 487 1539 513 499 512 503 513 499 512 1513 512 From 5a02a51bd9b28285ce19b25fb08d392f732679ad Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:33:17 +0000 Subject: [PATCH 06/41] Updated audio.ir new additions --- assets/resources/infrared/assets/audio.ir | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 216ac7b2df..1bb3c11e08 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 8th Feb, 2023 -# Last Checked 8th Feb, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: parsed @@ -2050,3 +2050,21 @@ type: parsed protocol: NEC address: 01 00 00 00 command: 10 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4555 4463 532 473 532 473 531 474 530 474 530 1478 531 1478 531 475 529 476 528 1482 551 1480 529 1480 528 1481 528 477 527 478 527 478 526 478 527 4498 526 477 527 477 527 478 526 478 526 478 526 478 526 478 527 478 526 1483 527 1483 526 1483 526 478 526 1483 527 1483 527 1483 526 1483 526 478 526 478 527 478 527 1484 526 55527 4527 4492 526 478 526 478 526 478 526 479 526 1483 527 1483 526 478 526 478 526 1483 527 1483 526 1483 526 1483 526 478 527 478 526 479 526 478 526 4497 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 478 526 1484 525 1483 526 1484 525 478 526 1484 525 1484 525 1484 525 1484 525 478 526 479 526 479 525 1484 525 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 4552 4463 531 474 530 474 530 474 530 474 530 1478 531 1478 531 475 529 476 553 1455 554 1478 530 1479 529 1481 527 477 527 478 526 478 526 478 526 4497 526 478 526 478 526 478 526 477 527 1483 526 1482 527 1482 527 478 526 1483 526 1483 526 1483 526 478 526 478 526 478 526 478 526 1483 526 478 526 478 526 478 526 1483 526 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 325 50440 173 137541 4551 4465 530 475 529 475 529 474 530 474 530 1479 530 1479 529 476 528 477 527 1480 554 1457 551 1480 528 1481 527 477 527 478 526 478 526 478 526 4497 525 478 526 478 526 478 526 478 526 479 525 479 525 479 525 1484 525 1483 526 1484 525 1483 526 479 525 1483 526 1483 526 1483 526 479 525 479 525 479 525 479 525 1484 525 From 6bcb9a60f7dd099d4ed9a11fbf97d1eb5df9e188 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:33:43 +0000 Subject: [PATCH 07/41] Updated fans.ir New additions --- assets/resources/infrared/assets/fans.ir | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index 653583681d..c30f58e5e0 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 8th Feb, 2023 -# Last Checked 8th Feb, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: raw @@ -1401,3 +1401,21 @@ type: parsed protocol: NEC address: 01 00 00 00 command: 0D 00 00 00 +# +name: POWER +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 00 FF 00 00 +# +name: SPEED+ +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 08 F7 00 00 +# +name: SPEED- +type: parsed +protocol: NECext +address: 80 DE 00 00 +command: 10 EF 00 00 From 58e9acc19eebdb0648db33e3b3e82b31665edd15 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:34:14 +0000 Subject: [PATCH 08/41] Updated projectors.ir Updated last checked --- assets/resources/infrared/assets/projectors.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 9cdf29b91a..6378f2d12e 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 8th Feb, 2023 -# Last Checked 8th Feb, 2023 +# Last Checked 15th Feb, 2023 # # ON name: POWER From 55cfccafafd3fca0298c0c2ace51c9a68bd3764d Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Wed, 15 Feb 2023 19:34:42 +0000 Subject: [PATCH 09/41] Updated tv.ir New additions --- assets/resources/infrared/assets/tv.ir | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index ed89bb2d7f..e3d41b9a7d 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 19th Jan, 2023 -# Last Checked 8th Feb, 2023 +# Last Updated 15th Feb, 2023 +# Last Checked 15th Feb, 2023 # name: POWER type: parsed @@ -1839,3 +1839,27 @@ type: parsed protocol: SIRC20 address: 5A 0E 00 00 command: 11 00 00 00 +# +name: VOL+ +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 15 00 00 00 +# +name: VOL- +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 14 00 00 00 +# +name: CH+ +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 18 00 00 00 +# +name: CH- +type: parsed +protocol: RC5 +address: 00 00 00 00 +command: 17 00 00 00 From d81653461cafd157efc636a90861192c8d035317 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Wed, 15 Feb 2023 23:33:30 +0300 Subject: [PATCH 10/41] sync anims --- .ci_files/anims_ofw.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.ci_files/anims_ofw.txt b/.ci_files/anims_ofw.txt index f9d5c2a64f..94c61e0ff2 100644 --- a/.ci_files/anims_ofw.txt +++ b/.ci_files/anims_ofw.txt @@ -36,13 +36,6 @@ Min level: 1 Max level: 1 Weight: 3 -Name: L1_Happy_holidays_128x64 -Min butthurt: 0 -Max butthurt: 14 -Min level: 1 -Max level: 3 -Weight: 4 - Name: L1_Read_books_128x64 Min butthurt: 0 Max butthurt: 8 From a52f64acfda905e229e1835a326064882054f14d Mon Sep 17 00:00:00 2001 From: p3ngu19z Date: Thu, 16 Feb 2023 11:23:46 +0200 Subject: [PATCH 11/41] Improve fall speed algorithm --- applications/plugins/tetris_game/tetris_game.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/applications/plugins/tetris_game/tetris_game.c b/applications/plugins/tetris_game/tetris_game.c index b317d376ac..9b492cc8ec 100644 --- a/applications/plugins/tetris_game/tetris_game.c +++ b/applications/plugins/tetris_game/tetris_game.c @@ -16,6 +16,9 @@ #define FIELD_WIDTH 11 #define FIELD_HEIGHT 24 +#define MAX_FALL_SPEED 500 +#define MIN_FALL_SPEED 100 + typedef struct Point { // Also used for offset data, which is sometimes negative int8_t x, y; @@ -169,7 +172,7 @@ static void tetris_game_input_callback(InputEvent* input_event, FuriMessageQueue static void tetris_game_init_state(TetrisState* tetris_state) { tetris_state->gameState = GameStatePlaying; tetris_state->numLines = 0; - tetris_state->fallSpeed = 500; + tetris_state->fallSpeed = MAX_FALL_SPEED; memset(tetris_state->playField, 0, sizeof(tetris_state->playField)); memcpy(&tetris_state->currPiece, &shapes[rand() % 7], sizeof(tetris_state->currPiece)); @@ -303,6 +306,7 @@ static void tetris_game_render_curr_piece(tetris_state); uint8_t numLines = 0; uint8_t lines[] = {0, 0, 0, 0}; + uint16_t nextFallSpeed; tetris_game_check_for_lines(tetris_state, lines, &numLines); if(numLines > 0) { @@ -323,7 +327,10 @@ static void uint16_t oldNumLines = tetris_state->numLines; tetris_state->numLines += numLines; if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - tetris_state->fallSpeed -= 50; + nextFallSpeed = tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); + if (nextFallSpeed >= MIN_FALL_SPEED){ + tetris_state->fallSpeed = nextFallSpeed; + } } } From fd46bd188642ed918738fb6fefdbe29660b258b4 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 17 Feb 2023 00:14:16 +0300 Subject: [PATCH 12/41] Update readme and docs --- ReadMe.md | 7 +++---- documentation/DangerousSettings.md | 2 +- documentation/SubGHzSettings.md | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 04419b0fed..232058f6c4 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,8 +12,6 @@ Our goal is to make all features possible on this device without any limitations! -Please help us implement emulation for all Sub-GHz dynamic (rolling code) protocols! -
### This software is for experimental purposes only and is not meant for any illegal activity/purposes.
We do not condone illegal activity and strongly encourage keeping transmissions to legal/valid uses allowed by law.
Also, this software is made without any support from Flipper Devices and is in no way related to the official devs. @@ -230,8 +228,6 @@ Games: # Where I can find IR, Sub-GHz, ... files, DBs, and other stuff? ## [UberGuidoZ Playground - Large collection of files - Github](https://github.com/UberGuidoZ/Flipper) ## [Awesome Flipper Zero - Github](https://github.com/djsime1/awesome-flipperzero) -## [CAME-12bit, NICE-12bit, Linear-10bit, PT-2240 - Sub-GHz fixed code bruteforce](https://github.com/tobiabocchi/flipperzero-bruteforce) -## [SMC5326, UNILARM - Sub-GHz fixed code bruteforce](https://github.com/Hong5489/flipperzero-gate-bruteforce)

@@ -239,6 +235,9 @@ Games: # Links * Unofficial Discord: [discord.unleashedflip.com](https://discord.unleashedflip.com) +* Hello world - plugin tutorial (English): [https://github.com/DroomOne/Flipper-Plugin-Tutorial](https://github.com/DroomOne/Flipper-Plugin-Tutorial) +* Hello world - plugin tutorial (in Russian): [https://yakovlev.me/hello-flipper-zero/](https://yakovlev.me/hello-flipper-zero/) +* CLion IDE - How to setup workspace for flipper firmware development: [https://krasovs.ky/2022/11/01/flipper-zero-clion.html](https://krasovs.ky/2022/11/01/flipper-zero-clion.html) * Docs by atmanos / How to write your own app (outdated API): [https://flipper.atmanos.com/docs/overview/intro](https://flipper.atmanos.com/docs/overview/intro) * Official Docs: [http://docs.flipperzero.one](http://docs.flipperzero.one) diff --git a/documentation/DangerousSettings.md b/documentation/DangerousSettings.md index 1da2fc4ab0..cb89df3517 100644 --- a/documentation/DangerousSettings.md +++ b/documentation/DangerousSettings.md @@ -1,6 +1,6 @@ ## How to extend SubGHz supported frequency range -#### CC1101 Frequency range specs: 300-348 MHz, 386-464 MHz, and 778-928 MHz (+ 350MHz was added to default range) +#### CC1101 Frequency range specs: 300-348 MHz, 386-464 MHz, and 778-928 MHz (+ 350MHz and 467MHz was added to default range) #### This setting will extend to: 281-361 MHz, 378-481 MHz, and 749-962 MHz 1. Please do not do that unless you know what exactly you are doing diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index bfcfcccfad..b1a678e8e4 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -1,6 +1,6 @@ ## How to add new SubGHz frequencies -#### CC1101 Frequency range specs: 300-348 MHz, 386-464 MHz, and 778-928 MHz (+ 350MHz was added to default range) +#### CC1101 Frequency range specs: 300-348 MHz, 386-464 MHz, and 778-928 MHz (+ 350MHz and 467MHz was added to default range) Edit user settings file located on your microSD card - `subghz/assets/setting_user` @@ -54,6 +54,7 @@ if you need your custom one, make sure it doesn't listed here 438900000, 440175000, 464000000, + 467750000, /* 779 - 928 */ 779000000, From 660f97f24172b4858d41f124202d801776fe2005 Mon Sep 17 00:00:00 2001 From: Willy-JL Date: Thu, 16 Feb 2023 23:21:35 +0000 Subject: [PATCH 13/41] Add desktop auto lock with pin setting --- applications/services/desktop/desktop.c | 2 +- .../services/desktop/desktop_settings.h | 1 + .../scenes/desktop_settings_scene_start.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index 7995ac80d8..0f66e5570b 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -62,7 +62,7 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { return true; case DesktopGlobalAutoLock: if(!loader_is_locked(desktop->loader)) { - if(desktop->settings.pin_code.length > 0) { + if(desktop->settings.auto_lock_with_pin && desktop->settings.pin_code.length > 0) { desktop_pin_lock(&desktop->settings); } desktop_lock(desktop); diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index e624807183..d443dc122d 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -63,4 +63,5 @@ typedef struct { uint32_t auto_lock_delay_ms; uint8_t displayBatteryPercentage; uint8_t dummy_mode; + bool auto_lock_with_pin; } DesktopSettings; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c index 2d1d2f8a52..e3f83d275a 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_start.c @@ -60,6 +60,14 @@ static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* i app->settings.auto_lock_delay_ms = auto_lock_delay_value[index]; } +static void desktop_settings_scene_start_auto_lock_pin_changed(VariableItem* item) { + DesktopSettingsApp* app = variable_item_get_context(item); + uint8_t value = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, value ? "ON" : "OFF"); + app->settings.auto_lock_with_pin = value; +} + void desktop_settings_scene_start_on_enter(void* context) { DesktopSettingsApp* app = context; VariableItemList* variable_item_list = app->variable_item_list; @@ -87,6 +95,16 @@ void desktop_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, value_index); variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]); + item = variable_item_list_add( + variable_item_list, + "Auto Lock Pin", + 2, + desktop_settings_scene_start_auto_lock_pin_changed, + app); + + variable_item_set_current_value_index(item, app->settings.auto_lock_with_pin); + variable_item_set_current_value_text(item, app->settings.auto_lock_with_pin ? "ON" : "OFF"); + item = variable_item_list_add( variable_item_list, "Battery View", From aae37121d6f20668f952addf41d6b6b47801b219 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 17 Feb 2023 03:36:34 +0300 Subject: [PATCH 14/41] Bump Settings file version to 7, cuz struct is changed and requires upd Settings are saved as binary struct dump, so if we make any change to struct, we need to bump a version since it will not be compatible with older file in any case --- applications/services/desktop/desktop_settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index d443dc122d..26c39f6114 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (6) +#define DESKTOP_SETTINGS_VER (7) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) From 5b0f74bffa0e705198cae3db9c856499dc79d281 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 17 Feb 2023 04:27:01 +0300 Subject: [PATCH 15/41] Add missing buttons into hid app, remove old app Now its all in one app, compiles as two apps that will be placed in misc folder --- ReadMe.md | 1 - applications/plugins/hid_app/application.fam | 24 +- applications/plugins/hid_app/hid_usb_10px.png | Bin 969 -> 174 bytes .../plugins/hid_app/views/hid_keyboard.c | 16 +- applications/plugins/usbkeyboard/LICENSE.md | 24 -- .../plugins/usbkeyboard/application.fam | 15 - .../usbkeyboard/assets/Arr_dwn_7x9.png | Bin 3602 -> 0 bytes .../plugins/usbkeyboard/assets/Arr_up_7x9.png | Bin 3605 -> 0 bytes .../usbkeyboard/assets/ButtonDown_7x4.png | Bin 102 -> 0 bytes .../usbkeyboard/assets/ButtonLeft_4x7.png | Bin 1415 -> 0 bytes .../usbkeyboard/assets/ButtonRight_4x7.png | Bin 1839 -> 0 bytes .../usbkeyboard/assets/ButtonUp_7x4.png | Bin 102 -> 0 bytes .../usbkeyboard/assets/Button_18x18.png | Bin 3609 -> 0 bytes .../usbkeyboard/assets/Circles_47x47.png | Bin 3712 -> 0 bytes .../assets/Left_mouse_icon_9x9.png | Bin 3622 -> 0 bytes .../usbkeyboard/assets/Like_def_11x9.png | Bin 3616 -> 0 bytes .../usbkeyboard/assets/Like_pressed_17x17.png | Bin 3643 -> 0 bytes .../plugins/usbkeyboard/assets/Ok_btn_9x9.png | Bin 3605 -> 0 bytes .../assets/Ok_btn_pressed_13x13.png | Bin 3625 -> 0 bytes .../usbkeyboard/assets/Pin_arrow_down_7x9.png | Bin 3607 -> 0 bytes .../usbkeyboard/assets/Pin_arrow_left_9x7.png | Bin 3603 -> 0 bytes .../assets/Pin_arrow_right_9x7.png | Bin 3602 -> 0 bytes .../usbkeyboard/assets/Pin_arrow_up_7x9.png | Bin 3603 -> 0 bytes .../assets/Pin_back_arrow_10x8.png | Bin 3606 -> 0 bytes .../assets/Pressed_Button_13x13.png | Bin 3606 -> 0 bytes .../assets/Right_mouse_icon_9x9.png | Bin 3622 -> 0 bytes .../usbkeyboard/assets/Space_65x18.png | Bin 3619 -> 0 bytes .../plugins/usbkeyboard/assets/Voldwn_6x6.png | Bin 3593 -> 0 bytes .../plugins/usbkeyboard/assets/Volup_8x6.png | Bin 3595 -> 0 bytes applications/plugins/usbkeyboard/usb_hid.c | 198 --------- applications/plugins/usbkeyboard/usb_hid.h | 39 -- .../plugins/usbkeyboard/usb_keyboard_10px.png | Bin 174 -> 0 bytes .../usbkeyboard/views/usb_hid_dirpad.c | 197 --------- .../usbkeyboard/views/usb_hid_dirpad.h | 13 - .../usbkeyboard/views/usb_hid_keyboard.c | 387 ------------------ .../usbkeyboard/views/usb_hid_keyboard.h | 13 - .../plugins/usbkeyboard/views/usb_hid_media.c | 201 --------- .../plugins/usbkeyboard/views/usb_hid_media.h | 13 - .../plugins/usbkeyboard/views/usb_hid_mouse.c | 215 ---------- .../plugins/usbkeyboard/views/usb_hid_mouse.h | 13 - .../usbkeyboard/views/usb_hid_mouse_jiggler.c | 156 ------- .../usbkeyboard/views/usb_hid_mouse_jiggler.h | 14 - 42 files changed, 20 insertions(+), 1519 deletions(-) delete mode 100644 applications/plugins/usbkeyboard/LICENSE.md delete mode 100644 applications/plugins/usbkeyboard/application.fam delete mode 100644 applications/plugins/usbkeyboard/assets/Arr_dwn_7x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Arr_up_7x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/ButtonDown_7x4.png delete mode 100644 applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png delete mode 100644 applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png delete mode 100644 applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png delete mode 100644 applications/plugins/usbkeyboard/assets/Button_18x18.png delete mode 100644 applications/plugins/usbkeyboard/assets/Circles_47x47.png delete mode 100644 applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Like_def_11x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Like_pressed_17x17.png delete mode 100644 applications/plugins/usbkeyboard/assets/Ok_btn_9x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Ok_btn_pressed_13x13.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pin_arrow_right_9x7.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pin_back_arrow_10x8.png delete mode 100644 applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png delete mode 100644 applications/plugins/usbkeyboard/assets/Right_mouse_icon_9x9.png delete mode 100644 applications/plugins/usbkeyboard/assets/Space_65x18.png delete mode 100644 applications/plugins/usbkeyboard/assets/Voldwn_6x6.png delete mode 100644 applications/plugins/usbkeyboard/assets/Volup_8x6.png delete mode 100644 applications/plugins/usbkeyboard/usb_hid.c delete mode 100644 applications/plugins/usbkeyboard/usb_hid.h delete mode 100644 applications/plugins/usbkeyboard/usb_keyboard_10px.png delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_dirpad.c delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_dirpad.h delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_keyboard.c delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_keyboard.h delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_media.c delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_media.h delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_mouse.c delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_mouse.h delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c delete mode 100644 applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h diff --git a/ReadMe.md b/ReadMe.md index 232058f6c4..d93061bb6b 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -116,7 +116,6 @@ You can support us by using links or addresses below: - ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module) - WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module) - MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) -- USB Keyboard plugin [(by huuck)](https://github.com/huuck/FlipperZeroUSBKeyboard) - WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player) - Barcode generator plugin [(original by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - [EAN-8 and refactoring](https://github.com/DarkFlippers/unleashed-firmware/pull/154) by @msvsergey - GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin) diff --git a/applications/plugins/hid_app/application.fam b/applications/plugins/hid_app/application.fam index 54448d8419..fa67fed6be 100644 --- a/applications/plugins/hid_app/application.fam +++ b/applications/plugins/hid_app/application.fam @@ -1,14 +1,14 @@ -#App( -# appid="hid_usb", -# name="USB Remote", -# apptype=FlipperAppType.PLUGIN, -# entry_point="hid_usb_app", -# stack_size=1 * 1024, -# fap_category="Tools", -# fap_icon="hid_usb_10px.png", -# fap_icon_assets="assets", -# fap_icon_assets_symbol="hid", -#) +App( + appid="hid_usb", + name="USB Keyboard & Mouse", + apptype=FlipperAppType.PLUGIN, + entry_point="hid_usb_app", + stack_size=1 * 1024, + fap_category="Misc", + fap_icon="hid_usb_10px.png", + fap_icon_assets="assets", + fap_icon_assets_symbol="hid", +) App( @@ -17,7 +17,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="hid_ble_app", stack_size=1 * 1024, - fap_category="Tools", + fap_category="Misc", fap_icon="hid_ble_10px.png", fap_icon_assets="assets", fap_icon_assets_symbol="hid", diff --git a/applications/plugins/hid_app/hid_usb_10px.png b/applications/plugins/hid_app/hid_usb_10px.png index 415de7d2304fe982c025b2b9a942abbf0a2b6dd0..7649138eb70ee33ccc98aba2252999969c7569a4 100644 GIT binary patch delta 157 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 JTZ;Aw|2NmVF(Lo} diff --git a/applications/plugins/usbkeyboard/assets/Arr_up_7x9.png b/applications/plugins/usbkeyboard/assets/Arr_up_7x9.png deleted file mode 100644 index 28b4236a292708b412629ffafe30f6d011491505..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3605 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 AV*mgE diff --git a/applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png b/applications/plugins/usbkeyboard/assets/ButtonLeft_4x7.png deleted file mode 100644 index 0b4655d43247083aa705620e9836ac415b42ca46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1415 zcmbVM+iKK67*5rq)>aU2M7$VM1Vxif;vTv~W2u`S7ED{V3s&&L*<`XiG|9wd+THd> z5CnY!sdyuJtrvQyAo>KpiLcV|{Tkc)riAbluXfwSZCApL`ztB&p zx6LGKvks4K_4~)qD&oGa-YdJlW)hAKMNJd7<=t?6c^RI1>c$ifyjaM>^|&8!ey zB4!nh9u>5uen6Ve@<H5rru6h<2Ef#GQdQ*CmZOlQi~N!?9H`Rp;C% zU}CB21#?;r`&0|6C0}b-=jODa5|nEJ#ntxQ&{~jpgtwDta4hftr~G=#p@V36e4Zjh zq%J~{y26Jjn=1Nw-l*3%QW5YFE*v4z3gt0$&(*xf2en34c?JpH8+FYldo+Alvg8af-pG4(=!fyUi-Wsg z`g#n9VUcf(DFr{poMSNzw-lz>w+HV+n1ELr&SLA#LHUb0p(xWQ(1*vJ-i+1!`swxZ Z!O7;c$;lT_->m1Ovaz)0yuI`A$q$F8u*d)a diff --git a/applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png b/applications/plugins/usbkeyboard/assets/ButtonRight_4x7.png deleted file mode 100644 index 8e1c74c1c0038ea55172f19ac875003fc80c2d06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1839 zcmcIlO>f*p7#Yw)M6zw!O+@VZ{?d|D~WYi~8rHRY?X-&T}Yen`g$^+EJ;z+|RV zE@PoDvZ9%#+_}3bC_5Cj8jDGq541mi{7F+&KF}W65sr$Xn5H|YrMQ2(J7%Yc%;(zO z57ax000=TsQ+1Ke@+w#iw3au3cGGQWY740k2ijH>P(6tD)S)be>gX6Tj7`<`b>di- zgWp$8Y+?i31~CzF0&E4uRlA=C(Mp~K`{74jEchB|)4DDK!ZVhSwdFyw0YIZ1cDh0S{OvfO-U_~ zvmRF*m9sWDXNH)GOyqS1Skhxbr6}s*7t&@~kFM(NW5}qh?Lu@lJ}HE;FDiLdGO>LO z5pS*%E2grR)l^;|?O5b_?u0me&c1U}%jrk8*%=Wk%i)8yp2P|kuxmKg<=(u_`oQRI_0 zS`-DNysBx=#3&qSkgA@hJP>~D+ZM(s5jI6Owp`?yE=3e`YGUqkVOp#Cp=3wR3O4hX zX6BLsN3UBzV(vI5;|SZHgOb=HD0VFjpTyfFW}GnQuh>2*Q`k>*cAmA#iUT7EXSpo# zkPm5~#I-o^cpgfe#P$=4-Pi*SpT!-@nJgp8L347xe>5EKl`=_ZFc8XGy+_j=_R_7! z@vZZMowS1GJ?Zw)eetks%~G{BTR>T}9|jt0j3Btyb*C3-`C?fwY3EY`q*oYZ39DpM z&uJ;PCZPLs4QO1Jd_|A1PF)azZJ)RZ`^-VMWr6e#XUOA%3eLG_Ch@BDOHzMk*MF0G zCo7xMd?Mg*HMIXw%nNz?%60fZiZPlqb?GqUpXO`F&Yi!okZl(n>P@r1P2i)yk3DgRwbHeNn6e|;J^SK4TM LH~i+q&mR8;k>NTA diff --git a/applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png b/applications/plugins/usbkeyboard/assets/ButtonUp_7x4.png deleted file mode 100644 index 1be79328b40a93297a5609756328406565c437c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J8d-yTOk1_O>mFaFD) zeWb+ZHz{mGZZ1QpXe09^4tcYT#4oe=UbmGC^A-KE*|F&zP#=S*tDnm{r-UX30HgpM AM*si- diff --git a/applications/plugins/usbkeyboard/assets/Button_18x18.png b/applications/plugins/usbkeyboard/assets/Button_18x18.png deleted file mode 100644 index 30a5b4fab236d8b57242559ef94fb1c5dbb5d10a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3609 zcmaJ@c{r49`+jVNvSba(81Yt?8Cx+K+gL`~8rw)>jKN@*W(G4tN=nI=Eo(wa4Q%8vkx{u?zYHw>PBq%Eg0DzDc z(hS9!#kL=Q9?lyh8i4}IOAwh8Gn{vj+=2WcHX}wv6 z{-S5$q3oHN^-t@S6WJ3RZH#u2$UR~zN#ptcfIceP0M?_BV27-0s*2>6L=N(TM8}(7 z`|{NTz#I>Q9zlC#w88a|1aJf7E{y|X4MV@8D(qEU08kPz2o{^z#g&Kx8Z{gnC4k1g zz$1sJ-hx0100c6^Ou@i?Az=E4l_4L{Q=Hr{4fN#iE9M8{xPXj4 zwXcCZrZHH9x3-ik()GEPC3j>M9}pamP82cr1R^s`)mi|M9yfs4FW$-nvgXNycGe6Q zdyu19NG_nZIkh$YM5nd{EA_o>$im#H=N(jFoW#zri2 zzHaq}&H-mLjWbGW3!*m9Vu-<|sQ8IyUQrUuD^Y zZ5kLaP)TNrO{v3TljpVO71A~Zl0$?5=4HED+vhu;fXTOrK ztd-`*>@YLleW2Dr)O5#aVKIBW;(Net{L&fmykHDc=SE~9Xfj6PB)GnjQpjCw>YwC} zR9aA{Na)9%HeO5YYXoUs+qhO~shM)&$w{7%+(E`K?kUJ#dz(k?py`OXN2cWmbjX(N zhetloFX}k)Erp$Yef^5L=T)?gtyCsf!S5mvbxHH}AK>JBc4f+;Vyks@FWBQm zv;|XTR&l>#uJV~bgvC9Qkq3mEZj9OrDk>*xS?#h4K=vWk3mpm#J4Nx?)+$qpgr={f z{7)j8p!B5jM3F?h8|zJPM$08&^)bWN0{I6}g(+gkb#X>xymxMCnP%kOKiOKG`;q^C z4D8k^D?(ndJ;dQkvA9l9rgCeR6r#CMy`bxTCf*mn;s=?eRS0~E+HaozKD{&G+s?^} z$*3P8yM-F2nbx$W4+H`tb7MFv+BM zVyUoH=hTSQiTjRDR41b@#{FH651d3EoN*4nYvJ_Nexz97qtt`0VtJ>R#YalpP$8%U z`}UI_1=Sv#7uT>tPcBDWD+@7pXTL<&4 z%LPNuSvw%8_kEZ?Nj^E_XIr_1-##9k)Bl`(yiKu9sO_9OkGhfi<8J>FpOT1@qrIWM z)xBOblo_d+sa|#vImb9hEoTWvfUN`xR2-=|SrJ{)7u5dU@B?;=F)6V0Zb^9ZONZqW z;YY!e^mleQyF=k9REPgaqD-Ks9(JxJ5&JFRCZ5$XcWLO}o@T#_q&mNX4y%GcSSqtu zd`EQY(uO`v(mpSy&R1N2fC0t}uhmyrS6DwQhyL`(& zG5PLev}0iuT2M=HAh~j?a7gD(ab5A7Nf%!^-`mujMP2E;ClZ^*(u32b9SB9&iio#D zn^VVRXDd3NeOM~UdYRQ<@|p1QOAEX{{K2}7MwVQY`x`jhf8pan$LN{4B@!7wn-ktw}#xeLT_EEzFQ3*fLAL; zbVp=F?A*v*KepDqneek_h_N6wZ_DS&^@?kZtLlR6g{M3LJPN!Symxl$^2PDJ+yU8b zC~3M|K*&{rl1!?VUXWYGYWMr9Wp+ruL) z{+L0_z!;VSUM53&HC*D*VXgZb-%pk~(9Y6U)Vi6YuIs*4@$(7A*Iyj#^M6hW_GS79 zq5`qgS*%Fbebxo~m7nJG>0&hT0|GNwN9%g(;8#be+!KMB+S#L-j%hS(=~#dM3+eI6 zw&vUr16N(w#4x?+n_}rtjK-osruLA%c4I|E8+q}COIgu&=GFOe`6nNjvyL0w7|(G| zUDo?@EF7`sciGM&=&iPZ9ZHpvBy;11(xQ#CS@&0F`{%Qt)%8=dQ?d(CLin^Y)lbm! zgXMNUs;bFCql|IFJGta5?^Z^YR;i19l7Z3I9R+2mQhQ-3YsfuSy4zkiIty8aJoQm~ zz-R0Gs?x5DQejnzkL+2Gp7yZluJeQ78uOP@O0f>oAsU+Qs0wd7ey%gT*{}IY+NS+5 z8s)U$&*)!>M@4nsxr0!>=%SNaoYK@xEd6on1y&N1>g~k#Pw#SbK7Uv`)q_c9-Yfn2 z$bvOK>|*QD6}H46^!9!|UjA-o3OQ9cMP#nH);v63nqiQIhLn4AaU_*dHP zQ2(X)*0R=jtvtFI-5Ix*=ghu^+eZqPLvzl%H#={ZJSeaJtkT5nouAA$Ik-3Fq#d+qrDcp7N)W0{b7<)I1R& zppL}tN5aTsS&^jPteMP^XXI0dgjgRTXXGub%YQ|%HAk>P4Y~;~xp_GU;q$Ab7n4Vdyo+*kY>nU_ zGx`}T)*BfC?kC-=d=c%rM$)ud>vE5krp2!l3GQ>1E|a6_gjoA_Sa-zzYeJtgQrJupeGtwb~ zv)29Yp$YVd8`Zs=-*>Kwd_P~d^%z%682ss3>)HOsRfH`pa3yyu<=2NRL!Fi_mR(8~ zN^uD}3JP*UvQ-P-ZOKDLPm09b-$gk8VoXsVObl!eub*f~Z}iOVT8(Y5DP-hN@s|B!#~QYw=)K*F;Y8Th24v;Z;(DaM z@*d7#r3}p+O>-dm&_Xa29AM&2^1^|v2pC@+3WxD#oNdAx0055)-Vseh+gQV}B!UKJ z+ed>=Aal?FU|>WiW3T}@8psRhizmXt?3XoQ5Z)UOcG0zg+K>@AKRhy&f^!J9b;O1S zVD-JhMus2*I*da=z|k-uIw6oqh0)>QKY3xC^|l!T2L0(m3xI?F5{0(02O&rl9O$Tq zraBf1g@TUiYj|V4Fjy}yHINomOA`XsfoSTeL!mHjeVC38=&Lss+)~Qs;Q6QyD}WhOSPeD*a|K!%?vmJeh_k z5kcFG7%x%~4G!i={VN9o`5#&$_3v}yoEU_TAwx7ZpxZh9cC@ki|6K`$f4r$Q6z;!z z|CN~P$ROh&C>)g(M8R?@=cBY8iVQ=&_Npv z7Ej!^9QqStV*|4yQfU|>7H4G!2Xja?@OW<+RM*_}sEH{;SI0tMQ_~z_s%xQZenj8Y z#MBIGc2r;QH`a`V4IPoKl5_wQQ%!g~LUmcOwk{}T)0h=FX^_W#uSw~5n0+sl7im$Uh&`Ef)}$5S}1 zy?{b{ajwM@~ diff --git a/applications/plugins/usbkeyboard/assets/Circles_47x47.png b/applications/plugins/usbkeyboard/assets/Circles_47x47.png deleted file mode 100644 index 6a16ebf7bbe999fa143c683bef713a6e2f466cbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3712 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 biU<_Yn+9Io=xs3K`2!qm58ISjpSt)z2v?8| diff --git a/applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png b/applications/plugins/usbkeyboard/assets/Left_mouse_icon_9x9.png deleted file mode 100644 index c533d85729f9b778cba33227141c90dea298f5e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3622 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 diff --git a/applications/plugins/usbkeyboard/assets/Like_def_11x9.png b/applications/plugins/usbkeyboard/assets/Like_def_11x9.png deleted file mode 100644 index 555bea3d4b0239ae1be630d0306316d3e9494c4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3616 zcmaJ@XH-+!7QP75n@AB6Cj_Jk389)uC`sr|AV?4kfrJn-g%Axzks?hP5RonjD!r(n zC{1ZnL_k1#lP01AyrBpq0x!&r^WKl=yX)S2&e>~!-~M*FYu)Hmwq`>7hxq{j5VA1G zIIvd%_QS`^$$s}$EB*oi{3c{H`jiD44Wct>p5#kJ0Pq{hbR=ON7bKAz6Kg1|sNg$R zGzSS@kOL|vSUf>dRgO>8GD{s3abXXl zZob)?3Vh%_P`mN5bLZKh!FYeg!%p z%3DE@^WB!`05*g4^^b$=d0qk>etiPGK)p>yy~dHqU6IeIw6h$+H#q8<2`8+0gT(=( zfH+hhU}VY>oSCZV2xM~sZXF)(Gr%czz)k7;$37r9b2BZF18}_~C&7`O0Duk>qcDKi zNuZ?r^i2~0rvZq2S~bIgA$35*!r9Xtc>Elw?-CU#2Y3Ym4g08Y6@V)caBGv7_XBRE z0pg}B&icO}FB6?tWmhV#T)#>IZW7|ktM0?&>{+RSI8F|NM%37wqmnvoqISOg936DP~a5jvBP$aPUd) zV9L(@V@q6K=LNDaZ^U?(ix@ovvKL02SLu7TG0C}AH9R~wJ3D0AjB>@lalW=gYP?YI zynX49ApP$f>mOcDD}-pC3o+x`{LuJz%{uo;_ier#?qeV0&AvYu*!?cs2X3}-ufnN{ z&)AFk#9`87S2c6N(Wu)huaEWa5~e5Bwm1zYb%4hg4LAZ5)C0xB7ZqEF>VlR=Acms5+M*XKlJX+0{G$1Was3#}X_!2!jo`6dPi(3vqK3&3D6TR-y z{e;CO7GhG*r_04cf$&F-&2iQ^+adD;&=Cdg10#HTe4IDz8Ao20R;-2|>`Ur=nn)VW38z}AdQ~Ff z4S$kll46pKDim8-lvgxSB;d5_)PapJJnwj|%+yKCai);(eR8o=QRb;HjxvsS4N?=o%q=9TkPR)cO%h%c*5tH|VOTUWt|XT6J( zQ<8DT=Ee5KW?$-b%NFx9^Xg1$T(&}ljax01&MKLa;=A@|&N~h}j_32|OWGh2>t&E4 z?_8Oj8Vu_dHGe5J>*e|2ENfc+gn!-qwQQh5ze za+e}Ke_htJlvtN|t@_%p+ejXv$YJ4P*)y_1zE2tAh|`FP^sc*0hSy%NB`-ipxNgzz zA+4FpgB>c(OVMHVjG=ueG2bxBn28J$%ntrY-BL%@ zpa^nNe?+fZyV|e?;_33XAD4-WqE^PcF_n-nsa; z;?3wSy}Qfzb{EAO#injo=0;dKtIOg()|Fg@m+SlZkMhq*>^~lHn!7~*#m!1pO21w4 zqH{`FP@Q6cjd#fThBu)N&p5ol2srW2g4XeAsV&84v6ZuzbDKwAxN@-SeZOok66+8@ zaQuszaO*EGcQTh*>O#6gPQTu5nU<$x{AU+7_$D`w3L!?W#0Hj3@$~(2MV2HBy@*O* zNjJ@KOy6>KcdfR2YtS?Bc_QGu+2}7KceV9h{4H0p?c|Y#(7r^{N_T8#Qs%WF$RA^F zqxUNV=RLY6FN)BXt3{bpy(YUc^CxRhcAZ^$!CWaHojd6K!a4mB;sWI}^Rxa=VxL`W z&E1;xvZ}M*RZ9VN&jLL+7G$#Yy2jV){C}6+9q7-3BggAj185tsH`XU5$AcJ3+g%+s z!z`tx(ptOP3u{J;#>43G$bLiDow1?ivFjJ>S=p;SV`dxN;bGl73G4A9=>73&@f{ID z5nr-S7{KAvhK%in@A>F%Lbqa;)Xx2#jxs4pXwYW=m%*-{)SjG_m6XI+l&iVhpX+N!QZEys1E>~%495#iLH8tr1Qa3@5Avg2qWU8Ikl;Ug5$ye*843pd>B96zg8veQvpEGq(-=gM z9t5WDp`oDx(t|^Y1iYrZmM7jr4Wy}|34_Aex1Kso522}rfWbk3Uto4X2Eh~IfHD0$ z9Q%X>doh`G1Qg0*u^=oh2#rC4!r*W?R6`T0sj1HPQ1|txGVy-uRA2cY3>c!X2ZKy! zl4(@X9wXkJcA1F;v&H_E1%>_(E!Fq$O0jDO^~2MlFo?!pRzDnVZ2rG1h4PQLFVlhe zAHDyR*ca5>4|eZ7<@Z9-5oiVx&!jQ1G}@&fg*@d&W72%RXmpUK76b-T zw!wRlse2ZcKOr_Y2n(t&6HoOZT40c1HVK4GCLl06rdoP1-4j}96FnHr1akt7)DQm0= zd)?jL%^kis&fXojz!+owM%>*9Zf zDkw-(np6Qnkq**CWPm#qVWfRw?l|}RalL1qbKdveYd_C^b~$UEm=m^^V!{W70RRxg zSz#Tx>)zc*keB-wEiG>W0AX_~26F<3!GM@7h8Oh$836nT(;X=U$5|QF+UN?}Iy&Tz zHN!z#5afWq5h4|@qM;}xc|2P2!GN@V-ClEZKKYi+Xx`Y^kekx>nxfZ*`vs;HAI641 zioV{qF&^~D=VSHS=Z@_cea16|%juc>Lds2m-bEv|8;$Q9BY}(J7~SLay=Dvg40g3x-Gm zrh&2OY{1llCnP;t#SzHl1Kip@+$Vt(T7aAC)z9yNko5JGARfT=j-oVAW;_7ePmaa{ z-bO%S*U9VV08tx|^0ID(1N~ZnHqP103V2!$)OJdWlmLRFfVO>fggU?%1h};*Dft7} zQUEE7C1>OxM~fwAG`N*YDM3~!!_7lo1+{zyoSh+u)jDyqN2Lr%zmQT*A@u<%ayp@U z5}%ge0zhWGG&kGjE&opO;?7Qk*fQ~RT3=uD?||LiC%31&3Yew)7M}QD7+-+X~IEz(=5ZX#jngsy>n;EL{)J%S*?to@3 z|Dn1)!*wE?ZU)!T%8m7CNwlzM$RU=SdSMt^EwbaOf`%LPgQ0G+VS$ZAX2ozN0{)CbWQn2KD(gV!t`ioEk=!&2j9GSl9% zo*zWrGiD( zbUown?F%)p6*A!Cph2X=W>!QSqHVubF6fZ5-rhkWLm}R4_VudZgk0n{2uFH{_ZL+J>;XV1`J?$FPRma1gt)x3j#r8;oOB&0^MpPm7C7anpO|x$cckPQ zY zDtSwx>IN!5?*Sa6dtBGK)M5FKmx;h+vhVsmwyn^NT29h(@byutMfC}F`D{I#3K;pc zPkv%jBC)`#z`nq8uEwBvJ|{i9#=Od9BUIe1`MBz7RZB`-=brQ##{tKY9N`=pJPNT| z49WM&l7CQz<-DfnEF@>VIvbKliGB8QhAcrL~DAa!mpyJVvYZb zUr2SpS7fVa8`&7yG(iM@n@Q_S8!LA^<$p@EEVt|>8CNoOD%)kD ztePHi3ht6cbUJmW)S@W8=*Y*aqN<#|ITf}EwgnjHH!LL7BwVSy^4k_lKrCuNyg=cULa^U+mK5S7Vl=h$-h#=MH!F#=Pzte2 zva4TrvTT35dLuR6G3~u2MV3QBgQ(c9g<`WNt16HX{nhy&R+FBGalHpnx0mg zRzIIR^kl(cfw~YieE+T9ef10%UB7n?EtpUC)7>T__wQ=^j1>mkVeCRFFJ_dW9?*E_ zqQ0l)S)BYe(xR;KH)GcQN#jYR;i%52%el9PwdF14?RE`}jB^oVn5#-Vo;!g%-9S#r z5grO}OsH9?>n|JYftM9u$C@C9$lpo^=FM(qR+vef#f24xP1hAEdbj+3t4MKeCb=`d zlPVr@BKXV4cLJo(q#F&vqN)*55zdh&vCL@V!ERWRKBs#a<2Q!=j!ndlrcq#a@F!Zw z^)-z1A?J~UhLw7iCQT48m$$vdbRzD8^&vP!qu79c;nmpY{BqPp`h>`2kZdxv44KqRAes&eQ3DIV9e>Lgov(;bD5HF( zeD=E3UPz88*?vR6Q4T$PSD@9W^j6^>7cJp3boLj*DYZTgff5SY+3R&jOdCA0AmeDq z{M*vDp<9Oc7Vq!O@2lT8e!DCy(%M-|f%v(m@I1T(=^HR4JSn~BXyi%$LgdTqWg4_z zyMlS=q~hQjl|Z~t=-Ilqu(}sKK64^Y!qX8~=7#&`&)5;6E@Ll9-y_rIjiqC*7fTJv zCP`oIR~z=9mXBhzy-pdv^E|JhvBI;`y4b+rbFs0L&*xXa znGZpeI@E@$!pkrfk6t5RR+DpDJ3EX_2#*OXgzp4{g`SZYq`q}}_kw&-^*6oWdxu=B z*S3sXUky3&IN^J}ddVBOjnXxf;+Xu|^~4R@nIc=7?|d_F5AT+Ml6YBP#fM&n9u&bL z?&HxpOY!DkUu~x^aQbsjnq%sQtGjEZ-CN`Ck6%XvH!X*LmAI#ebO|`VOlYMJ&W62Dpe%LWOuw6cB^dJO zu-nkXvY;7{&av|njKxYx_IQu^&W#zPYNO86OE1|=B}3EuonJbqK0%zLePw?|ZYR9A zYp%Lim0DbJ+NWY6u;xXO*V?RnhGFN(N=?8YGCLo8GvKI^n&m*o+MBi2F`1EImg-h# zd({9(b)l%*uKL`H>AcwhW+bZD#C3bPe{uNg`C3lqa`&+18h=E1*LM7BoCIc1TuNMf zq*&x!#xY|!e8PmaHM^OE>GJGS$&lTCxZPeXD+3K)@15)G>`v}}khGMP@S1ixYwK(6 zoZOS4ruwGCuUh?eVP{uPZp_zlhB*q0kH#eIrY?i7s_l6H`E1qkUCu^=TtdPQA8+#V z=A!2I0Y= zK}fqk5Puqziv|Fsi9eI%;X`JF+{qLw9R*&jdJP6qJyBq1eY`fFi6MJatpZtO$3R=%hbBlzTL%V(ac@H{m?1((7XgEV{=UH6fGkfhgag*% z?{M4`3hd2hGZ9cIhr@wzbRi5D1qy@1;ZSWIsE&>n*F(!MfX*iQYtj9belTFkejY3; zlTBsNLA#73cg96F3d|Mz?<{D{e`x7`e^-iIGpIj_357wlceDE8h{ykLR~qdfZ$GvJ z`9FI9E3qFTfJufrko_1JSsvWpc`5CNVj?gsGKtM#5g3dMKMHxmo55!Ic{7+G9bE_v zq=qMXQ0coC^}ir^JOW4eW0U9}WE>U+=8{0DR8Is}-$K_AW`NPfm>a@i=GbExj3GuB zt&hbXLt_l!=pR@t!{Z{2OlSYVdj1EC{V8^LAZSc(WGtCQy+ro3U@>T*zp_S9f3C&s zr+j~7J%6qR{ZlNID+apT+yB?=A13Yq?QZ`WUhd(a@h8){Gtc4YQ z0;jHws9YPp4#h=}FrzISo|AMhZvN}rHxug+9smjf@b~stec&JD$aK0bym%#uaXpT2Gcd#)x2azcxAABGV0BC)Aj-lw(6)B^^6`Y8RS?}DV z%)ko(See1!Eb3M$dL6)A6csaRjExg?k&xVzi*Rm;?iNJk#f=mkVEUR~jXN3dd|Lmz z;y}sMh%ol-?E1&`>dD;6jdps6NYoxN)s%@sf4~40YY6LAOtMEbwA4g#OCpANL823^ zSH66W05Hcxr$tg98gFntAOYL}xm$C;Skv&Ym?{TVR{)d(41vWacX1`7fM!jnW(lBK z26*WB#9I(Z1Ast!xEUC@Cj`v=urcBTdP`FWq=DYTy`}s>0vC{VzHdNRvxNFy}ir1|g=xDsrFP&l1P<-Sv zXLqYVYz{b^ZIV@1Ulg->7DEgvM*Min&Y8{8QW! z$_pA434?^wCTq$4%^>Zo8&|8XwbCv;KEd;WJJ{s;T}8R8Zwi7ssk$QWQ5l5+opKfX z;8D*COFEB#4W^*FIrRU%PDSc?B(}+9ZV?N9(yH>0uSnM?xg!>+>;e z{{7tXQQ|ZFXD*7q3XD!pwnih-=66+Qlqtl9;N-D|PHoI&B5d8>^V#i{mE>V0gQgu3+(DG%B z|8W!pl$lbQERt-0eZA%NSfvE4F>VAYP`DpeoF;Zm4`)2id;6xgSysWl6K$pWANcRZ z!ETRXKIU9G=@9lEB?<{ivj7!8FE9WN;qoo2Lr0#c@DmcF=JzU<73PmM3 zbe!-gs`c26Uc(AKz7%U!a0yZ5gsprdo1i51MjJPeHtV6d@Jy=*+_3dJ^>}p#8N#kPK_4t?hltq>u=?m+t z?em(Y%u3Bp_pyV?c_w-4c}p+?Y$aHr>TuPGs@SUj;Er!b@3GVLDS@T8OTts1JFS-p zKZ=&5zp;DRor*`Gy8MTeWdpVJv2(4-*slRM@XXG+i^F&Ku>7i08vKenZHoS4s(!!h zJE}*MHu7PR_IfdNzu*P}3^87K?f&A1;>NMsgKcR6**;aB74NC7tR(NB?{dHT-9QhXa*KoG!kGU1}$l2D>ypo)fSBuG$ zkTW4?+|I1m?6ZH8tD4^fB{cUpoEoZOo%4hl!EtNtQ#?j*jJR)x-Mn0TrxrX2uT_rh ziOh=Jxsktqbd9x{^s{c5z92Pk$LGoQl53o+=7QXXCp-Z>io998w|DCCCGfr20oiRN zX|`KH$W4)wN~)J$kYB~>4EU;NcS^qH&yzeUzXokpMegg_lX$6ve^4}%bY~Sg)%uJ- zZpb$p4x^GS5d{XJP=STbfpHV`58UBH& zKFg&BgS6bV+#-|^KBGeIBee2B zrM-`uTB^_(eS+{-KK1h3l`-Yjpv8X4z*uBwQ3a~pL0Ae2xvNGyC3A|#MARToe$W~8 z+4{DsyenENye9df1M}gNUM9_Leh6G=`9exL-cdSKQ_CGyEdZ3W5uoR!Lb^D)9!bd=7h@R=M%=|JqX9XP;Z6# zFD15Bw7qTP(ZlG?o@#x@=wG;XxM(>n@4P$9WwY#lW$h=`zMi_zq30HbV-zHheqpE0 zR6kXtxdzl&Ml2D#zDIvflJkb*e zIAI?GMjp?JBK76WW`{l{pFAY|%5?nYUxRnT&y6~Kz19AD;C0(z*7?dM{%HhVtqWEc z%+M$z6u@uQu)kg_%2PO_U|n1JE0V1>iVbekOLEOG$U6X^Umc519WC)L$t%`#Di0$ zY1|5H*440_`onhmXeayq`8EIg?x2r9KWe()q}QayqCMEC?c4meb4}#i`HHPaxO&3SPtSVKj@ND?Y+-@R`CDnf-d`T>vTn8RR<=@3 zNXk=Gloyh#S@3R89WHrXBHr;f(&ZO@I_Uo7;O5Bs@ecGx@7%7{_>Q`Adg&sCeZTYp ztVy{^vAUfOpTDzF*4`h%X0odWn`#uZ4s4igIV^UrVVg?c*{>K)hHq^^RxU2CM;WN> z;oK@^sg`J}BguyvilN{DQ*V+N4rD{X_~KAFj5qyk3(gP#cvSIDXe!zk3B!^InwV{j zCXGPmumQl(m`28618`K37tR+?goD{H>cAkpHyrG$XA89@o8$cOh%gGyG0e^h8y0{y z@CF+jfedLdjsO8i#eispKw=P#1_%GG3**eU%@8o?ZwNI24*pM2Xj=!6If;S;9nsX% zz(S!=&=CVoZ;TfP>*b{m(uQhlL7=)2EnN*L6sBVU)71t2^ME<-DBeCWl!etl&NwSL z*pEsj!yu5*&``}#9ZeF&7oufgU;u$?L$tLuI0%g(I+2Q@X%K^ye=Atvg0K`knTjV7 zLEDNLFH$fS4(5dVpED51|H=}B{>c+3V-OmK4AIhrZlCEl(AM_T0=zuK- zizjYd4*pHCwT0ObgQyrH7H4At2XjO;@px~TsgAA%R9|05PuEIcOUu&SOwUTs^00xK zshI`T;)sF%Z>|Li8%)3vslU12|K;lbk-Oav1Tx371&)Fb!FgLzNCeQ|r-tGG9E;W; z_5R^{|2Y=zKXM_QU?AJI{a>~IZQ?Z0_VnM@{Vn_(lP!vI=DFY(X1wo}3 z6%<84X#!FOq&E=|(E;92gpu~b%sB7;nD_3w_nve1+TXXoz0W>totP7L<|2Y}f&c)B zSX$s5_r|@CpPTbH)s?gZ06|kK7JI@Hiv=;5bT8@!G5`dOWI9psPV>^}^@&xCb#&+* zYr3NpKgbbtGgLA`MO{%q+$vfzXIRRie!rk8K_zR)VcF)&~UC~C9|TNuZ~|h*+SbvH&nO~b9n!U@Rp|LsTqiIn4mHP z5a+M(RP^6g;sQ28P^e?zI=)u`S3sW-KTv0zQKxk%YFF$FChas==yk3-R>E;>{!mH4 zI4BO22N;`ig=VIzI04x_fP1?KX&N}83An3X{nQ79W^SYfa{+F56s5Sb69CWwax@O` zHULVxPu?&E2wH%omvs{Y7}5l^EM2@TfXB~)x-M~{a)4hL&~k{5I12Ct1MaO#N&&$2 zG(gg9*#-66u`=;Fbxx(y%28Fy2-7e(eoa3<7Z=E3wJuAUW0HErpNQ$kkcPlCS$LR^ z*oT!40LV^|;$*wB9nd9O*43pKS1Ec<^UG`AT`-9>y))Zg%rFLkDOO0&js~o>j1#f+Z;+4CbVD~!F`nC9H78XlgVnHjQb!nhIJT(0a;8qU?Z zY+v|21huuk_Tkk>`~ZN<4pV<@BEMRHP@|6b zQ2oBKdZ8_Mz3Uj|rUr~SM$j|#5Yzo=$u*2xWancAb$94{V+EZ$2k*#4hA5=L`GqK& zA@-ffpH;6`6DGi8(#n5;s5lbMMY=&yisP3_i`Y=Cx8RYusSJ7>E$INZPSCZ0Io`m7 zoGlcV(afI^QK!vbCK$8=@M~LOLRj({8$;1!-=?JUOl*km%9=1Y9Cq+${I_WC?e5%$i5{ z6E=@Tm}#AW9uFG>A|5ueAlMM>hAav|hm>{pj|k`sa9?+5Pz5IzSU**Hx&Qa3gCsaC zieRCkG$0Xw04g3Fjcw9bmWaW^RjY3OWclPFzE`5xtk>63X)yr%yQ_ z;*JLBSZl;g=1k*^_Kf_D;osVrg_|f_kO;WvPTV z!6d6Bl_Ys}D88^LuV|u3$a%%N9UotK*6B)_nX|UjbfLie5|fB2Q`Zx!dQcDg&3-Wxi={T7o>rcwHPf0OsPL*Ns#x28v0Y4e zw5`fJnrC2RVAIms(RsgfAWb&|4I6~dWz1y^W=uYJKNWCFqq3m#1=+HE=2V{RVr7kQ z#3_VpF2VWKnF_Pg%+ezR)uq+>`}3>p677n!1}Ke>f2(|3S@>M`@$3-qXjvt#@(Phc zlA%0*Q`WecSetm|<&|Hy(R?CN!=l9srxZf`pE4zpCy^8BU3V9auDn@Io`+Hh-QwLt z+S8Q>+K)C-Go3Q}%qcRID*y16=$kRt*V-W|hL8;T=JD3r87tPB-sIhw;I`@udxoZ2rYiz}SaG32e61tb96Rzhv^y{9tK5w^gq-ULrn8aRH+V$KG+U)`ILyvG# zxMRXh!rXq^+z7g?_&UxAIZFOkKD=NOn_XohWfFg_^xABFsiJr5ueVAS*XL5Z61u3O z5hp@E54__eej?s%3=vk1h>CEDG>T(H6XbeeDZ1>QF|7Y2?mI3SH<3Ys*&`llTIs4A z7D3LVM)Y6myfkWtc)51;6EX>w7pxBvyIBXNR(4GIkuFtkUnCwd5bTK%xyvW2>B z(CuFnYIFmY-)QG*%vN1jExc7@BVse2fy|OlzXYPe(a2g@`0a#SewZRf+r&!B7s@BE zOYJ4(i1M8`zBivk4=3@x^{Kd3vd>jhuo9E^8GlM`P@S)wLU!?b-5Jw{NG{Gg*16D8 z(KdQZ|L)Sg-35sTiK*L_xslc`nhJzZwI$~f1XyNYV-sV#htsJa+->=Y%#yiFj z9Q$f6+VbllzAlt^81+k z=>5vzIghT%^J4U+m*T9cUen#1a|SgAU8k2{u$Ie5XAii%a7llJJV*P&`hwa??6YsF zzFVDMR(0B^YB8wxS+LjoynL2^*Z68};BV5q1N~VD^my$`5Pkj4`r4%QcnDKZZ5p#QfD<9kK*{zZ#vvYr^y-Y?L8nV&J?JzD zanA=5Kx1&w0Dv+IU=Tfg$Se?vOriRs!AsSz!62$98tkHLt7Xf;lD(-GK}@n!kR9G5 z$j1ZW2{tkWp#qQ`0vee`1O?D8`1&IQ(BMCKk(~LS843pd;llDkgZ~souss37(wStC zJ_M%ep{1n-(nmnZoDNfCx0YnBA2GQEf>W8DP?f-YB(f;=KXE~Dp zqxT<){qcbeGSrdmPru0Y;Ow23(q1SA63ZkLS#&0zPQUP@kSDz9EV{opodJStLtr2^ zTcQWmch7S44~VTT($d$TMfCL`TjJ1Q4he)x^+f98FuE`;eI1yVnJx@wiZj7sk7ICf z3|1em4MV{7e_(NRkBc<2FY5=^^FLS){(oTi8iK~)M8=Vs)JtSfGbWt|`Xg&3^&hlg z5ilLB-f;wnPv@Vt{E7Aa2Q7bLP5vhq$`J$I+uQ%z>mMdg1MN-!ZeGsf@AfDAa(bT0 zY3`!iXF2z3K;VQ8-jp-$h5$Pu0Q7Lr69@cE tNU_5F5@tDqw>z-XxMyOWnyrgG{91sV9boy3dsxXH+S1exSB7!F_HPPcG0^}3 diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_down_7x9.png deleted file mode 100644 index 9687397afa81c92fb727bd40542830392fabdccb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3607 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 QX&eA7&1_6djNPvM5BL~PlmGw# diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_left_9x7.png deleted file mode 100644 index fb4ded78fde8d1bf4f053ba0b353e7acf14f031a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3603 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 diff --git a/applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png b/applications/plugins/usbkeyboard/assets/Pin_arrow_up_7x9.png deleted file mode 100644 index a91a6fd5e99a72112e28865cd8a004c7d1933fff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3603 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 TFC+3}9cE|kU{!4CefEC<&8td2 diff --git a/applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png b/applications/plugins/usbkeyboard/assets/Pressed_Button_13x13.png deleted file mode 100644 index 823926b842b8f9868fd70d6f1434dff071c04d5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3606 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 diff --git a/applications/plugins/usbkeyboard/assets/Voldwn_6x6.png b/applications/plugins/usbkeyboard/assets/Voldwn_6x6.png deleted file mode 100644 index d7a82a2df8262667a9a03419f437ff9b350e645f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3593 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 -#include -#include - -#define TAG "UsbHidApp" - -enum UsbDebugSubmenuIndex { - UsbHidSubmenuIndexDirpad, - UsbHidSubmenuIndexKeyboard, - UsbHidSubmenuIndexMedia, - UsbHidSubmenuIndexMouse, - UsbHidSubmenuIndexMouseJiggler, -}; - -void usb_hid_submenu_callback(void* context, uint32_t index) { - furi_assert(context); - UsbHid* app = context; - if(index == UsbHidSubmenuIndexDirpad) { - app->view_id = UsbHidViewDirpad; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewDirpad); - } else if(index == UsbHidSubmenuIndexKeyboard) { - app->view_id = UsbHidViewKeyboard; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewKeyboard); - } else if(index == UsbHidSubmenuIndexMedia) { - app->view_id = UsbHidViewMedia; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMedia); - } else if(index == UsbHidSubmenuIndexMouse) { - app->view_id = UsbHidViewMouse; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouse); - } else if(index == UsbHidSubmenuIndexMouseJiggler) { - app->view_id = UsbHidViewMouseJiggler; - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouseJiggler); - } -} - -void usb_hid_dialog_callback(DialogExResult result, void* context) { - furi_assert(context); - UsbHid* app = context; - if(result == DialogExResultLeft) { - view_dispatcher_stop(app->view_dispatcher); - } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view - } else if(result == DialogExResultCenter) { - view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewSubmenu); - } -} - -uint32_t usb_hid_exit_confirm_view(void* context) { - UNUSED(context); - return UsbHidViewExitConfirm; -} - -uint32_t usb_hid_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -UsbHid* usb_hid_app_alloc() { - UsbHid* app = malloc(sizeof(UsbHid)); - - // Gui - app->gui = furi_record_open(RECORD_GUI); - - // Notifications - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - // View dispatcher - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - // Submenu view - app->submenu = submenu_alloc(); - submenu_add_item( - app->submenu, "Dirpad", UsbHidSubmenuIndexDirpad, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Keyboard", UsbHidSubmenuIndexKeyboard, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Media", UsbHidSubmenuIndexMedia, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, "Mouse", UsbHidSubmenuIndexMouse, usb_hid_submenu_callback, app); - submenu_add_item( - app->submenu, - "Mouse Jiggler", - UsbHidSubmenuIndexMouseJiggler, - usb_hid_submenu_callback, - app); - view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewSubmenu, submenu_get_view(app->submenu)); - - // Dialog view - app->dialog = dialog_ex_alloc(); - dialog_ex_set_result_callback(app->dialog, usb_hid_dialog_callback); - dialog_ex_set_context(app->dialog, app); - dialog_ex_set_left_button_text(app->dialog, "Exit"); - dialog_ex_set_right_button_text(app->dialog, "Stay"); - dialog_ex_set_center_button_text(app->dialog, "Menu"); - dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewExitConfirm, dialog_ex_get_view(app->dialog)); - - // Dirpad view - app->usb_hid_dirpad = usb_hid_dirpad_alloc(); - view_set_previous_callback( - usb_hid_dirpad_get_view(app->usb_hid_dirpad), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewDirpad, usb_hid_dirpad_get_view(app->usb_hid_dirpad)); - - // Keyboard view - app->usb_hid_keyboard = usb_hid_keyboard_alloc(); - view_set_previous_callback( - usb_hid_keyboard_get_view(app->usb_hid_keyboard), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, - UsbHidViewKeyboard, - usb_hid_keyboard_get_view(app->usb_hid_keyboard)); - - // Media view - app->usb_hid_media = usb_hid_media_alloc(); - view_set_previous_callback( - usb_hid_media_get_view(app->usb_hid_media), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewMedia, usb_hid_media_get_view(app->usb_hid_media)); - - // Mouse view - app->usb_hid_mouse = usb_hid_mouse_alloc(); - view_set_previous_callback( - usb_hid_mouse_get_view(app->usb_hid_mouse), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, UsbHidViewMouse, usb_hid_mouse_get_view(app->usb_hid_mouse)); - - // Mouse jiggler view - app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); - view_set_previous_callback( - hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), usb_hid_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, - UsbHidViewMouseJiggler, - hid_mouse_jiggler_get_view(app->hid_mouse_jiggler)); - - // TODO switch to menu after Media is done - app->view_id = UsbHidViewSubmenu; - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); - - return app; -} - -void usb_hid_app_free(UsbHid* app) { - furi_assert(app); - - // Reset notification - notification_internal_message(app->notifications, &sequence_reset_blue); - - // Free views - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewSubmenu); - submenu_free(app->submenu); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewExitConfirm); - dialog_ex_free(app->dialog); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewDirpad); - usb_hid_dirpad_free(app->usb_hid_dirpad); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewKeyboard); - usb_hid_keyboard_free(app->usb_hid_keyboard); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMedia); - usb_hid_media_free(app->usb_hid_media); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouse); - usb_hid_mouse_free(app->usb_hid_mouse); - view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouseJiggler); - hid_mouse_jiggler_free(app->hid_mouse_jiggler); - view_dispatcher_free(app->view_dispatcher); - // Close records - furi_record_close(RECORD_GUI); - app->gui = NULL; - furi_record_close(RECORD_NOTIFICATION); - app->notifications = NULL; - - // Free rest - free(app); -} - -int32_t usb_hid_app(void* p) { - UNUSED(p); - // Switch profile to Hid - UsbHid* app = usb_hid_app_alloc(); - - FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); - furi_hal_usb_unlock(); - furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); - - view_dispatcher_run(app->view_dispatcher); - - // Change back profile - furi_hal_usb_set_config(usb_mode_prev, NULL); - usb_hid_app_free(app); - - return 0; -} diff --git a/applications/plugins/usbkeyboard/usb_hid.h b/applications/plugins/usbkeyboard/usb_hid.h deleted file mode 100644 index 77b70e59f2..0000000000 --- a/applications/plugins/usbkeyboard/usb_hid.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include "views/usb_hid_dirpad.h" -#include "views/usb_hid_keyboard.h" -#include "views/usb_hid_media.h" -#include "views/usb_hid_mouse.h" -#include "views/usb_hid_mouse_jiggler.h" - -typedef struct { - Gui* gui; - NotificationApp* notifications; - ViewDispatcher* view_dispatcher; - Submenu* submenu; - DialogEx* dialog; - UsbHidDirpad* usb_hid_dirpad; - UsbHidKeyboard* usb_hid_keyboard; - UsbHidMedia* usb_hid_media; - UsbHidMouse* usb_hid_mouse; - HidMouseJiggler* hid_mouse_jiggler; - uint32_t view_id; -} UsbHid; - -typedef enum { - UsbHidViewSubmenu, - UsbHidViewDirpad, - UsbHidViewKeyboard, - UsbHidViewMedia, - UsbHidViewMouse, - UsbHidViewMouseJiggler, - UsbHidViewExitConfirm, -} UsbHidView; diff --git a/applications/plugins/usbkeyboard/usb_keyboard_10px.png b/applications/plugins/usbkeyboard/usb_keyboard_10px.png deleted file mode 100644 index 7649138eb70ee33ccc98aba2252999969c7569a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4v7|ftIx;Y9?C1WI$O`0h7I;J! zGcf2WfiUB$M|URy1p_=?978mMd;1x=7!)~Jw*LRWb5?>aXRoxz$+XEed20^d^}YW1 z4X?+E4eQjmi&=L1+cVk^B@OehhySjf>x0qUfxcxlr SbuJ%hHiM_DpUXO@geCx&K0Pe} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c deleted file mode 100644 index d6aec9ef21..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "usb_hid_dirpad.h" -#include -#include -#include -#include - -struct UsbHidDirpad { - View* view; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool back_pressed; - bool connected; -} UsbHidDirpadModel; - -static void usb_hid_dirpad_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { - canvas_draw_triangle(canvas, x, y, 5, 3, dir); - if(dir == CanvasDirectionBottomToTop) { - canvas_draw_line(canvas, x, y + 6, x, y - 1); - } else if(dir == CanvasDirectionTopToBottom) { - canvas_draw_line(canvas, x, y - 6, x, y + 1); - } else if(dir == CanvasDirectionRightToLeft) { - canvas_draw_line(canvas, x + 6, y, x - 1, y); - } else if(dir == CanvasDirectionLeftToRight) { - canvas_draw_line(canvas, x - 6, y, x + 1, y); - } -} - -static void usb_hid_dirpad_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidDirpadModel* model = context; - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Dirpad"); - - canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit"); - - // Up - canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); - if(model->up_pressed) { - elements_slightly_rounded_box(canvas, 24, 26, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); - canvas_set_color(canvas, ColorBlack); - - // Down - canvas_draw_icon(canvas, 21, 45, &I_Button_18x18); - if(model->down_pressed) { - elements_slightly_rounded_box(canvas, 24, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); - canvas_set_color(canvas, ColorBlack); - - // Left - canvas_draw_icon(canvas, 0, 45, &I_Button_18x18); - if(model->left_pressed) { - elements_slightly_rounded_box(canvas, 3, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); - canvas_set_color(canvas, ColorBlack); - - // Right - canvas_draw_icon(canvas, 42, 45, &I_Button_18x18); - if(model->right_pressed) { - elements_slightly_rounded_box(canvas, 45, 47, 13, 13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_dirpad_draw_arrow(canvas, 53, 53, CanvasDirectionLeftToRight); - canvas_set_color(canvas, ColorBlack); - - // Ok - canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); - if(model->ok_pressed) { - elements_slightly_rounded_box(canvas, 66, 27, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space"); - canvas_set_color(canvas, ColorBlack); - - // Back - canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); - if(model->back_pressed) { - elements_slightly_rounded_box(canvas, 66, 47, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); -} - -static void usb_hid_dirpad_process(UsbHidDirpad* usb_hid_dirpad, InputEvent* event) { - with_view_model( - usb_hid_dirpad->view, - UsbHidDirpadModel * model, - { - if(event->type == InputTypePress) { - if(event->key == InputKeyUp) { - model->up_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - furi_hal_hid_kb_press(HID_KEYBOARD_SPACEBAR); - } else if(event->key == InputKeyBack) { - model->back_pressed = true; - } - } else if(event->type == InputTypeRelease) { - if(event->key == InputKeyUp) { - model->up_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_UP_ARROW); - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_DOWN_ARROW); - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_LEFT_ARROW); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - furi_hal_hid_kb_release(HID_KEYBOARD_SPACEBAR); - } else if(event->key == InputKeyBack) { - model->back_pressed = false; - } - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); - furi_hal_hid_consumer_key_press(HID_CONSUMER_AC_BACK); - furi_hal_hid_consumer_key_release(HID_CONSUMER_AC_BACK); - } - } - }, - true); -} - -static bool usb_hid_dirpad_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidDirpad* usb_hid_dirpad = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } else { - usb_hid_dirpad_process(usb_hid_dirpad, event); - consumed = true; - } - - return consumed; -} - -UsbHidDirpad* usb_hid_dirpad_alloc() { - UsbHidDirpad* usb_hid_dirpad = malloc(sizeof(UsbHidDirpad)); - usb_hid_dirpad->view = view_alloc(); - view_set_context(usb_hid_dirpad->view, usb_hid_dirpad); - view_allocate_model(usb_hid_dirpad->view, ViewModelTypeLocking, sizeof(UsbHidDirpadModel)); - view_set_draw_callback(usb_hid_dirpad->view, usb_hid_dirpad_draw_callback); - view_set_input_callback(usb_hid_dirpad->view, usb_hid_dirpad_input_callback); - - return usb_hid_dirpad; -} - -void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad) { - furi_assert(usb_hid_dirpad); - view_free(usb_hid_dirpad->view); - free(usb_hid_dirpad); -} - -View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad) { - furi_assert(usb_hid_dirpad); - return usb_hid_dirpad->view; -} - -void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected) { - furi_assert(usb_hid_dirpad); - with_view_model( - usb_hid_dirpad->view, UsbHidDirpadModel * model, { model->connected = connected; }, true); -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h deleted file mode 100644 index 305e051b40..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidDirpad UsbHidDirpad; - -UsbHidDirpad* usb_hid_dirpad_alloc(); - -void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad); - -View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad); - -void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c deleted file mode 100644 index 8ca4f366af..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c +++ /dev/null @@ -1,387 +0,0 @@ -#include "usb_hid_keyboard.h" -#include -#include -#include -#include -#include - -struct UsbHidKeyboard { - View* view; -}; - -typedef struct { - bool shift; - bool alt; - bool ctrl; - bool gui; - uint8_t x; - uint8_t y; - uint8_t last_key_code; - uint16_t modifier_code; - bool ok_pressed; - bool back_pressed; - bool connected; - char key_string[5]; -} UsbHidKeyboardModel; - -typedef struct { - uint8_t width; - char* key; - const Icon* icon; - char* shift_key; - uint8_t value; -} UsbHidKeyboardKey; - -typedef struct { - int8_t x; - int8_t y; -} UsbHidKeyboardPoint; - -// 4 BY 12 -#define MARGIN_TOP 0 -#define MARGIN_LEFT 4 -#define KEY_WIDTH 9 -#define KEY_HEIGHT 12 -#define KEY_PADDING 1 -#define ROW_COUNT 7 -#define COLUMN_COUNT 12 - -// 0 width items are not drawn, but there value is used -const UsbHidKeyboardKey usb_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { - { - {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, - {.width = 1, .icon = NULL, .key = "3", .shift_key = "#", .value = HID_KEYBOARD_3}, - {.width = 1, .icon = NULL, .key = "4", .shift_key = "$", .value = HID_KEYBOARD_4}, - {.width = 1, .icon = NULL, .key = "5", .shift_key = "%", .value = HID_KEYBOARD_5}, - {.width = 1, .icon = NULL, .key = "6", .shift_key = "^", .value = HID_KEYBOARD_6}, - {.width = 1, .icon = NULL, .key = "7", .shift_key = "&", .value = HID_KEYBOARD_7}, - {.width = 1, .icon = NULL, .key = "8", .shift_key = "*", .value = HID_KEYBOARD_8}, - {.width = 1, .icon = NULL, .key = "9", .shift_key = "(", .value = HID_KEYBOARD_9}, - {.width = 1, .icon = NULL, .key = "0", .shift_key = ")", .value = HID_KEYBOARD_0}, - {.width = 2, .icon = &I_Pin_arrow_left_9x7, .value = HID_KEYBOARD_DELETE}, - {.width = 0, .value = HID_KEYBOARD_DELETE}, - }, - { - {.width = 1, .icon = NULL, .key = "q", .shift_key = "Q", .value = HID_KEYBOARD_Q}, - {.width = 1, .icon = NULL, .key = "w", .shift_key = "W", .value = HID_KEYBOARD_W}, - {.width = 1, .icon = NULL, .key = "e", .shift_key = "E", .value = HID_KEYBOARD_E}, - {.width = 1, .icon = NULL, .key = "r", .shift_key = "R", .value = HID_KEYBOARD_R}, - {.width = 1, .icon = NULL, .key = "t", .shift_key = "T", .value = HID_KEYBOARD_T}, - {.width = 1, .icon = NULL, .key = "y", .shift_key = "Y", .value = HID_KEYBOARD_Y}, - {.width = 1, .icon = NULL, .key = "u", .shift_key = "U", .value = HID_KEYBOARD_U}, - {.width = 1, .icon = NULL, .key = "i", .shift_key = "I", .value = HID_KEYBOARD_I}, - {.width = 1, .icon = NULL, .key = "o", .shift_key = "O", .value = HID_KEYBOARD_O}, - {.width = 1, .icon = NULL, .key = "p", .shift_key = "P", .value = HID_KEYBOARD_P}, - {.width = 1, .icon = NULL, .key = "[", .shift_key = "{", .value = HID_KEYBOARD_OPEN_BRACKET}, - {.width = 1, - .icon = NULL, - .key = "]", - .shift_key = "}", - .value = HID_KEYBOARD_CLOSE_BRACKET}, - }, - { - {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_A}, - {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_S}, - {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_D}, - {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_F}, - {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_G}, - {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_H}, - {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_J}, - {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_K}, - {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_L}, - {.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON}, - {.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN}, - {.width = 0, .value = HID_KEYBOARD_RETURN}, - }, - { - {.width = 1, .icon = NULL, .key = "z", .shift_key = "Z", .value = HID_KEYBOARD_Z}, - {.width = 1, .icon = NULL, .key = "x", .shift_key = "X", .value = HID_KEYBOARD_X}, - {.width = 1, .icon = NULL, .key = "c", .shift_key = "C", .value = HID_KEYBOARD_C}, - {.width = 1, .icon = NULL, .key = "v", .shift_key = "V", .value = HID_KEYBOARD_V}, - {.width = 1, .icon = NULL, .key = "b", .shift_key = "B", .value = HID_KEYBOARD_B}, - {.width = 1, .icon = NULL, .key = "n", .shift_key = "N", .value = HID_KEYBOARD_N}, - {.width = 1, .icon = NULL, .key = "m", .shift_key = "M", .value = HID_KEYBOARD_M}, - {.width = 1, .icon = NULL, .key = "/", .shift_key = "?", .value = HID_KEYBOARD_SLASH}, - {.width = 1, .icon = NULL, .key = "\\", .shift_key = "|", .value = HID_KEYBOARD_BACKSLASH}, - {.width = 1, .icon = NULL, .key = "`", .shift_key = "~", .value = HID_KEYBOARD_GRAVE_ACCENT}, - {.width = 1, .icon = &I_ButtonUp_7x4, .value = HID_KEYBOARD_UP_ARROW}, - {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, - }, - { - {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, - {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, - {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, - {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, - {.width = 1, .icon = NULL, .key = "'", .shift_key = "\"", .value = HID_KEYBOARD_APOSTROPHE}, - {.width = 1, .icon = NULL, .key = "=", .shift_key = "+", .value = HID_KEYBOARD_EQUAL_SIGN}, - {.width = 1, .icon = &I_ButtonLeft_4x7, .value = HID_KEYBOARD_LEFT_ARROW}, - {.width = 1, .icon = &I_ButtonDown_7x4, .value = HID_KEYBOARD_DOWN_ARROW}, - {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, - }, - { - {.width = 2, .icon = NULL, .key = "Ctl", .value = HID_KEYBOARD_L_CTRL}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, - {.width = 2, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, - {.width = 2, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, - {.width = 2, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, - {.width = 2, .icon = NULL, .key = "Esc", .value = HID_KEYBOARD_ESCAPE}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_ESCAPE}, - {.width = 2, .icon = NULL, .key = "Del", .value = HID_KEYBOARD_DELETE_FORWARD}, - {.width = 0, .icon = NULL, .value = HID_KEYBOARD_DELETE_FORWARD}, - }, - { - {.width = 1, .icon = NULL, .key = "1", .shift_key = "1", .value = HID_KEYBOARD_F1}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "2", .value = HID_KEYBOARD_F2}, - {.width = 1, .icon = NULL, .key = "3", .shift_key = "3", .value = HID_KEYBOARD_F3}, - {.width = 1, .icon = NULL, .key = "4", .shift_key = "4", .value = HID_KEYBOARD_F4}, - {.width = 1, .icon = NULL, .key = "5", .shift_key = "5", .value = HID_KEYBOARD_F5}, - {.width = 1, .icon = NULL, .key = "6", .shift_key = "6", .value = HID_KEYBOARD_F6}, - {.width = 1, .icon = NULL, .key = "7", .shift_key = "7", .value = HID_KEYBOARD_F7}, - {.width = 1, .icon = NULL, .key = "8", .shift_key = "8", .value = HID_KEYBOARD_F8}, - {.width = 1, .icon = NULL, .key = "9", .shift_key = "9", .value = HID_KEYBOARD_F9}, - {.width = 1, .icon = NULL, .key = "0", .shift_key = "0", .value = HID_KEYBOARD_F10}, - {.width = 1, .icon = NULL, .key = "1", .shift_key = "1", .value = HID_KEYBOARD_F11}, - {.width = 1, .icon = NULL, .key = "2", .shift_key = "2", .value = HID_KEYBOARD_F12}, - }}; - -static void usb_hid_keyboard_to_upper(char* str) { - while(*str) { - *str = toupper((unsigned char)*str); - str++; - } -} - -static void usb_hid_keyboard_draw_key( - Canvas* canvas, - UsbHidKeyboardModel* model, - uint8_t x, - uint8_t y, - UsbHidKeyboardKey key, - bool selected) { - if(!key.width) return; - - canvas_set_color(canvas, ColorBlack); - uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); - if(selected) { - // Draw a filled box - elements_slightly_rounded_box( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), - keyWidth, - KEY_HEIGHT); - canvas_set_color(canvas, ColorWhite); - } else { - // Draw a framed box - elements_slightly_rounded_frame( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), - keyWidth, - KEY_HEIGHT); - } - if(key.icon != NULL) { - // Draw the icon centered on the button - canvas_draw_icon( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2 - key.icon->height / 2, - key.icon); - } else { - // If shift is toggled use the shift key when available - strcpy(model->key_string, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); - // Upper case if ctrl or alt was toggled true - if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || - (model->alt && key.value == HID_KEYBOARD_L_ALT) || - (model->gui && key.value == HID_KEYBOARD_L_GUI)) { - usb_hid_keyboard_to_upper(model->key_string); - } - canvas_draw_str_aligned( - canvas, - MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, - MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2, - AlignCenter, - AlignCenter, - model->key_string); - } -} - -static void usb_hid_keyboard_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidKeyboardModel* model = context; - - canvas_set_font(canvas, FontKeyboard); - // Start shifting the all keys up if on the next row (Scrolling) - uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; - for(uint8_t y = initY; y < ROW_COUNT; y++) { - const UsbHidKeyboardKey* keyboardKeyRow = usb_hid_keyboard_keyset[y]; - uint8_t x = 0; - for(uint8_t i = 0; i < COLUMN_COUNT; i++) { - UsbHidKeyboardKey key = keyboardKeyRow[i]; - // Select when the button is hovered - // Select if the button is hovered within its width - // Select if back is clicked and its the backspace key - // Deselect when the button clicked or not hovered - bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; - // Revert selection for function keys - keySelected = y == ROW_COUNT - 1 ? !keySelected : keySelected; - bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; - usb_hid_keyboard_draw_key( - canvas, - model, - x, - y - initY, - key, - (!model->ok_pressed && keySelected) || backSelected); - x += key.width; - } - } -} - -static uint8_t usb_hid_keyboard_get_selected_key(UsbHidKeyboardModel* model) { - UsbHidKeyboardKey key = usb_hid_keyboard_keyset[model->y][model->x]; - // Use upper case if shift is toggled - bool useUppercase = model->shift; - // Check if the key has an upper case version - bool hasUppercase = key.shift_key != 0; - if(useUppercase && hasUppercase) - return key.value; - else - return key.value; -} - -static void - usb_hid_keyboard_get_select_key(UsbHidKeyboardModel* model, UsbHidKeyboardPoint delta) { - // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map - do { - if(((int8_t)model->y) + delta.y < 0) - model->y = ROW_COUNT - 1; - else - model->y = (model->y + delta.y) % ROW_COUNT; - } while(delta.y != 0 && usb_hid_keyboard_keyset[model->y][model->x].value == 0); - - do { - if(((int8_t)model->x) + delta.x < 0) - model->x = COLUMN_COUNT - 1; - else - model->x = (model->x + delta.x) % COLUMN_COUNT; - } while(delta.x != 0 && usb_hid_keyboard_keyset[model->y][model->x].width == - 0); // Skip zero width keys, pretend they are one key -} - -static void usb_hid_keyboard_process(UsbHidKeyboard* usb_hid_keyboard, InputEvent* event) { - with_view_model( - usb_hid_keyboard->view, - UsbHidKeyboardModel * model, - { - if(event->key == InputKeyOk) { - if(event->type == InputTypePress) { - model->ok_pressed = true; - } else if(event->type == InputTypeLong || event->type == InputTypeShort) { - model->last_key_code = usb_hid_keyboard_get_selected_key(model); - - // Toggle the modifier key when clicked, and click the key - if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { - model->shift = !model->shift; - if(model->shift) - model->modifier_code |= KEY_MOD_LEFT_SHIFT; - else - model->modifier_code &= ~KEY_MOD_LEFT_SHIFT; - } else if(model->last_key_code == HID_KEYBOARD_L_ALT) { - model->alt = !model->alt; - if(model->alt) - model->modifier_code |= KEY_MOD_LEFT_ALT; - else - model->modifier_code &= ~KEY_MOD_LEFT_ALT; - } else if(model->last_key_code == HID_KEYBOARD_L_CTRL) { - model->ctrl = !model->ctrl; - if(model->ctrl) - model->modifier_code |= KEY_MOD_LEFT_CTRL; - else - model->modifier_code &= ~KEY_MOD_LEFT_CTRL; - } else if(model->last_key_code == HID_KEYBOARD_L_GUI) { - model->gui = !model->gui; - if(model->gui) - model->modifier_code |= KEY_MOD_LEFT_GUI; - else - model->modifier_code &= ~KEY_MOD_LEFT_GUI; - } - furi_hal_hid_kb_press(model->modifier_code | model->last_key_code); - } else if(event->type == InputTypeRelease) { - // Release happens after short and long presses - furi_hal_hid_kb_release(model->modifier_code | model->last_key_code); - model->ok_pressed = false; - } - } else if(event->key == InputKeyBack) { - // If back is pressed for a short time, backspace - if(event->type == InputTypePress) { - model->back_pressed = true; - } else if(event->type == InputTypeShort) { - furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); - furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); - } else if(event->type == InputTypeRelease) { - model->back_pressed = false; - } - } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { - // Cycle the selected keys - if(event->key == InputKeyUp) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = -1}); - } else if(event->key == InputKeyDown) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = 1}); - } else if(event->key == InputKeyLeft) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = -1, .y = 0}); - } else if(event->key == InputKeyRight) { - usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 1, .y = 0}); - } - } - }, - true); -} - -static bool usb_hid_keyboard_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidKeyboard* usb_hid_keyboard = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } else { - usb_hid_keyboard_process(usb_hid_keyboard, event); - consumed = true; - } - - return consumed; -} - -UsbHidKeyboard* usb_hid_keyboard_alloc() { - UsbHidKeyboard* usb_hid_keyboard = malloc(sizeof(UsbHidKeyboard)); - - usb_hid_keyboard->view = view_alloc(); - view_set_context(usb_hid_keyboard->view, usb_hid_keyboard); - view_allocate_model(usb_hid_keyboard->view, ViewModelTypeLocking, sizeof(UsbHidKeyboardModel)); - view_set_draw_callback(usb_hid_keyboard->view, usb_hid_keyboard_draw_callback); - view_set_input_callback(usb_hid_keyboard->view, usb_hid_keyboard_input_callback); - - with_view_model( - usb_hid_keyboard->view, UsbHidKeyboardModel * model, { model->connected = true; }, true); - - return usb_hid_keyboard; -} - -void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard) { - furi_assert(usb_hid_keyboard); - view_free(usb_hid_keyboard->view); - free(usb_hid_keyboard); -} - -View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard) { - furi_assert(usb_hid_keyboard); - return usb_hid_keyboard->view; -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h deleted file mode 100644 index 4dee5fbeed..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidKeyboard UsbHidKeyboard; - -UsbHidKeyboard* usb_hid_keyboard_alloc(); - -void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard); - -View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard); - -void usb_hid_keyboard_set_connected_status(UsbHidKeyboard* usb_hid_keyboard, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.c b/applications/plugins/usbkeyboard/views/usb_hid_media.c deleted file mode 100644 index 8d2188434b..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_media.c +++ /dev/null @@ -1,201 +0,0 @@ -#include "usb_hid_media.h" -#include -#include -#include -#include - -struct UsbHidMedia { - View* view; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool connected; -} UsbHidMediaModel; - -static void usb_hid_media_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { - canvas_draw_triangle(canvas, x, y, 5, 3, dir); - if(dir == CanvasDirectionBottomToTop) { - canvas_draw_dot(canvas, x, y - 1); - } else if(dir == CanvasDirectionTopToBottom) { - canvas_draw_dot(canvas, x, y + 1); - } else if(dir == CanvasDirectionRightToLeft) { - canvas_draw_dot(canvas, x - 1, y); - } else if(dir == CanvasDirectionLeftToRight) { - canvas_draw_dot(canvas, x + 1, y); - } -} - -static void usb_hid_media_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidMediaModel* model = context; - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); - canvas_set_font(canvas, FontSecondary); - - // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); - usb_hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); - usb_hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->ok_pressed) { - canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); - canvas_set_color(canvas, ColorWhite); - } - usb_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); - canvas_draw_line(canvas, 100, 29, 100, 33); - canvas_draw_line(canvas, 102, 29, 102, 33); - canvas_set_color(canvas, ColorBlack); - - // Exit - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); -} - -static void usb_hid_media_process_press(UsbHidMedia* usb_hid_media, InputEvent* event) { - with_view_model( - usb_hid_media->view, - UsbHidMediaModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - furi_hal_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); - } - }, - true); -} - -static void hid_media_process_release(UsbHidMedia* usb_hid_media, InputEvent* event) { - with_view_model( - usb_hid_media->view, - UsbHidMediaModel * model, - { - if(event->key == InputKeyUp) { - model->up_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - furi_hal_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); - } - }, - true); -} - -static bool usb_hid_media_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidMedia* usb_hid_media = context; - bool consumed = false; - - if(event->type == InputTypePress) { - usb_hid_media_process_press(usb_hid_media, event); - consumed = true; - } else if(event->type == InputTypeRelease) { - hid_media_process_release(usb_hid_media, event); - consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - furi_hal_hid_kb_release_all(); - } - } - - return consumed; -} - -UsbHidMedia* usb_hid_media_alloc() { - UsbHidMedia* usb_hid_media = malloc(sizeof(UsbHidMedia)); - usb_hid_media->view = view_alloc(); - view_set_context(usb_hid_media->view, usb_hid_media); - view_allocate_model(usb_hid_media->view, ViewModelTypeLocking, sizeof(UsbHidMediaModel)); - view_set_draw_callback(usb_hid_media->view, usb_hid_media_draw_callback); - view_set_input_callback(usb_hid_media->view, usb_hid_media_input_callback); - - with_view_model( - usb_hid_media->view, UsbHidMediaModel * model, { model->connected = true; }, true); - - return usb_hid_media; -} - -void usb_hid_media_free(UsbHidMedia* usb_hid_media) { - furi_assert(usb_hid_media); - view_free(usb_hid_media->view); - free(usb_hid_media); -} - -View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media) { - furi_assert(usb_hid_media); - return usb_hid_media->view; -} - -void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected) { - furi_assert(usb_hid_media); - with_view_model( - usb_hid_media->view, UsbHidMediaModel * model, { model->connected = connected; }, true); -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.h b/applications/plugins/usbkeyboard/views/usb_hid_media.h deleted file mode 100644 index 441e2bd6d5..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_media.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidMedia UsbHidMedia; - -UsbHidMedia* usb_hid_media_alloc(); - -void usb_hid_media_free(UsbHidMedia* usb_hid_media); - -View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media); - -void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.c b/applications/plugins/usbkeyboard/views/usb_hid_mouse.c deleted file mode 100644 index 27f2ac1056..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "usb_hid_mouse.h" -#include -#include -#include -#include - -struct UsbHidMouse { - View* view; -}; -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool left_mouse_pressed; - bool left_mouse_held; - bool right_mouse_pressed; - bool connected; -} UsbHidMouseModel; - -static void usb_hid_mouse_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - UsbHidMouseModel* model = context; - - // Header - /*if(model->connected) { - canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); - } else { - canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); - }*/ - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse"); - canvas_set_font(canvas, FontSecondary); - - if(model->left_mouse_held == true) { - elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting..."); - } else { - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); - } - - // Keypad circles - canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->left_mouse_pressed) { - canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); - } - - // Back - if(model->right_mouse_pressed) { - canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); - } -} - -static void usb_hid_mouse_process(UsbHidMouse* usb_hid_mouse, InputEvent* event) { - with_view_model( - usb_hid_mouse->view, - UsbHidMouseModel * model, - { - if(event->key == InputKeyBack) { - if(event->type == InputTypeShort) { - furi_hal_hid_mouse_press(HID_MOUSE_BTN_RIGHT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); - } else if(event->type == InputTypePress) { - model->right_mouse_pressed = true; - } else if(event->type == InputTypeRelease) { - model->right_mouse_pressed = false; - } - } else if(event->key == InputKeyOk) { - if(event->type == InputTypeShort) { - // Just release if it was being held before - if(!model->left_mouse_held) furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); - model->left_mouse_held = false; - } else if(event->type == InputTypeLong) { - furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); - model->left_mouse_held = true; - model->left_mouse_pressed = true; - } else if(event->type == InputTypePress) { - model->left_mouse_pressed = true; - } else if(event->type == InputTypeRelease) { - // Only release if it wasn't a long press - if(!model->left_mouse_held) model->left_mouse_pressed = false; - } - - } else if(event->key == InputKeyRight) { - if(event->type == InputTypePress) { - model->right_pressed = true; - furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(MOUSE_MOVE_LONG, 0); - } else if(event->type == InputTypeRelease) { - model->right_pressed = false; - } - } else if(event->key == InputKeyLeft) { - if(event->type == InputTypePress) { - model->left_pressed = true; - furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(-MOUSE_MOVE_LONG, 0); - } else if(event->type == InputTypeRelease) { - model->left_pressed = false; - } - } else if(event->key == InputKeyDown) { - if(event->type == InputTypePress) { - model->down_pressed = true; - furi_hal_hid_mouse_move(0, MOUSE_MOVE_SHORT); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(0, MOUSE_MOVE_LONG); - } else if(event->type == InputTypeRelease) { - model->down_pressed = false; - } - } else if(event->key == InputKeyUp) { - if(event->type == InputTypePress) { - model->up_pressed = true; - furi_hal_hid_mouse_move(0, -MOUSE_MOVE_SHORT); - } else if(event->type == InputTypeRepeat) { - furi_hal_hid_mouse_move(0, -MOUSE_MOVE_LONG); - } else if(event->type == InputTypeRelease) { - model->up_pressed = false; - } - } - }, - true); -} - -static bool usb_hid_mouse_input_callback(InputEvent* event, void* context) { - furi_assert(context); - UsbHidMouse* usb_hid_mouse = context; - bool consumed = false; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); - furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); - } else { - usb_hid_mouse_process(usb_hid_mouse, event); - consumed = true; - } - - return consumed; -} - -UsbHidMouse* usb_hid_mouse_alloc() { - UsbHidMouse* usb_hid_mouse = malloc(sizeof(UsbHidMouse)); - usb_hid_mouse->view = view_alloc(); - view_set_context(usb_hid_mouse->view, usb_hid_mouse); - view_allocate_model(usb_hid_mouse->view, ViewModelTypeLocking, sizeof(UsbHidMouseModel)); - view_set_draw_callback(usb_hid_mouse->view, usb_hid_mouse_draw_callback); - view_set_input_callback(usb_hid_mouse->view, usb_hid_mouse_input_callback); - - with_view_model( - usb_hid_mouse->view, UsbHidMouseModel * model, { model->connected = true; }, true); - - return usb_hid_mouse; -} - -void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse) { - furi_assert(usb_hid_mouse); - view_free(usb_hid_mouse->view); - free(usb_hid_mouse); -} - -View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse) { - furi_assert(usb_hid_mouse); - return usb_hid_mouse->view; -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.h b/applications/plugins/usbkeyboard/views/usb_hid_mouse.h deleted file mode 100644 index e7eec92244..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -typedef struct UsbHidMouse UsbHidMouse; - -UsbHidMouse* usb_hid_mouse_alloc(); - -void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse); - -View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse); - -void usb_hid_mouse_set_connected_status(UsbHidMouse* usb_hid_mouse, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c b/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c deleted file mode 100644 index e042a0247f..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.c +++ /dev/null @@ -1,156 +0,0 @@ -#include "usb_hid_mouse_jiggler.h" -#include -#include -#include - -#include - -#define TAG "HidMouseJiggler" - -#define LENGTH(x) (int)(sizeof(x) / sizeof((x)[0])) - -struct HidMouseJiggler { - View* view; - FuriTimer* timer; -}; - -typedef struct { - bool running; - int interval_idx; - uint8_t counter; -} HidMouseJigglerModel; - -const int intervals[6] = {500, 2000, 5000, 10000, 30000, 60000}; - -static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - HidMouseJigglerModel* model = context; - - // Header - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 2, AlignLeft, AlignTop, "Mouse Jiggler"); - - // Timeout - elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); - canvas_set_font(canvas, FontSecondary); - if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); - if(model->interval_idx != LENGTH(intervals) - 1) - canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); - FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); - elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); - furi_string_free(interval_str); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text(canvas, AlignLeft, 40, "Press Start\nto jiggle"); - canvas_set_font(canvas, FontSecondary); - - // Ok - canvas_draw_icon(canvas, 63, 30, &I_Space_65x18); - if(model->running) { - elements_slightly_rounded_box(canvas, 66, 32, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 74, 34, &I_Ok_btn_9x9); - if(model->running) { - elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Stop"); - } else { - elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Start"); - } - canvas_set_color(canvas, ColorBlack); - - // Back - canvas_draw_icon(canvas, 74, 54, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 62, AlignLeft, AlignBottom, "Quit"); -} - -static void hid_mouse_jiggler_timer_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { - if(model->running) { - model->counter++; - furi_hal_hid_mouse_move( - (model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT, 0); - } - }, - false); -} - -static void hid_mouse_jiggler_exit_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - furi_timer_stop(hid_mouse_jiggler->timer); -} - -static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - - bool consumed = false; - - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { - if(event->type == InputTypePress && event->key == InputKeyOk) { - model->running = !model->running; - if(model->running) { - furi_timer_stop(hid_mouse_jiggler->timer); - furi_timer_start(hid_mouse_jiggler->timer, intervals[model->interval_idx]); - }; - consumed = true; - } - if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && - model->interval_idx < LENGTH(intervals) - 1) { - model->interval_idx++; - consumed = true; - } - if(event->type == InputTypePress && event->key == InputKeyLeft && !model->running && - model->interval_idx > 0) { - model->interval_idx--; - consumed = true; - } - }, - true); - - return consumed; -} - -HidMouseJiggler* hid_mouse_jiggler_alloc() { - HidMouseJiggler* hid_mouse_jiggler = malloc(sizeof(HidMouseJiggler)); - - hid_mouse_jiggler->view = view_alloc(); - view_set_context(hid_mouse_jiggler->view, hid_mouse_jiggler); - view_allocate_model( - hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel)); - view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback); - view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback); - view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback); - - hid_mouse_jiggler->timer = furi_timer_alloc( - hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler); - - with_view_model( - hid_mouse_jiggler->view, HidMouseJigglerModel * model, { model->interval_idx = 2; }, true); - - return hid_mouse_jiggler; -} - -void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler) { - furi_assert(hid_mouse_jiggler); - - furi_timer_stop(hid_mouse_jiggler->timer); - furi_timer_free(hid_mouse_jiggler->timer); - - view_free(hid_mouse_jiggler->view); - - free(hid_mouse_jiggler); -} - -View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler) { - furi_assert(hid_mouse_jiggler); - return hid_mouse_jiggler->view; -} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h b/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h deleted file mode 100644 index 24cf877a72..0000000000 --- a/applications/plugins/usbkeyboard/views/usb_hid_mouse_jiggler.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 - -typedef struct HidMouseJiggler HidMouseJiggler; - -HidMouseJiggler* hid_mouse_jiggler_alloc(); - -void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler); - -View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler); From 1e983612997af682e935ebad3bf0a7e9eb5820dc Mon Sep 17 00:00:00 2001 From: Ari Bytyqi <101530102+Z3BRO@users.noreply.github.com> Date: Fri, 17 Feb 2023 02:17:57 -0600 Subject: [PATCH 16/41] Fixed first start animation typo (#2384) * fixed first start animation typo * updated pixels. (bottom left corner was off by two pixels) Co-authored-by: jbohack --- assets/slideshow/first_start/frame_02.png | Bin 562 -> 656 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/slideshow/first_start/frame_02.png b/assets/slideshow/first_start/frame_02.png index dc1080abaab43b40f9214c53e444839f9f3c9ffb..adff6af6672bc6f13ad0be1c0f7d19db4955f589 100644 GIT binary patch delta 643 zcmV-}0(||l1ds)g7=H)@0002x2#-ww0004VQb$4nuFf3k00006P)t-s|Ns900033O z(|!N|0v<_3K~!jg?Usvjgdhw>$^ZX!J1dVoZW2)3PG`upu7Yw8m|Q94#EBCpPMkRL zUxPM8HfpH9WfE3Bx_$wG#06fF2*6vzLUVv@bXUo3_W+915q}RJtu^i%0G}Cu{yD(a zRwp*joUy}v!<}7?F1h+w6Ng%xIJiS6xc~`VfZ8jxue5LhxB!hol-Lsh@c;mbrSKA{ z96$gn2V4MN3sC5u_w+6loi|c zh+yjh?R@sAKbpSdNL~|U0K;)Qz`_c6*1rHCx0^Hi+SzXacsa0I1@?BEMa~L53h`|> z9oqcmT{{87?DtwXI^m@LYXGzQCJDC01Ar|Azr*|h{u~6R)=RWQ0000EWmrjOO-%qQ d00008000000002eQcz2XilNogTwuu7~B5w5vn;e3F20e`W(DTKpH#XNu(EBFSM zQ(E~93pSQ1E!4gLH#-~GJi|?z>@VMb^XHoh{x4aotd<4hvLLj=4+hxc2hagBpg=5O z(fjT}Swz-D!g9hg*%AI8B|kPF2<_@ceLDKQpRe<4mreQ}lKuRN&{qkP8nnrfGC@~* zjM(FzkTJohH-Dd_mBMBc4INbjdvHs%qefDOLb3>%K#C;Y319~SjEBBL34L()FxmKB zFf_)kh}%x{_37>IIU$;L72za*3NR?r_(dvo4bF9*p?}@oPc}Sk1HBn{v3`yO<@gq~ zLJgeIAJ-f*hr!cmKnm3mlR8S()jG$HFIhfWY-x>MNGyj{1sW)uR=FJ*r(a)QP}+KndE%yd>|C%9KqbsgZ!@ n!-X*daUS@46g7nZOX>arU#^{;{__u)00000NkvXXu0mjfq&fEl From 32b74b968e8bb5730d95d0b3fd18b9cf90dca5b6 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 17 Feb 2023 12:16:53 +0300 Subject: [PATCH 17/41] Fix openssl cert path in fbtenv (#2408) * Temp fix openssl cert path * Moving fix from CI to fbtenv --- scripts/toolchain/fbtenv.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index bedb3450a0..2d4d172449 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -289,6 +289,9 @@ fbtenv_main() fbtenv_check_download_toolchain || return 1; fbtenv_set_shell_prompt; fbtenv_print_version; + if [ "$SYS_TYPE" = "Linux" ]; then + SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + fi PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; From 487d03eca4093d6e699c07f192531dd8689b0bf7 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 17 Feb 2023 12:59:08 +0300 Subject: [PATCH 18/41] Fix openssl path again (#2409) * Temp fix openssl cert path * Moving fix from CI to fbtenv * Fix openssl again --- scripts/toolchain/fbtenv.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 2d4d172449..8933bc48d1 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -290,7 +290,7 @@ fbtenv_main() fbtenv_set_shell_prompt; fbtenv_print_version; if [ "$SYS_TYPE" = "Linux" ]; then - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt fi PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; From 009c9b1b71bd8e7bd68f5ad9b955ff924dd5a913 Mon Sep 17 00:00:00 2001 From: Mathie <62908057+MathieDev@users.noreply.github.com> Date: Fri, 17 Feb 2023 06:43:06 -0500 Subject: [PATCH 19/41] Update nfc_cli.c (#2402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified the f to a capital F, looks cleaner. Co-authored-by: あく --- applications/main/nfc/nfc_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index a6475ca681..23335e2993 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -32,7 +32,7 @@ static void nfc_cli_detect(Cli* cli, FuriString* args) { while(!cmd_exit) { cmd_exit |= cli_cmd_interrupt_received(cli); if(furi_hal_nfc_detect(&dev_data, 400)) { - printf("found: %s ", nfc_get_dev_type(dev_data.type)); + printf("Found: %s ", nfc_get_dev_type(dev_data.type)); printf("UID length: %d, UID:", dev_data.uid_len); for(size_t i = 0; i < dev_data.uid_len; i++) { printf("%02X", dev_data.uid[i]); From 335f8b9aff670b033072e78ca477d4057ae54284 Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 17 Feb 2023 16:22:08 +0400 Subject: [PATCH 20/41] fbt: FBT_QUIET option; docs on environment (#2403) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: added FBT_QUIET to suppress toolchain version output; docs: added info on fbt environment * docs: typo fixes * fbt: fix for FBT_QUIET handling on *nix * Add FBT_VERBOSE flag * Add export * Fix export * docs: updates for FBT_VERBOSE Co-authored-by: DrunkBatya Co-authored-by: あく --- .vscode/example/launch.json | 5 +++-- documentation/fbt.md | 28 ++++++++++++++++++++++------ fbt | 11 ++++++++--- fbt.cmd | 7 ++++++- scripts/toolchain/fbtenv.cmd | 5 ++++- scripts/toolchain/fbtenv.sh | 28 ++++++++++++++++------------ 6 files changed, 59 insertions(+), 25 deletions(-) diff --git a/.vscode/example/launch.json b/.vscode/example/launch.json index 5c46d39791..f7a9f8269d 100644 --- a/.vscode/example/launch.json +++ b/.vscode/example/launch.json @@ -11,9 +11,10 @@ "args": { "useSingleResult": true, "env": { - "PATH": "${workspaceFolder};${env:PATH}" + "PATH": "${workspaceFolder};${env:PATH}", + "FBT_QUIET": 1 }, - "command": "./fbt get_blackmagic", + "command": "fbt get_blackmagic", "description": "Get Blackmagic device", } } diff --git a/documentation/fbt.md b/documentation/fbt.md index 5166d0ab71..65c3ee6825 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -3,17 +3,27 @@ FBT is the entry point for firmware-related commands and utilities. It is invoked by `./fbt` in the firmware project root directory. Internally, it is a wrapper around [scons](https://scons.org/) build system. -## Requirements +## Environment -Install Python packages required by assets build scripts: `pip3 install -r scripts/requirements.txt` +To use `fbt`, you only need `git` installed in your system. -## NB +`fbt` by default downloads and unpacks a pre-built toolchain, and then modifies environment variables for itself to use it. It does not contaminate your global system's path with the toolchain. + > However, if you wish to use tools supplied with the toolchain outside `fbt`, you can open an *fbt shell*, with properly configured environment. + > - On Windows, simply run `scripts/toochain/fbtenv.cmd`. + > - On Linux & MacOS, run `source scripts/toochain/fbtenv.sh` in a new shell. + + If your system is not supported by pre-built toolchain variants or you want to use custom versions of dependencies, you can `set FBT_NOENV=1`. `fbt` will skip toolchain & environment configuration and will expect all tools to be available on your system's `PATH`. *(this option is not available on Windows)* + + If `FBT_TOOLCHAIN_PATH` variable is set, `fbt` will use that directory to unpack toolchain into. By default, it downloads toolchain into `toolchain` subdirectory repo's root. -- `fbt` constructs all referenced environments and their targets' dependency trees on startup. So, to keep startup time as low as possible, we're hiding the construction of certain targets behind command-line options. -- `fbt` always performs `git submodule update --init` on start, unless you set `FBT_NO_SYNC=1` in the environment: +If you want to enable extra debug output for `fbt` and toolchain management scripts, you can `set FBT_VERBOSE=1`. + +`fbt` always performs `git submodule update --init` on start, unless you set `FBT_NO_SYNC=1` in the environment: - On Windows, it's `set "FBT_NO_SYNC=1"` in the shell you're running `fbt` from - On \*nix, it's `$ FBT_NO_SYNC=1 ./fbt ...` -- `fbt` builds updater & firmware in separate subdirectories in `build`, and their names depend on optimization settings (`COMPACT` & `DEBUG` options). However, for ease of integration with IDEs, the latest built variant's directory is always linked as `built/latest`. Additionally, `compile_commands.json` is generated in that folder (used for code completion support in IDE). + + > There are more variables controlling basic `fbt` behavior. See `fbt` & `fbtenv` scripts' sources for details. + ## Invoking FBT @@ -23,6 +33,12 @@ To build with FBT, call it and specify configuration options & targets to build. To run cleanup (think of `make clean`) for specified targets, add the `-c` option. +## Build directories + +`fbt` builds updater & firmware in separate subdirectories in `build`, and their names depend on optimization settings (`COMPACT` & `DEBUG` options). However, for ease of integration with IDEs, the latest built variant's directory is always linked as `built/latest`. Additionally, `compile_commands.json` is generated in that folder (it is used for code completion support in IDEs). + +`build/latest` symlink & compilation database are only updated upon *firmware build targets* - that is, when you're re-building the firmware itself. Running other tasks, like firmware flashing or building update bundles *for a different debug/release configuration or hardware target*, does not update `built/latest` dir to point to that configuration. + ## VSCode integration `fbt` includes basic development environment configuration for VS Code. Run `./fbt vscode_dist` to deploy it. That will copy the initial environment configuration to the `.vscode` folder. After that, you can use that configuration by starting VS Code and choosing the firmware root folder in the "File > Open Folder" menu. diff --git a/fbt b/fbt index e576f37acf..f80e802b62 100755 --- a/fbt +++ b/fbt @@ -6,16 +6,21 @@ set -eu; # private variables SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd -P)"; -SCONS_DEFAULT_FLAGS="-Q --warn=target-not-built"; -SCONS_EP="python3 -m SCons" +SCONS_DEFAULT_FLAGS="--warn=target-not-built"; +SCONS_EP="python3 -m SCons"; # public variables FBT_NOENV="${FBT_NOENV:-""}"; FBT_NO_SYNC="${FBT_NO_SYNC:-""}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; +FBT_VERBOSE="${FBT_VERBOSE:-""}"; if [ -z "$FBT_NOENV" ]; then - . "$SCRIPT_PATH/scripts/toolchain/fbtenv.sh"; + FBT_VERBOSE="$FBT_VERBOSE" . "$SCRIPT_PATH/scripts/toolchain/fbtenv.sh"; +fi + +if [ -z "$FBT_VERBOSE" ]; then + SCONS_DEFAULT_FLAGS="$SCONS_DEFAULT_FLAGS -Q"; fi if [ -z "$FBT_NO_SYNC" ]; then diff --git a/fbt.cmd b/fbt.cmd index 197f2359c7..92c734860a 100644 --- a/fbt.cmd +++ b/fbt.cmd @@ -12,5 +12,10 @@ if [%FBT_NO_SYNC%] == [] ( ) ) -set "SCONS_DEFAULT_FLAGS=-Q --warn=target-not-built" +set "SCONS_DEFAULT_FLAGS=--warn=target-not-built" + +if not defined FBT_VERBOSE ( + set "SCONS_DEFAULT_FLAGS=%SCONS_DEFAULT_FLAGS% -Q" +) + %SCONS_EP% %SCONS_DEFAULT_FLAGS% %* diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 5dff4b25e6..3f69de00b0 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -36,7 +36,10 @@ if not "%REAL_TOOLCHAIN_VERSION%" == "%FLIPPER_TOOLCHAIN_VERSION%" ( set /p REAL_TOOLCHAIN_VERSION=<"%FBT_TOOLCHAIN_VERSION_FILE%" ) -echo FBT: using toolchain version %REAL_TOOLCHAIN_VERSION% +if defined FBT_VERBOSE ( + echo FBT: using toolchain version %REAL_TOOLCHAIN_VERSION% +) + set "HOME=%USERPROFILE%" set "PYTHONHOME=%FBT_TOOLCHAIN_ROOT%\python" set "PYTHONPATH=" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index 8933bc48d1..ddd27c3707 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -7,13 +7,14 @@ DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"20"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; +FBT_VERBOSE="${FBT_VERBOSE:-""}"; fbtenv_show_usage() { echo "Running this script manually is wrong, please source it"; echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh\n"; - echo "To restore your environment source fbtenv.sh with '--restore'." + echo "To restore your environment, source fbtenv.sh with '--restore'." echo "Example:"; printf "\tsource scripts/toolchain/fbtenv.sh --restore\n"; } @@ -42,9 +43,9 @@ fbtenv_restore_env() PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')"; fi - PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; - PYTHONPATH="$SAVED_PYTHONPATH"; - PYTHONHOME="$SAVED_PYTHONHOME"; + export PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; + export PYTHONPATH="$SAVED_PYTHONPATH"; + export PYTHONHOME="$SAVED_PYTHONHOME"; unset SAVED_PYTHONNOUSERSITE; unset SAVED_PYTHONPATH; @@ -122,7 +123,7 @@ fbtenv_get_kernel_type() TOOLCHAIN_ARCH_DIR="$FBT_TOOLCHAIN_PATH/toolchain/x86_64-linux"; TOOLCHAIN_URL="https://update.flipperzero.one/builds/toolchain/gcc-arm-none-eabi-10.3-x86_64-linux-flipper-$FBT_TOOLCHAIN_VERSION.tar.gz"; elif echo "$SYS_TYPE" | grep -q "MINGW"; then - echo "In MinGW shell use \"[u]fbt.cmd\" instead of \"[u]fbt\""; + echo "In MinGW shell, use \"[u]fbt.cmd\" instead of \"[u]fbt\""; return 1; else echo "Your system configuration is not supported. Sorry.. Please report us your configuration."; @@ -273,7 +274,9 @@ fbtenv_download_toolchain() fbtenv_print_version() { - echo "FBT: using toolchain version $(cat "$TOOLCHAIN_ARCH_DIR/VERSION")"; + if [ -n "$FBT_VERBOSE" ]; then + echo "FBT: using toolchain version $(cat "$TOOLCHAIN_ARCH_DIR/VERSION")"; + fi } fbtenv_main() @@ -297,14 +300,15 @@ fbtenv_main() PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openocd/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/openssl/bin:$PATH"; + export PATH; - SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; - SAVED_PYTHONPATH="${PYTHONPATH:-""}"; - SAVED_PYTHONHOME="${PYTHONHOME:-""}"; + export SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; + export SAVED_PYTHONPATH="${PYTHONPATH:-""}"; + export SAVED_PYTHONHOME="${PYTHONHOME:-""}"; - PYTHONNOUSERSITE=1; - PYTHONPATH=; - PYTHONHOME=; + export PYTHONNOUSERSITE=1; + export PYTHONPATH=; + export PYTHONHOME=; } fbtenv_main "${1:-""}"; From c7fbc8323b93337c94dc1e69a3ce755224e2621c Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Fri, 17 Feb 2023 19:06:48 +0300 Subject: [PATCH 21/41] Toolchain 20 rollback (#2410) * Toolchain rollback * Remove extra code --- scripts/toolchain/fbtenv.cmd | 2 +- scripts/toolchain/fbtenv.sh | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index 3f69de00b0..dce5f37c4d 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=20" +set "FLIPPER_TOOLCHAIN_VERSION=19" if ["%FBT_TOOLCHAIN_ROOT%"] == [""] ( set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index ddd27c3707..c68673b7be 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"20"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"19"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; FBT_VERBOSE="${FBT_VERBOSE:-""}"; @@ -292,9 +292,6 @@ fbtenv_main() fbtenv_check_download_toolchain || return 1; fbtenv_set_shell_prompt; fbtenv_print_version; - if [ "$SYS_TYPE" = "Linux" ]; then - export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt - fi PATH="$TOOLCHAIN_ARCH_DIR/python/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/bin:$PATH"; PATH="$TOOLCHAIN_ARCH_DIR/protobuf/bin:$PATH"; From 78afaab7e8b7beea2b3789c175d613bd0089ce4d Mon Sep 17 00:00:00 2001 From: ComputerCarsten <50232606+ComputerCarsten@users.noreply.github.com> Date: Mon, 20 Feb 2023 10:24:51 +0100 Subject: [PATCH 22/41] IR Universal Audio Remote: Add Grundig CMS 5000 (#2414) Add Grundig CMS 5000 to Infrared Universal Audio Remote. The 'Play' button doubles as 'Pause' button. The 'Pause' button is unused. Issue: 'Prev' button rewinds to start of title, to skip to previous title two consecutive button presses in a short time are required, however the timing is not satisfied. --- assets/resources/infrared/assets/audio.ir | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index bcf035df13..825d1bc3ef 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -285,3 +285,46 @@ type: parsed protocol: NECext address: 10 E7 00 00 command: 41 BE 00 00 +# +# Model: Grundig CMS 5000 +name: Power +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 10 EF 00 00 +# Also Pause +name: Play +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 02 FD 00 00 +# +name: Vol_up +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0D F2 00 00 +# +name: Vol_dn +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 17 E8 00 00 +# +name: Next +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 13 EC 00 00 +# +name: Prev +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 11 EE 00 00 +# +name: Mute +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0C F3 00 00 From 3de6ae07b7bfdc6d75f82d4c688eac00db313318 Mon Sep 17 00:00:00 2001 From: Max Andreev Date: Mon, 20 Feb 2023 15:21:29 +0300 Subject: [PATCH 23/41] [FL-2974] Up toolchain version to 21 (#2416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- scripts/toolchain/fbtenv.cmd | 2 +- scripts/toolchain/fbtenv.sh | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index dce5f37c4d..8587f6d0e0 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=19" +set "FLIPPER_TOOLCHAIN_VERSION=21" if ["%FBT_TOOLCHAIN_ROOT%"] == [""] ( set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index c68673b7be..8f05c23ca8 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"19"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"21"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; FBT_VERBOSE="${FBT_VERBOSE:-""}"; @@ -43,10 +43,19 @@ fbtenv_restore_env() PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')"; fi + if [ -n "$SAVED_SSL_CERT_FILE" ]; then + export SSL_CERT_FILE="$SAVED_SSL_CERT_FILE"; + export REQUESTS_CA_BUNDLE="$SAVED_REQUESTS_CA_BUNDLE"; + else + unset SSL_CERT_FILE; + unset REQUESTS_CA_BUNDLE; + fi export PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; export PYTHONPATH="$SAVED_PYTHONPATH"; export PYTHONHOME="$SAVED_PYTHONHOME"; + unset SAVED_SSL_CERT_FILE; + unset SAVED_REQUESTS_CA_BUNDLE; unset SAVED_PYTHONNOUSERSITE; unset SAVED_PYTHONPATH; unset SAVED_PYTHONHOME; @@ -299,10 +308,14 @@ fbtenv_main() PATH="$TOOLCHAIN_ARCH_DIR/openssl/bin:$PATH"; export PATH; + export SAVED_SSL_CERT_FILE="${SSL_CERT_FILE:-""}"; + export SAVED_REQUESTS_CA_BUNDLE="${REQUESTS_CA_BUNDLE:-""}"; export SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; export SAVED_PYTHONPATH="${PYTHONPATH:-""}"; export SAVED_PYTHONHOME="${PYTHONHOME:-""}"; + export SSL_CERT_FILE="$TOOLCHAIN_ARCH_DIR/python/lib/python3.11/site-packages/certifi/cacert.pem"; + export REQUESTS_CA_BUNDLE="$SSL_CERT_FILE"; export PYTHONNOUSERSITE=1; export PYTHONPATH=; export PYTHONHOME=; From 738e0df4f460733ec9ae46c3d90a56372fb81249 Mon Sep 17 00:00:00 2001 From: Igor Danilov <59930161+polarikus@users.noreply.github.com> Date: Mon, 20 Feb 2023 15:52:15 +0300 Subject: [PATCH 24/41] Delete rwfiletest.bin on exit SDcard benchmark (#2415) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update storage_settings_scene_benchmark.c: delete rwfiletest.bin on exit SDcard brencmark * Settings: cleanup SD Benchmark temp file only if test successful Co-authored-by: あく --- .../storage_settings/scenes/storage_settings_scene_benchmark.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index 71a3df78b1..8359c00be3 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -103,6 +103,9 @@ static void storage_settings_scene_benchmark(StorageSettings* app) { break; furi_string_cat_printf(app->text_string, "R %luK", bench_r_speed[i]); + + storage_common_remove(app->fs_api, BENCH_FILE); + dialog_ex_set_text( dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter); } From b15c4afea11cf02068216057f6fa1f15ded7fc2d Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Mon, 20 Feb 2023 16:44:03 +0200 Subject: [PATCH 25/41] [FL-3122] Re-init NFC when starting the worker (#2399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Re-init NFC when starting the worker * FuriHal: cleanup nfc init/deinit sequence * FuriHal: a little bit more defensive nfc init Co-authored-by: あく --- firmware/targets/f7/api_symbols.csv | 3 ++- firmware/targets/f7/furi_hal/furi_hal_nfc.c | 20 ++++++++++++++++++-- firmware/targets/f7/furi_hal/furi_hal_nfc.h | 4 ++++ lib/nfc/nfc_worker.c | 2 ++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 33c443ae05..e320fc92ba 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,14.0,, +Version,+,14.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1171,6 +1171,7 @@ Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_nfc_activate_nfca,_Bool,"uint32_t, uint32_t*" +Function,-,furi_hal_nfc_deinit,void, Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t" Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t" Function,+,furi_hal_nfc_exit_sleep,void, diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index ce81fd0585..8910d887bc 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -24,13 +24,29 @@ FuriEventFlag* event = NULL; #define FURI_HAL_NFC_UID_INCOMPLETE (0x04) void furi_hal_nfc_init() { + furi_assert(!event); + event = furi_event_flag_alloc(); + ReturnCode ret = rfalNfcInitialize(); if(ret == ERR_NONE) { furi_hal_nfc_start_sleep(); - event = furi_event_flag_alloc(); FURI_LOG_I(TAG, "Init OK"); } else { - FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); + FURI_LOG_W(TAG, "Init Failed, RFAL returned: %d", ret); + } +} + +void furi_hal_nfc_deinit() { + ReturnCode ret = rfalDeinitialize(); + if(ret == ERR_NONE) { + FURI_LOG_I(TAG, "Deinit OK"); + } else { + FURI_LOG_W(TAG, "Deinit Failed, RFAL returned: %d", ret); + } + + if(event) { + furi_event_flag_free(event); + event = NULL; } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index d3f6de6028..dc3f873f34 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -101,6 +101,10 @@ typedef struct { */ void furi_hal_nfc_init(); +/** Deinit nfc + */ +void furi_hal_nfc_deinit(); + /** Check if nfc worker is busy * * @return true if busy diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index a652e088a0..54bdbb24ca 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -56,6 +56,8 @@ void nfc_worker_start( while(furi_hal_nfc_is_busy()) { furi_delay_ms(10); } + furi_hal_nfc_deinit(); + furi_hal_nfc_init(); nfc_worker->callback = callback; nfc_worker->context = context; From 0a3ff7f85ae653629957dfdd970a6fd3310ad14e Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 20 Feb 2023 18:19:53 +0300 Subject: [PATCH 26/41] Show RSSI in Weather Station app (#2395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show RSSI in weather station app: copy changes from main SubGHz app * WeatherStation: remove dead code * WeatherStation: sync naming schema with current code. Co-authored-by: あく --- .../scenes/weather_station_receiver.c | 4 +++ .../views/weather_station_receiver.c | 32 +++++++++++++++++-- .../views/weather_station_receiver.h | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/applications/plugins/weather_station/scenes/weather_station_receiver.c b/applications/plugins/weather_station/scenes/weather_station_receiver.c index 670c8c3861..e76810430a 100644 --- a/applications/plugins/weather_station/scenes/weather_station_receiver.c +++ b/applications/plugins/weather_station/scenes/weather_station_receiver.c @@ -195,6 +195,10 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev ws_hopper_update(app); weather_station_scene_receiver_update_statusbar(app); } + // Get current RSSI + float rssi = furi_hal_subghz_get_rssi(); + ws_view_receiver_set_rssi(app->ws_receiver, rssi); + if(app->txrx->txrx_state == WSTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); } diff --git a/applications/plugins/weather_station/views/weather_station_receiver.c b/applications/plugins/weather_station/views/weather_station_receiver.c index de5d7b1a36..f8e2e32889 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.c +++ b/applications/plugins/weather_station/views/weather_station_receiver.c @@ -12,6 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 +#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; uint8_t type; @@ -59,8 +60,24 @@ typedef struct { uint16_t list_offset; uint16_t history_item; WSReceiverBarShow bar_show; + uint8_t u_rssi; } WSReceiverModel; +void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { + furi_assert(instance); + with_view_model( + instance->view, + WSReceiverModel * model, + { + if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + model->u_rssi = 0; + } else { + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + } + }, + true); +} + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock lock) { furi_assert(ws_receiver); ws_receiver->lock_count = 0; @@ -164,13 +181,22 @@ static void ws_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrol canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11); } +static void ws_view_rssi_draw(Canvas* canvas, WSReceiverModel* model) { + for(uint8_t i = 1; i < model->u_rssi; i++) { + if(i % 5) { + canvas_draw_dot(canvas, 46 + i, 50); + canvas_draw_dot(canvas, 47 + i, 51); + canvas_draw_dot(canvas, 46 + i, 52); + } + } +} + void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -203,10 +229,12 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } + // Draw RSSI + ws_view_rssi_draw(canvas, model); + switch(model->bar_show) { case WSReceiverBarShowLock: canvas_draw_icon(canvas, 64, 55, &I_Lock_7x8); diff --git a/applications/plugins/weather_station/views/weather_station_receiver.h b/applications/plugins/weather_station/views/weather_station_receiver.h index 30c6516d53..f81aa1f5ec 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.h +++ b/applications/plugins/weather_station/views/weather_station_receiver.h @@ -8,6 +8,8 @@ typedef struct WSReceiver WSReceiver; typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context); +void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi); + void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard); void ws_view_receiver_set_callback( From b89902942bd32f119603589e774cb4ef6318986e Mon Sep 17 00:00:00 2001 From: Round-Pi Date: Mon, 20 Feb 2023 10:55:53 -0500 Subject: [PATCH 27/41] typo combing --- ReadMe.md | 2 +- SConstruct | 2 +- .../infrared/views/infrared_progress_view.h | 2 +- .../lfrfid/scenes/lfrfid_scene_clear_t5577.c | 2 +- .../main/nfc/helpers/nfc_emv_parser.h | 6 +++--- .../main/subghz/helpers/subghz_chat.c | 2 +- .../subghz_frequency_analyzer_worker.c | 12 +++++------ .../main/subghz/helpers/subghz_types.h | 2 +- .../subghz/scenes/subghz_scene_read_raw.c | 4 ++-- .../scenes/subghz_scene_receiver_config.c | 16 +++++++-------- .../scenes/subghz_scene_receiver_info.c | 4 ++-- .../subghz/scenes/subghz_scene_set_seed_bft.c | 2 +- .../scenes/subghz_scene_set_seed_faac.c | 2 +- applications/main/subghz/subghz.c | 2 +- applications/main/subghz/subghz_history.h | 2 +- .../main/subghz/subghz_history_private.h | 4 ++-- applications/main/subghz/subghz_i.c | 2 +- applications/main/subghz/views/receiver.c | 6 +++--- .../main/subghz/views/subghz_read_raw.c | 20 +++++++++---------- .../main/subghz/views/subghz_read_raw.h | 2 +- applications/main/u2f/u2f_data.c | 2 +- applications/main/unirfremix/unirfremix_app.c | 4 ++-- applications/services/cli/cli_commands.c | 2 +- applications/services/crypto/crypto_cli.c | 2 +- .../desktop/animations/animation_manager.h | 2 +- applications/services/gui/canvas.h | 2 +- applications/services/gui/elements.c | 20 +++++++++---------- applications/services/gui/elements.h | 4 ++-- .../services/gui/modules/button_panel.h | 2 +- .../services/gui/modules/text_input.c | 6 +++--- applications/services/gui/modules/widget.h | 2 +- applications/services/gui/scene_manager.c | 4 ++-- applications/services/gui/view_stack.h | 2 +- .../services/power/power_service/power.c | 4 ++-- applications/services/rpc/rpc.c | 4 ++-- applications/services/storage/storage.h | 4 ++-- .../power_settings_app/power_settings_app.c | 6 +++--- .../power_settings_app/power_settings_app.h | 2 +- .../power_settings_scene_battery_info.c | 2 +- .../settings/system/system_settings.c | 18 ++++++++--------- documentation/InfraredCaptures.md | 2 +- documentation/MultiConverter.md | 2 +- documentation/SubGHzSettings.md | 6 +++--- documentation/fbt.md | 2 +- .../file_formats/SubGhzFileFormats.md | 2 +- fbt_options.py | 2 +- firmware/targets/f7/furi_hal/furi_hal_uart.h | 2 +- lib/subghz/subghz_file_encoder_worker.c | 10 +++++----- lib/subghz/subghz_tx_rx_worker.c | 6 +++--- scripts/fbt_tools/fbt_dist.py | 8 ++++---- scripts/fbt_tools/fbt_help.py | 2 +- scripts/fbt_tools/fbt_hwtarget.py | 2 +- 52 files changed, 118 insertions(+), 118 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index d93061bb6b..e6d5bb1a63 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -54,7 +54,7 @@ Our Discord Community: Also check the changelog in releases for latest updates! ### Current modified and new Sub-GHz protocols list: -Thanks to Official team (to thier SubGHz Developer, Skorp) for implementing decoders for these protocols. +Thanks to Official team (to their SubGHz Developer, Skorp) for implementing decoders for these protocols. Encoders/sending made by Eng1n33r & @xMasterX: diff --git a/SConstruct b/SConstruct index 62e37dfdcb..81ff67790b 100644 --- a/SConstruct +++ b/SConstruct @@ -139,7 +139,7 @@ if GetOption("fullenv") or any( basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"]) distenv.Default(basic_dist) -dist_dir = distenv.GetProjetDirName() +dist_dir = distenv.GetProjectDirName() fap_dist = [ distenv.Install( distenv.Dir(f"#/dist/{dist_dir}/apps/debug_elf"), diff --git a/applications/main/infrared/views/infrared_progress_view.h b/applications/main/infrared/views/infrared_progress_view.h index e8f76ba1fa..4f3c3a8755 100644 --- a/applications/main/infrared/views/infrared_progress_view.h +++ b/applications/main/infrared/views/infrared_progress_view.h @@ -10,7 +10,7 @@ extern "C" { #endif -/** Anonumous instance */ +/** Anonymous instance */ typedef struct InfraredProgressView InfraredProgressView; /** Callback for back button handling */ diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c index db9718669e..c57373a3ac 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c @@ -14,7 +14,7 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { T55xxTiming* t55xxtiming = malloc(sizeof(T55xxTiming)); Popup* popup = app->popup; char curr_buf[32] = {}; - //TODO: use .txt file in resourses for passwords. + //TODO: use .txt file in resources for passwords. const uint32_t default_passwords[] = { 0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F, 0x89A69E60, 0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752, diff --git a/applications/main/nfc/helpers/nfc_emv_parser.h b/applications/main/nfc/helpers/nfc_emv_parser.h index abe57f470f..c636ca77d5 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.h +++ b/applications/main/nfc/helpers/nfc_emv_parser.h @@ -9,7 +9,7 @@ * @param aid - AID number array * @param aid_len - AID length * @param aid_name - string to keep AID name - * @return - true if AID found, false otherwies + * @return - true if AID found, false otherwise */ bool nfc_emv_parser_get_aid_name( Storage* storage, @@ -21,7 +21,7 @@ bool nfc_emv_parser_get_aid_name( * @param storage Storage instance * @param country_code - ISO 3166 country code * @param country_name - string to keep country name - * @return - true if country found, false otherwies + * @return - true if country found, false otherwise */ bool nfc_emv_parser_get_country_name( Storage* storage, @@ -32,7 +32,7 @@ bool nfc_emv_parser_get_country_name( * @param storage Storage instance * @param currency_code - ISO 3166 currency code * @param currency_name - string to keep currency name - * @return - true if currency found, false otherwies + * @return - true if currency found, false otherwise */ bool nfc_emv_parser_get_currency_name( Storage* storage, diff --git a/applications/main/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c index dbf34c9705..b589ba5d59 100644 --- a/applications/main/subghz/helpers/subghz_chat.c +++ b/applications/main/subghz/helpers/subghz_chat.c @@ -9,7 +9,7 @@ struct SubGhzChatWorker { SubGhzTxRxWorker* subghz_txrx; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; FuriMessageQueue* event_queue; uint32_t last_time_rx_data; diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index f7b3ea669c..d4e7197924 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -117,15 +117,15 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // First stage: coarse scan for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) { - uint32_t current_frequnecy = subghz_setting_get_frequency(instance->setting, i); - if(furi_hal_subghz_is_frequency_valid(current_frequnecy) && - (current_frequnecy != 467750000) && + uint32_t current_frequency = subghz_setting_get_frequency(instance->setting, i); + if(furi_hal_subghz_is_frequency_valid(current_frequency) && + (current_frequency != 467750000) && !((furi_hal_subghz.radio_type == SubGhzRadioExternal) && - (current_frequnecy >= 311900000 && current_frequnecy <= 312200000))) { + (current_frequency >= 311900000 && current_frequency <= 312200000))) { furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); frequency = - cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequnecy); + cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequency); cc1101_calibrate(furi_hal_subghz.spi_bus_handle); do { @@ -330,4 +330,4 @@ void subghz_frequency_analyzer_worker_set_trigger_level( float subghz_frequency_analyzer_worker_get_trigger_level(SubGhzFrequencyAnalyzerWorker* instance) { return instance->trigger_level; -} \ No newline at end of file +} diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 7d63ba6b98..6e42c15235 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -23,7 +23,7 @@ typedef enum { /** SubGhzHopperState state */ typedef enum { SubGhzHopperStateOFF, - SubGhzHopperStateRunnig, + SubGhzHopperStateRunning, SubGhzHopperStatePause, SubGhzHopperStateRSSITimeOut, } SubGhzHopperState; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index e396527cc4..1e3d6a9c07 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -368,7 +368,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { float rssi = furi_hal_subghz_get_rssi(); - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { + if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); subghz_protocol_raw_save_to_file_pause( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); @@ -421,4 +421,4 @@ void subghz_scene_read_raw_on_exit(void* context) { //filter restoration subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); -} \ No newline at end of file +} diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index af4c6aca30..ff51e2f4d0 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -8,11 +8,11 @@ enum SubGhzSettingIndex { SubGhzSettingIndexBinRAW, SubGhzSettingIndexSound, SubGhzSettingIndexLock, - SubGhzSettingIndexRAWThesholdRSSI, + SubGhzSettingIndexRAWThresholdRSSI, }; #define RAW_THRESHOLD_RSSI_COUNT 11 -const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { +const char* const raw_threshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { "-----", "-85.0", "-80.0", @@ -26,7 +26,7 @@ const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { "-40.0", }; -const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { +const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { -90.0f, -85.0f, -80.0f, @@ -47,7 +47,7 @@ const char* const hopping_text[HOPPING_COUNT] = { }; const uint32_t hopping_value[HOPPING_COUNT] = { SubGhzHopperStateOFF, - SubGhzHopperStateRunnig, + SubGhzHopperStateRunning, }; #define SPEAKER_COUNT 2 @@ -213,8 +213,8 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; + variable_item_set_current_value_text(item, raw_threshold_rssi_text[index]); + subghz->txrx->raw_threshold_rssi = raw_threshold_rssi_value[index]; } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -320,9 +320,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz->txrx->raw_threshold_rssi, raw_threshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); + variable_item_set_current_value_text(item, raw_threshold_rssi_text[value_index]); } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 0b265cca29..e5b037f2eb 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -148,7 +148,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_rx(subghz, subghz->txrx->preset->frequency); } if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } subghz->state_notifications = SubGhzNotificationStateRx; } else { @@ -175,7 +175,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_rx(subghz, subghz->txrx->preset->frequency); } if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } subghz->state_notifications = SubGhzNotificationStateRx; } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c b/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c index 1d6f9d70ba..2c48462efa 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c @@ -14,7 +14,7 @@ void subghz_scene_set_seed_bft_on_enter(void* context) { SubGhz* subghz = context; // Setup view - // roguemaster don't steal!!! + // RogueMaster don't steal!!! ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter SEED in hex"); byte_input_set_result_callback( diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c b/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c index 8e955e4b76..55387a0a51 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c @@ -65,7 +65,7 @@ bool subghz_scene_set_seed_faac_on_event(void* context, SceneManagerEvent event) seed, "FAAC_SLH", subghz->txrx->preset); - // rogueemaster dont steal! + // RogueMaster dont steal! uint8_t seed_data[sizeof(uint32_t)] = {0}; for(size_t i = 0; i < sizeof(uint32_t); i++) { seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 78295f08ce..ac92701141 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -275,7 +275,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->history = subghz_history_alloc(); } - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; + subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->fff_data = flipper_format_string_alloc(); diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 607dbeae2f..4b01f5aefb 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -80,7 +80,7 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* outp * * @param instance - SubGhzHistory instance * @param output - FuriString* output - * @return bool - is FUUL + * @return bool - is FULL */ bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output); diff --git a/applications/main/subghz/subghz_history_private.h b/applications/main/subghz/subghz_history_private.h index 7c554621b7..12ce28fffb 100644 --- a/applications/main/subghz/subghz_history_private.h +++ b/applications/main/subghz/subghz_history_private.h @@ -92,7 +92,7 @@ uint32_t subghz_history_rand_range(uint32_t min, uint32_t max); * * @param file - Stream* * @param is_negative_start - first value is negative or positive? - * @param current_position - 0 if started from begining + * @param current_position - 0 if started from beginning * @param empty_line - add RAW_Data to this line * @return true * @return false @@ -160,4 +160,4 @@ bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool str * @return true * @return false */ -bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last); \ No newline at end of file +bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 9f9a4be8fd..c1a1a92aeb 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -575,7 +575,7 @@ void subghz_hopper_update(SubGhz* subghz) { return; } } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } // Select next frequency if(subghz->txrx->hopper_idx_frequency < diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index f09b919e6b..f981a2eef2 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -12,7 +12,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -80,10 +80,10 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { instance->view, SubGhzViewReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 7ba2f44346..fcc077efa5 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -23,7 +23,7 @@ typedef struct { FuriString* sample_write; FuriString* file_name; uint8_t* rssi_history; - uint8_t rssi_curret; + uint8_t rssi_current; bool rssi_history_end; uint8_t ind_write; uint8_t ind_sin; @@ -62,17 +62,17 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); } with_view_model( instance->view, SubGhzReadRAWModel * model, { - model->rssi_curret = u_rssi; + model->rssi_current = u_rssi; if(trace) { model->rssi_history[model->ind_write++] = u_rssi; } else { @@ -206,10 +206,10 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]); } canvas_draw_line( - canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_curret); + canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_current); if(model->ind_write > 3) { canvas_draw_line( - canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_curret); + canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_current); for(uint8_t i = 13; i < 47; i += width * 2) { canvas_draw_line(canvas, model->ind_write, i, model->ind_write, i + width); @@ -231,13 +231,13 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, 47, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, - 47 - model->rssi_curret); + 47 - model->rssi_current); canvas_draw_line( canvas, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, 47, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, - 47 - model->rssi_curret); + 47 - model->rssi_current); for(uint8_t i = 13; i < 47; i += width * 2) { canvas_draw_line( @@ -266,9 +266,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod uint8_t x = 118; uint8_t y = 48; - if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) { uint8_t x = 118; - y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); uint8_t width = 3; for(uint8_t i = 0; i < x; i += width * 2) { diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 43afac427f..9d63870d5c 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,7 +3,7 @@ #include #include "../helpers/subghz_custom_event.h" -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct SubGhzReadRAW SubGhzReadRAW; diff --git a/applications/main/u2f/u2f_data.c b/applications/main/u2f/u2f_data.c index 66604d166a..217733c943 100644 --- a/applications/main/u2f/u2f_data.c +++ b/applications/main/u2f/u2f_data.c @@ -178,7 +178,7 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) { uint8_t key_slot = 0; uint32_t version = 0; - // Check if unique key exists in secure eclave and generate it if missing + // Check if unique key exists in secure eclave(typo?) and generate it if missing if(!furi_hal_crypto_verify_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false; FuriString* filetype; diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index 03c3c2f275..1db9a13c50 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -640,7 +640,7 @@ static void render_callback(Canvas* canvas, void* ctx) { //canvas_draw_str(canvas, 0, 40, "D: "); //canvas_draw_str(canvas, 0, 50, "Ok: "); - //PNGs are located in assets/icons/UniRFRemix before compiliation + //PNGs are located in assets/icons/UniRFRemix before compilation //Icons for Labels //canvas_draw_icon(canvas, 0, 0, &I_UniRFRemix_LeftAlignedButtons_9x64); @@ -1046,4 +1046,4 @@ int32_t unirfremix_app(void* p) { unirfremix_free(app, true); return 0; -} \ No newline at end of file +} diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index c21d45ee49..093b9ace70 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -137,7 +137,7 @@ void cli_command_date(Cli* cli, FuriString* args, void* context) { } void cli_command_src(Cli* cli, FuriString* args, void* context) { - // Quality of life feaature for people exploring CLI on lab.flipper.net/cli + // Quality of life feature for people exploring CLI on lab.flipper.net/cli // By Yousef AK UNUSED(cli); UNUSED(args); diff --git a/applications/services/crypto/crypto_cli.c b/applications/services/crypto/crypto_cli.c index a286f44571..511a9d2a8f 100644 --- a/applications/services/crypto/crypto_cli.c +++ b/applications/services/crypto/crypto_cli.c @@ -14,7 +14,7 @@ void crypto_cli_print_usage() { "\tdecrypt \t - Using key from secure enclave and IV decrypt hex encoded encrypted with AES256CBC data to plain text\r\n"); printf("\thas_key \t - Check if secure enclave has key in slot\r\n"); printf( - "\tstore_key \t - Store key in secure enclave. !!! NON-REVERSABLE OPERATION - READ MANUAL FIRST !!!\r\n"); + "\tstore_key \t - Store key in secure enclave. !!! NON-REVERSIBLE OPERATION - READ MANUAL FIRST !!!\r\n"); }; void crypto_cli_encrypt(Cli* cli, FuriString* args) { diff --git a/applications/services/desktop/animations/animation_manager.h b/applications/services/desktop/animations/animation_manager.h index a3dcc88279..a02bfe7dbf 100644 --- a/applications/services/desktop/animations/animation_manager.h +++ b/applications/services/desktop/animations/animation_manager.h @@ -152,7 +152,7 @@ bool animation_manager_is_animation_loaded(AnimationManager* animation_manager); void animation_manager_unload_and_stall_animation(AnimationManager* animation_manager); /** - * Load and Contunue execution of animation manager. + * Load and Continue execution of animation manager. * * @animation_manager instance */ diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 4fc97931f2..79ad2bcc57 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -363,7 +363,7 @@ void canvas_draw_rframe( uint8_t height, uint8_t radius); -/** Draw rounded-corner box of width, height at x,y, with round value raduis +/** Draw rounded-corner box of width, height at x,y, with round value radius * * @param canvas Canvas instance * @param x x coordinate diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index 9b7c84ece1..90682d68e4 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -635,8 +635,8 @@ void elements_text_box( ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; bool bold = false; bool mono = false; - bool inversed = false; - bool inversed_present = false; + bool inverse = false; + bool inverse_present = false; Font current_font = FontSecondary; Font prev_font = FontSecondary; const CanvasFontParameters* font_params = canvas_get_font_params(canvas, current_font); @@ -692,8 +692,8 @@ void elements_text_box( canvas_set_font(canvas, FontKeyboard); mono = !mono; } - if(text[i] == ELEMENTS_INVERSED_MARKER) { - inversed_present = true; + if(text[i] == ELEMENTS_INVERSE_MARKER) { + inverse_present = true; } continue; } @@ -709,10 +709,10 @@ void elements_text_box( if(text[i] == '\0') { full_text_processed = true; } - if(inversed_present) { + if(inverse_present) { line_leading_min += 1; line_leading_default += 1; - inversed_present = false; + inverse_present = false; } line[line_num].leading_min = line_leading_min; line[line_num].leading_default = line_leading_default; @@ -775,7 +775,7 @@ void elements_text_box( canvas_set_font(canvas, FontSecondary); bold = false; mono = false; - inversed = false; + inverse = false; for(uint8_t i = 0; i < line_num; i++) { for(uint8_t j = 0; j < line[i].len; j++) { // Process format symbols @@ -799,11 +799,11 @@ void elements_text_box( mono = !mono; continue; } - if(line[i].text[j] == ELEMENTS_INVERSED_MARKER) { - inversed = !inversed; + if(line[i].text[j] == ELEMENTS_INVERSE_MARKER) { + inverse = !inverse; continue; } - if(inversed) { + if(inverse) { canvas_draw_box( canvas, line[i].x - 1, diff --git a/applications/services/gui/elements.h b/applications/services/gui/elements.h index 4853351312..04ca357b82 100644 --- a/applications/services/gui/elements.h +++ b/applications/services/gui/elements.h @@ -19,7 +19,7 @@ extern "C" { #define ELEMENTS_MAX_LINES_NUM (7) #define ELEMENTS_BOLD_MARKER '#' #define ELEMENTS_MONO_MARKER '*' -#define ELEMENTS_INVERSED_MARKER '!' +#define ELEMENTS_INVERSE_MARKER '!' /** Draw progress bar. * @@ -240,7 +240,7 @@ void elements_scrollable_text_line( * @param[in] text Formatted text. The following formats are available: * "\e#Bold text\e#" - bold font is used * "\e*Monospaced text\e*" - monospaced font is used - * "\e!Inversed text\e!" - white text on black background + * "\e!Inverted text\e!" - white text on black background * @param strip_to_dots Strip text to ... if does not fit to width */ void elements_text_box( diff --git a/applications/services/gui/modules/button_panel.h b/applications/services/gui/modules/button_panel.h index e74f7bc3b2..4733b46958 100644 --- a/applications/services/gui/modules/button_panel.h +++ b/applications/services/gui/modules/button_panel.h @@ -61,7 +61,7 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re * @param matrix_place_x coordinates by x-axis on virtual grid, it * is only used for navigation * @param matrix_place_y coordinates by y-axis on virtual grid, it - * is only used for naviagation + * is only used for navigation * @param x x-coordinate to draw icon on * @param y y-coordinate to draw icon on * @param icon_name name of the icon to draw diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 32607e8842..60700f12ab 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -309,9 +309,9 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b char selected = get_selected_char(model); size_t text_length = strlen(model->text_buffer); - bool toogle_case = text_length == 0; - if(shift) toogle_case = !toogle_case; - if(toogle_case) { + bool toggle_case = text_length == 0; + if(shift) toggle_case = !toggle_case; + if(toggle_case) { selected = char_to_uppercase(selected); } diff --git a/applications/services/gui/modules/widget.h b/applications/services/gui/modules/widget.h index 9076ce7f29..a78c4ce06a 100644 --- a/applications/services/gui/modules/widget.h +++ b/applications/services/gui/modules/widget.h @@ -91,7 +91,7 @@ void widget_add_string_element( * @param[in] text Formatted text. The following formats are available: * "\e#Bold text\e#" - bold font is used * "\e*Monospaced text\e*" - monospaced font is used - * "\e!Inversed text\e!" - white text on black background + * "\e!Inverted text\e!" - white text on black background * @param strip_to_dots Strip text to ... if does not fit to width */ void widget_add_text_box_element( diff --git a/applications/services/gui/scene_manager.c b/applications/services/gui/scene_manager.c index 4064dafb66..4122b3bc36 100644 --- a/applications/services/gui/scene_manager.c +++ b/applications/services/gui/scene_manager.c @@ -10,7 +10,7 @@ SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers scene_manager->scene_handlers = app_scene_handlers; // Allocate all scenes scene_manager->scene = malloc(sizeof(AppScene) * app_scene_handlers->scene_num); - // Initialize ScaneManager array for navigation + // Initialize SceneManager array for navigation SceneManagerIdStack_init(scene_manager->scene_id_stack); return scene_manager; @@ -19,7 +19,7 @@ SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers void scene_manager_free(SceneManager* scene_manager) { furi_assert(scene_manager); - // Clear ScaneManager array + // Clear SceneManager array SceneManagerIdStack_clear(scene_manager->scene_id_stack); // Clear allocated scenes free(scene_manager->scene); diff --git a/applications/services/gui/view_stack.h b/applications/services/gui/view_stack.h index cd62b4f6a0..f16f5febc3 100644 --- a/applications/services/gui/view_stack.h +++ b/applications/services/gui/view_stack.h @@ -3,7 +3,7 @@ * GUI: ViewStack API * * ViewStack accumulates several Views in one stack. - * Draw callbacks are called sequenctially starting from + * Draw callbacks are called sequentially starting from * first added. Input callbacks are called in reverse order. * Consumed input is not passed on underlying layers. */ diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index cf71487b70..a134751260 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -66,7 +66,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { 4.2)) { // not looking nice with low voltage indicator canvas_set_font(canvas, FontBatteryPercent); - // align charge dispaly value with digits to draw + // align charge display value with digits to draw uint8_t bar_charge = power->info.charge; if(bar_charge > 23 && bar_charge < 38) { bar_charge = 23; @@ -158,7 +158,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 1, 1, 22, 6); - // align charge dispaly value with digits to draw + // align charge display value with digits to draw uint8_t bar_charge = power->info.charge; if(bar_charge > 48 && bar_charge < 63) { diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 63a71ad06d..ecb4b76393 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -145,8 +145,8 @@ void rpc_session_set_terminated_callback( /* Doesn't forbid using rpc_feed_bytes() after session close - it's safe. * Because any bytes received in buffer will be flushed before next session. - * If bytes get into stream buffer before it's get epmtified and this - * command is gets processed - it's safe either. But case of it is quite + * If bytes get into stream buffer before it's get emptied and this + * command is gets processed - it's safe either way. But case of it is quite * odd: client sends close request and sends command after. */ size_t diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index e093cbe0f4..df85a40b8f 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -305,14 +305,14 @@ typedef void (*Storage_name_converter)(FuriString*); /** Backs up internal storage to a tar archive * @param api pointer to the api - * @param dstmane destination archive path + * @param dstname destination archive path * @return FS_Error operation result */ FS_Error storage_int_backup(Storage* api, const char* dstname); /** Restores internal storage from a tar archive * @param api pointer to the api - * @param dstmane archive path + * @param dstname archive path * @param converter pointer to filename conversion function, may be NULL * @return FS_Error operation result */ diff --git a/applications/settings/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c index b01f32f75b..d2eaec0a5a 100644 --- a/applications/settings/power_settings_app/power_settings_app.c +++ b/applications/settings/power_settings_app/power_settings_app.c @@ -39,11 +39,11 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views - app->batery_info = battery_info_alloc(); + app->battery_info = battery_info_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewBatteryInfo, - battery_info_get_view(app->batery_info)); + battery_info_get_view(app->battery_info)); app->submenu = submenu_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu)); @@ -60,7 +60,7 @@ void power_settings_app_free(PowerSettingsApp* app) { furi_assert(app); // Views view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo); - battery_info_free(app->batery_info); + battery_info_free(app->battery_info); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu); submenu_free(app->submenu); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewDialog); diff --git a/applications/settings/power_settings_app/power_settings_app.h b/applications/settings/power_settings_app/power_settings_app.h index cd05846c05..eb9ffcf67d 100644 --- a/applications/settings/power_settings_app/power_settings_app.h +++ b/applications/settings/power_settings_app/power_settings_app.h @@ -19,7 +19,7 @@ typedef struct { Gui* gui; SceneManager* scene_manager; ViewDispatcher* view_dispatcher; - BatteryInfo* batery_info; + BatteryInfo* battery_info; Submenu* submenu; DialogEx* dialog; PowerInfo info; diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c index 5fa38df729..2b70662c84 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c @@ -11,7 +11,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app .charge = app->info.charge, .health = app->info.health, }; - battery_info_set_data(app->batery_info, &battery_info_data); + battery_info_set_data(app->battery_info, &battery_info_data); } void power_settings_scene_battery_info_on_enter(void* context) { diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 5eade21159..f9abdb693f 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -71,21 +71,21 @@ static void heap_trace_mode_changed(VariableItem* item) { furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]); } -const char* const mesurement_units_text[] = { +const char* const measurement_units_text[] = { "Metric", "Imperial", }; -const uint32_t mesurement_units_value[] = { +const uint32_t measurement_units_value[] = { LocaleMeasurementUnitsMetric, LocaleMeasurementUnitsImperial, }; -static void mesurement_units_changed(VariableItem* item) { +static void measurement_units_changed(VariableItem* item) { // SystemSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, mesurement_units_text[index]); - locale_set_measurement_unit(mesurement_units_value[index]); + variable_item_set_current_value_text(item, measurement_units_text[index]); + locale_set_measurement_unit(measurement_units_value[index]); } const char* const time_format_text[] = { @@ -148,13 +148,13 @@ SystemSettings* system_settings_alloc() { item = variable_item_list_add( app->var_item_list, "Units", - COUNT_OF(mesurement_units_text), - mesurement_units_changed, + COUNT_OF(measurement_units_text), + measurement_units_changed, app); value_index = value_index_uint32( - locale_get_measurement_unit(), mesurement_units_value, COUNT_OF(mesurement_units_value)); + locale_get_measurement_unit(), measurement_units_value, COUNT_OF(measurement_units_value)); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, mesurement_units_text[value_index]); + variable_item_set_current_value_text(item, measurement_units_text[value_index]); item = variable_item_list_add( app->var_item_list, "Time Format", COUNT_OF(time_format_text), time_format_changed, app); diff --git a/documentation/InfraredCaptures.md b/documentation/InfraredCaptures.md index 61097ad6dd..4f23e65702 100644 --- a/documentation/InfraredCaptures.md +++ b/documentation/InfraredCaptures.md @@ -22,7 +22,7 @@ If you notice you get a parsed code when capturing it's best to click "Retry" a **Parsed data** -This is the cleanest type of data because it means it is a recognised code. +This is the cleanest type of data because it means it is a recognized code. ``` name: EXAMPLE diff --git a/documentation/MultiConverter.md b/documentation/MultiConverter.md index 5ce78c7494..9e27f40f0d 100644 --- a/documentation/MultiConverter.md +++ b/documentation/MultiConverter.md @@ -14,7 +14,7 @@ I wrote it with the idea of _expanding the unit list_ on mind, so adding new one ## Current conversions - `Decimal / Hexadecimal / Binary` -- `Celsius / Fahernheit / Kelvin` +- `Celsius / Fahrenheit / Kelvin` - `Kilometers / Meters / Centimeters / Miles / Feet / Inches` - `Degree / Radian` diff --git a/documentation/SubGHzSettings.md b/documentation/SubGHzSettings.md index b1a678e8e4..e30a7c2445 100644 --- a/documentation/SubGHzSettings.md +++ b/documentation/SubGHzSettings.md @@ -70,7 +70,7 @@ if you need your custom one, make sure it doesn't listed here ### User frequencies added AFTER that default list! You need to continue until you reach the end of that list -### If you want to disable default list and use ONLY user added frequecies from user settings file +### If you want to disable default list and use ONLY user added frequencies from user settings file Change that line `#Add_standard_frequencies: true` to @@ -81,7 +81,7 @@ Just add new line `Frequency: 928000000` - where `928000000` is your frequency, keep it in that format! it should be 9 digits! ### Hopper frequency list -To add new frequecy to hopper: +To add new frequency to hopper: add new line `Hopper_frequency: 345000000`
But remember! You should keep it as small as possible, or hopper functionality would be useless!
If `#Add_standard_frequencies: true` is not changed
@@ -95,4 +95,4 @@ Your frequencies will be added after default ones 433420000, 433920000, 868350000, -``` \ No newline at end of file +``` diff --git a/documentation/fbt.md b/documentation/fbt.md index 65c3ee6825..3930cd5918 100644 --- a/documentation/fbt.md +++ b/documentation/fbt.md @@ -72,7 +72,7 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio - `get_stlink` - output serial numbers for attached STLink probes. Used for specifying an adapter with `OPENOCD_ADAPTER_SERIAL=...`. - `lint`, `format` - run clang-format on the C source code to check and reformat it according to the `.clang-format` specs. - `lint_py`, `format_py` - run [black](https://black.readthedocs.io/en/stable/index.html) on the Python source code, build system files & application manifests. -- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be availabe on your system's `PATH`. +- `firmware_pvs` - generate a PVS Studio report for the firmware. Requires PVS Studio to be available on your system's `PATH`. - `cli` - start a Flipper CLI session over USB. ### Firmware targets diff --git a/documentation/file_formats/SubGhzFileFormats.md b/documentation/file_formats/SubGhzFileFormats.md index 26863f5642..f65c5bfb19 100644 --- a/documentation/file_formats/SubGhzFileFormats.md +++ b/documentation/file_formats/SubGhzFileFormats.md @@ -141,7 +141,7 @@ Long payload not fitting into internal memory buffer and consisting of short dur Frequency: 433920000 Preset: FuriHalSubGhzPresetCustom Custom_preset_module: CC1101 - Сustom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 + Custom_preset_data: 02 0D 03 07 08 32 0B 06 14 00 13 00 12 30 11 32 10 17 18 18 19 18 1D 91 1C 00 1B 07 20 FB 22 11 21 B6 00 00 00 C0 00 00 00 00 00 00 Protocol: RAW RAW_Data: 29262 361 -68 2635 -66 24113 -66 11 ... RAW_Data: -424 205 -412 159 -412 381 -240 181 ... diff --git a/fbt_options.py b/fbt_options.py index 9ecd735667..3ba59e733b 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -32,7 +32,7 @@ # Leave 0 to let scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -# If you override COPRO_CUBE_DIR on commandline, override this as well +# If you override COPRO_CUBE_DIR on command-line, override this as well COPRO_STACK_BIN_DIR = posixpath.join( COPRO_CUBE_DIR, "Projects", diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.h b/firmware/targets/f7/furi_hal/furi_hal_uart.h index 07211db8bc..3ba4dc4837 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.h +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.h @@ -31,7 +31,7 @@ typedef enum { /** * Init UART - * Configures GPIO to UART function, сonfigures UART hardware, enables UART hardware + * Configures GPIO to UART function, configures UART hardware, enables UART hardware * @param channel UART channel * @param baud baudrate */ diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index a8c6519ef0..8bc6e84460 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -16,7 +16,7 @@ struct SubGhzFileEncoderWorker { FlipperFormat* flipper_format; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; bool level; bool is_storage_slow; FuriString* str_data; @@ -105,7 +105,7 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { } else if(duration == 0) { //-V547 level_duration = level_duration_reset(); FURI_LOG_I(TAG, "Stop transmission"); - instance->worker_stoping = true; + instance->worker_stopping = true; } return level_duration; } else { @@ -142,7 +142,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { //skip the end of the previous line "\n" stream_seek(stream, 1, StreamOffsetFromCurrent); res = true; - instance->worker_stoping = false; + instance->worker_stopping = false; FURI_LOG_I(TAG, "Start transmission"); } while(0); @@ -174,7 +174,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { } FURI_LOG_I(TAG, "End transmission"); while(instance->worker_running) { - if(instance->worker_stoping) { + if(instance->worker_stopping) { if(instance->callback_end) instance->callback_end(instance->context_end); } furi_delay_ms(50); @@ -198,7 +198,7 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { instance->str_data = furi_string_alloc(); instance->file_path = furi_string_alloc(); instance->level = false; - instance->worker_stoping = true; + instance->worker_stopping = true; return instance; } diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index e380fc967c..21568dab1b 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -16,7 +16,7 @@ struct SubGhzTxRxWorker { FuriStreamBuffer* stream_rx; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; SubGhzTxRxWorkerStatus status; @@ -166,7 +166,7 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { subghz_tx_rx_worker_tx(instance, data, size_tx); } } else { - //recive + //receive if(subghz_tx_rx_worker_rx(instance, data, size_rx)) { if(furi_stream_buffer_spaces_available(instance->stream_rx) >= size_rx[0]) { if(instance->callback_have_read && @@ -211,7 +211,7 @@ SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() { furi_stream_buffer_alloc(sizeof(uint8_t) * SUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t)); instance->status = SubGhzTxRxWorkerStatusIDLE; - instance->worker_stoping = true; + instance->worker_stopping = true; return instance; } diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index f0b4434864..c0eca0d2ac 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -4,7 +4,7 @@ from SCons.Defaults import Touch -def GetProjetDirName(env, project=None): +def GetProjectDirName(env, project=None): parts = [f"f{env['TARGET_HW']}"] if project: parts.append(project) @@ -21,7 +21,7 @@ def GetProjetDirName(env, project=None): def create_fw_build_targets(env, configuration_name): - flavor = GetProjetDirName(env, configuration_name) + flavor = GetProjectDirName(env, configuration_name) build_dir = env.Dir("build").Dir(flavor) return env.SConscript( "firmware.scons", @@ -49,7 +49,7 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): ], ) - env.Replace(DIST_DIR=env.GetProjetDirName()) + env.Replace(DIST_DIR=env.GetProjectDirName()) return project_env @@ -115,7 +115,7 @@ def generate(env): env.AddMethod(AddFwProject) env.AddMethod(DistCommand) env.AddMethod(AddOpenOCDFlashTarget) - env.AddMethod(GetProjetDirName) + env.AddMethod(GetProjectDirName) env.AddMethod(AddJFlashTarget) env.AddMethod(AddUsbFlashTarget) diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index afdb36665c..1b2903058e 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -26,7 +26,7 @@ cli: Open a Flipper CLI session over USB firmware_cdb, updater_cdb: - Generate сompilation_database.json + Generate compilation_database.json lint, lint_py: run linters format, format_py: diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py index b4e1e58ac1..7deb3e87f9 100644 --- a/scripts/fbt_tools/fbt_hwtarget.py +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -93,7 +93,7 @@ def gatherSdkHeaders(self): sdk_headers = [] seen_sdk_headers = set(self.excluded_headers) for sdk_path in self.sdk_header_paths: - # dirty, but fast - exclude headers from overlayed targets by name + # dirty, but fast - exclude headers from overlaid targets by name # proper way would be to use relative paths, but names will do for now for header in self.env.GlobRecursive("*.h", sdk_path, "*_i.h"): if header.name not in seen_sdk_headers: From 663eb6cd6d4a14d00caf93d402b71eadb9a4d63f Mon Sep 17 00:00:00 2001 From: Liam Hays Date: Tue, 21 Feb 2023 00:15:48 -0700 Subject: [PATCH 28/41] Display Mifare Classic data in NFC app (#2389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add data display for Mifare Classic cards. * Clean up log statements and data display. Co-authored-by: あく --- .../main/nfc/scenes/nfc_scene_config.h | 1 + .../nfc/scenes/nfc_scene_mf_classic_data.c | 106 ++++++++++++++++++ .../main/nfc/scenes/nfc_scene_nfc_data_info.c | 6 +- .../main/nfc/scenes/nfc_scene_saved_menu.c | 2 + 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_classic_data.c diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index f81fe178e2..a9da07dfda 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -29,6 +29,7 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_data, MfClassicData) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c new file mode 100644 index 0000000000..dcb02d3645 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c @@ -0,0 +1,106 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_data_on_enter(void* context) { + Nfc* nfc = context; + MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + TextBox* text_box = nfc->text_box; + + text_box_set_font(text_box, TextBoxFontHex); + + int card_blocks = 0; + if(type == MfClassicType1k) { + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; + } else if(type == MfClassicType4k) { + // 16 sectors of 4 blocks each plus 8 sectors of 16 blocks each + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4 + 8 * 16; + } else if(type == MfClassicTypeMini) { + card_blocks = MF_MINI_TOTAL_SECTORS_NUM * 4; + } + + int bytes_written = 0; + for(int block_num = 0; block_num < card_blocks; block_num++) { + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + sec_tr->access_bits[i], + sec_tr->access_bits[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } else { + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + data->block[block_num].value[i], + data->block[block_num].value[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_classic_data_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index b44ab7823b..92ad7b56ef 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -14,7 +14,8 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { NfcDeviceData* dev_data = &nfc->dev->dev_data; NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; - if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl)) { + if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || + (protocol == NfcDeviceProtocolMifareClassic)) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); text_scroll_height = 52; @@ -136,6 +137,9 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } else if(protocol == NfcDeviceProtocolMifareUl) { scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData); consumed = true; + } else if(protocol == NfcDeviceProtocolMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + consumed = true; } } } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 04c686fbe8..f42e0fe951 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -150,6 +150,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } + FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); + if(application_info_present) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { From 9690dba7fe0df77032395bb2d626bbb14b214656 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:21:57 +0000 Subject: [PATCH 29/41] Updated ac.ir New additions --- assets/resources/infrared/assets/ac.ir | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index e55c27f30a..3b25a5c86b 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: raw @@ -1560,3 +1560,15 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 8838 3941 624 1427 514 500 515 497 541 473 540 1487 540 474 539 474 538 476 512 1538 514 1516 544 466 514 497 514 501 514 499 514 500 513 499 513 501 487 525 514 499 512 502 487 526 512 1517 542 470 487 1539 513 499 512 503 513 499 512 1513 512 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8364 4223 621 1958 1115 1478 593 1986 1082 1566 1072 1497 576 2003 1069 1513 1069 1541 1070 1505 1069 1505 1069 1497 1070 1550 1069 1530 1045 1522 551 2028 1045 1582 1044 1530 1044 1522 1045 1530 1044 1566 1045 1530 1045 1530 550 2021 550 2064 1044 1530 1044 1523 1043 1531 1044 1566 1045 1531 1043 1531 1044 1523 1044 1575 1043 1531 1044 1523 1044 1531 1044 1567 1044 1531 1043 1531 1044 1524 1043 1575 1043 1532 1043 1524 1043 1532 1043 1568 1042 1532 1043 1532 1043 1524 1043 1576 1042 1532 1043 1524 1043 1532 1042 1569 1042 1533 1016 1558 1042 1525 1042 1577 1016 1558 523 2048 1042 1525 547 2071 1041 1533 523 2049 522 2049 522 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8362 4223 595 1983 1116 1480 592 1987 1081 1567 1070 1524 550 2029 1043 1540 1042 1568 1043 1532 549 2030 1042 1540 1042 1568 1042 1532 1042 1532 549 2022 549 2065 1043 1528 1043 1532 1043 1524 1042 1576 1042 1532 1042 1525 548 2030 549 2082 1042 1524 1042 1533 1042 1525 1042 1576 1042 1533 1042 1525 1041 1533 1042 1569 1042 1533 1042 1533 1042 1525 1041 1577 1041 1533 1042 1525 1041 1534 1041 1569 1042 1533 1041 1534 1040 1526 1041 1578 1041 1534 1041 1526 1040 1534 1041 1570 1041 1534 1015 1560 1015 1552 1015 1604 1040 1535 1040 1527 1039 1535 1014 1597 1013 1561 1014 1561 1013 1554 519 2129 987 1554 544 2036 518 2093 987 From 2bcb15b8bc5db6673c41b7537ed672153765b9f7 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:25:20 +0000 Subject: [PATCH 30/41] Updated audio.ir New additions --- assets/resources/infrared/assets/audio.ir | 28 +++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 1bb3c11e08..d1db3270cb 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: parsed @@ -2068,3 +2068,27 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 325 50440 173 137541 4551 4465 530 475 529 475 529 474 530 474 530 1479 530 1479 529 476 528 477 527 1480 554 1457 551 1480 528 1481 527 477 527 478 526 478 526 478 526 4497 525 478 526 478 526 478 526 478 526 479 525 479 525 479 525 1484 525 1483 526 1484 525 1483 526 479 525 1483 526 1483 526 1483 526 479 525 479 525 479 525 479 525 1484 525 +# +name: POWER +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 10 EF 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0C F3 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0D F2 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 17 E8 00 00 From 11b3484f4b30b4c1e9f2c3f60c8dabd05ee599f1 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:25:51 +0000 Subject: [PATCH 31/41] Updated fans.ir Updated last checked --- assets/resources/infrared/assets/fans.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index c30f58e5e0..535f962740 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: raw From d16d1f43fc036fd2217ff46eac4a06d994fd9db0 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:26:38 +0000 Subject: [PATCH 32/41] Updated projectors.ir New additions --- assets/resources/infrared/assets/projectors.ir | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 6378f2d12e..d073dccfa9 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 8th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # # ON name: POWER @@ -838,3 +838,9 @@ type: parsed protocol: NECext address: 87 45 00 00 command: 52 AD 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8811 4222 530 1580 531 1579 531 507 531 507 531 507 531 508 531 508 530 1582 528 1583 527 535 503 1608 502 536 501 1609 501 537 501 1610 500 538 500 1611 499 538 500 539 500 538 500 1611 500 539 499 538 500 1611 499 539 499 1611 499 1611 500 1611 499 539 499 1611 500 1611 500 539 499 35437 8784 4252 500 1611 500 1612 500 539 500 539 500 539 500 539 500 539 500 1611 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 539 500 539 499 1612 499 540 499 539 500 1612 499 539 500 1612 499 1613 499 1612 499 539 500 1612 500 1612 500 539 500 From 36debf25fbc7a7070a1554d78389ca321f7c35d8 Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:27:01 +0000 Subject: [PATCH 33/41] Updated tv.ir Updated last checked --- assets/resources/infrared/assets/tv.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index e3d41b9a7d..7b203b15e7 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: parsed From f9db06b7814575b42553b9e09a5710fb3faee38a Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:42:12 +0300 Subject: [PATCH 34/41] fbt format --- applications/plugins/tetris_game/tetris_game.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/plugins/tetris_game/tetris_game.c b/applications/plugins/tetris_game/tetris_game.c index 9b492cc8ec..0b813f26ae 100644 --- a/applications/plugins/tetris_game/tetris_game.c +++ b/applications/plugins/tetris_game/tetris_game.c @@ -327,9 +327,10 @@ static void uint16_t oldNumLines = tetris_state->numLines; tetris_state->numLines += numLines; if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - nextFallSpeed = tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); - if (nextFallSpeed >= MIN_FALL_SPEED){ - tetris_state->fallSpeed = nextFallSpeed; + nextFallSpeed = + tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); + if(nextFallSpeed >= MIN_FALL_SPEED) { + tetris_state->fallSpeed = nextFallSpeed; } } } From 1f3e937471071df385eaa5cb419ce69fd1c9fb6f Mon Sep 17 00:00:00 2001 From: amec0e <88857687+amec0e@users.noreply.github.com> Date: Tue, 21 Feb 2023 23:35:00 +0000 Subject: [PATCH 35/41] Updated audio.ir Fixed rename of a power button --- assets/resources/infrared/assets/audio.ir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index d1db3270cb..b3b56e211e 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1913,7 +1913,7 @@ protocol: SIRC address: 0F 00 00 00 command: 15 00 00 00 # -name: Power +name: POWER type: parsed protocol: Samsung32 address: 10 00 00 00 From 07ff0c7d9761b4d0bbd3aea99a5995f44dd7052c Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 24 Feb 2023 02:43:42 +0300 Subject: [PATCH 36/41] Add SWD Probe into main FW Moved from extra pack to main FW https://github.com/g3gg0/flipper-swd_probe --- ReadMe.md | 1 + applications/plugins/swd_probe/.gitignore | 52 + applications/plugins/swd_probe/LICENSE.txt | 674 ++++ applications/plugins/swd_probe/README.md | 0 applications/plugins/swd_probe/adi.c | 1016 ++++++ applications/plugins/swd_probe/adi.h | 34 + .../plugins/swd_probe/application.fam | 13 + .../swd_probe/icons/ButtonDown_7x4.png | Bin 0 -> 102 bytes .../plugins/swd_probe/icons/ButtonUp_7x4.png | Bin 0 -> 102 bytes applications/plugins/swd_probe/icons/app.png | Bin 0 -> 179 bytes applications/plugins/swd_probe/icons/swd.png | Bin 0 -> 169 bytes applications/plugins/swd_probe/jep106.c | 26 + applications/plugins/swd_probe/jep106.h | 26 + applications/plugins/swd_probe/jep106.inc | 1791 +++++++++++ applications/plugins/swd_probe/model/chip.ply | 216 ++ .../plugins/swd_probe/model/convert.py | 39 + .../plugins/swd_probe/model/model_chip.h | 420 +++ .../plugins/swd_probe/swd_probe_app.c | 2840 +++++++++++++++++ .../plugins/swd_probe/swd_probe_app.h | 233 ++ applications/plugins/swd_probe/usb_uart.c | 223 ++ applications/plugins/swd_probe/usb_uart.h | 29 + assets/resources/swd_scripts/100us.swd | 1 + assets/resources/swd_scripts/call_test_1.swd | 6 + assets/resources/swd_scripts/call_test_2.swd | 7 + .../swd_scripts/dump_0x00000000_1k.swd | 6 + .../swd_scripts/dump_0x00000000_4b.swd | 6 + assets/resources/swd_scripts/dump_STM32.swd | 6 + assets/resources/swd_scripts/goto_test.swd | 7 + assets/resources/swd_scripts/halt.swd | 11 + assets/resources/swd_scripts/reset.swd | 8 + assets/resources/swd_scripts/test_write.swd | 3 + 31 files changed, 7694 insertions(+) create mode 100644 applications/plugins/swd_probe/.gitignore create mode 100644 applications/plugins/swd_probe/LICENSE.txt create mode 100644 applications/plugins/swd_probe/README.md create mode 100644 applications/plugins/swd_probe/adi.c create mode 100644 applications/plugins/swd_probe/adi.h create mode 100644 applications/plugins/swd_probe/application.fam create mode 100644 applications/plugins/swd_probe/icons/ButtonDown_7x4.png create mode 100644 applications/plugins/swd_probe/icons/ButtonUp_7x4.png create mode 100644 applications/plugins/swd_probe/icons/app.png create mode 100644 applications/plugins/swd_probe/icons/swd.png create mode 100644 applications/plugins/swd_probe/jep106.c create mode 100644 applications/plugins/swd_probe/jep106.h create mode 100644 applications/plugins/swd_probe/jep106.inc create mode 100644 applications/plugins/swd_probe/model/chip.ply create mode 100644 applications/plugins/swd_probe/model/convert.py create mode 100644 applications/plugins/swd_probe/model/model_chip.h create mode 100644 applications/plugins/swd_probe/swd_probe_app.c create mode 100644 applications/plugins/swd_probe/swd_probe_app.h create mode 100644 applications/plugins/swd_probe/usb_uart.c create mode 100644 applications/plugins/swd_probe/usb_uart.h create mode 100644 assets/resources/swd_scripts/100us.swd create mode 100644 assets/resources/swd_scripts/call_test_1.swd create mode 100644 assets/resources/swd_scripts/call_test_2.swd create mode 100644 assets/resources/swd_scripts/dump_0x00000000_1k.swd create mode 100644 assets/resources/swd_scripts/dump_0x00000000_4b.swd create mode 100644 assets/resources/swd_scripts/dump_STM32.swd create mode 100644 assets/resources/swd_scripts/goto_test.swd create mode 100644 assets/resources/swd_scripts/halt.swd create mode 100644 assets/resources/swd_scripts/reset.swd create mode 100644 assets/resources/swd_scripts/test_write.swd diff --git a/ReadMe.md b/ReadMe.md index e6d5bb1a63..f5c9c20bbc 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -139,6 +139,7 @@ You can support us by using links or addresses below: - Text Viewer [(by kowalski7cc & kyhwana)](https://github.com/kowalski7cc/flipper-zero-text-viewer/tree/refactor-text-app) - **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main) - **ProtoView** [(by antirez)](https://github.com/antirez/protoview) +- **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/) diff --git a/applications/plugins/swd_probe/.gitignore b/applications/plugins/swd_probe/.gitignore new file mode 100644 index 0000000000..c6127b38c1 --- /dev/null +++ b/applications/plugins/swd_probe/.gitignore @@ -0,0 +1,52 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/applications/plugins/swd_probe/LICENSE.txt b/applications/plugins/swd_probe/LICENSE.txt new file mode 100644 index 0000000000..f288702d2f --- /dev/null +++ b/applications/plugins/swd_probe/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/applications/plugins/swd_probe/README.md b/applications/plugins/swd_probe/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/applications/plugins/swd_probe/adi.c b/applications/plugins/swd_probe/adi.c new file mode 100644 index 0000000000..95456fcd01 --- /dev/null +++ b/applications/plugins/swd_probe/adi.c @@ -0,0 +1,1016 @@ + +#include +#include + +#include "adi.h" +#include "swd_probe_app.h" + +/* https://github.com/openocd-org/openocd/blob/master/src/target/arm_adi_v5.c */ + +/* +static const char* class_description[16] = { + [0x0] = "Generic verification component", + [0x1] = "(ROM Table)", + [0x2] = "Reserved", + [0x3] = "Reserved", + [0x4] = "Reserved", + [0x5] = "Reserved", + [0x6] = "Reserved", + [0x7] = "Reserved", + [0x8] = "Reserved", + [0x9] = "CoreSight component", + [0xA] = "Reserved", + [0xB] = "Peripheral Test Block", + [0xC] = "Reserved", + [0xD] = "OptimoDE DESS", + [0xE] = "Generic IP component", + [0xF] = "CoreLink, PrimeCell or System component", +}; +*/ + +static const struct { + uint32_t arch_id; + const char* description; +} class0x9_devarch[] = { + /* keep same unsorted order as in ARM IHI0029E */ + {ARCH_ID(ARM_ID, 0x0A00), "RAS architecture"}, + {ARCH_ID(ARM_ID, 0x1A01), "Instrumentation Trace Macrocell (ITM) architecture"}, + {ARCH_ID(ARM_ID, 0x1A02), "DWT architecture"}, + {ARCH_ID(ARM_ID, 0x1A03), "Flash Patch and Breakpoint unit (FPB) architecture"}, + {ARCH_ID(ARM_ID, 0x2A04), "Processor debug architecture (ARMv8-M)"}, + {ARCH_ID(ARM_ID, 0x6A05), "Processor debug architecture (ARMv8-R)"}, + {ARCH_ID(ARM_ID, 0x0A10), "PC sample-based profiling"}, + {ARCH_ID(ARM_ID, 0x4A13), "Embedded Trace Macrocell (ETM) architecture"}, + {ARCH_ID(ARM_ID, 0x1A14), "Cross Trigger Interface (CTI) architecture"}, + {ARCH_ID(ARM_ID, 0x6A15), "Processor debug architecture (v8.0-A)"}, + {ARCH_ID(ARM_ID, 0x7A15), "Processor debug architecture (v8.1-A)"}, + {ARCH_ID(ARM_ID, 0x8A15), "Processor debug architecture (v8.2-A)"}, + {ARCH_ID(ARM_ID, 0x2A16), "Processor Performance Monitor (PMU) architecture"}, + {ARCH_ID(ARM_ID, 0x0A17), "Memory Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A27), "JTAG Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A31), "Basic trace router"}, + {ARCH_ID(ARM_ID, 0x0A37), "Power requestor"}, + {ARCH_ID(ARM_ID, 0x0A47), "Unknown Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A50), "HSSTP architecture"}, + {ARCH_ID(ARM_ID, 0x0A63), "System Trace Macrocell (STM) architecture"}, + {ARCH_ID(ARM_ID, 0x0A75), "CoreSight ELA architecture"}, + {ARCH_ID(ARM_ID, 0x0AF7), "CoreSight ROM architecture"}, +}; + +/* Part number interpretations are from Cortex + * core specs, the CoreSight components TRM + * (ARM DDI 0314H), CoreSight System Design + * Guide (ARM DGI 0012D) and ETM specs; also + * from chip observation (e.g. TI SDTI). + */ + +static const struct dap_part_nums { + uint16_t designer_id; + uint16_t part_num; + const char* type; + const char* full; +} dap_part_nums[] = { + { + ARM_ID, + 0x000, + "Cortex-M3 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x001, + "Cortex-M3 ITM", + "(Instrumentation Trace Module)", + }, + { + ARM_ID, + 0x002, + "Cortex-M3 DWT", + "(Data Watchpoint and Trace)", + }, + { + ARM_ID, + 0x003, + "Cortex-M3 FPB", + "(Flash Patch and Breakpoint)", + }, + { + ARM_ID, + 0x008, + "Cortex-M0 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x00a, + "Cortex-M0 DWT", + "(Data Watchpoint and Trace)", + }, + { + ARM_ID, + 0x00b, + "Cortex-M0 BPU", + "(Breakpoint Unit)", + }, + { + ARM_ID, + 0x00c, + "Cortex-M4 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x00d, + "CoreSight ETM11", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x00e, + "Cortex-M7 FPB", + "(Flash Patch and Breakpoint)", + }, + { + ARM_ID, + 0x193, + "SoC-600 TSGEN", + "(Timestamp Generator)", + }, + { + ARM_ID, + 0x470, + "Cortex-M1 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x471, + "Cortex-M0 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x490, + "Cortex-A15 GIC", + "(Generic Interrupt Controller)", + }, + { + ARM_ID, + 0x492, + "Cortex-R52 GICD", + "(Distributor)", + }, + { + ARM_ID, + 0x493, + "Cortex-R52 GICR", + "(Redistributor)", + }, + { + ARM_ID, + 0x4a1, + "Cortex-A53 ROM", + "(v8 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4a2, + "Cortex-A57 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4a3, + "Cortex-A53 ROM", + "(v7 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4a4, + "Cortex-A72 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4a9, + "Cortex-A9 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4aa, + "Cortex-A35 ROM", + "(v8 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4af, + "Cortex-A15 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4b5, + "Cortex-R5 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4b8, + "Cortex-R52 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c0, + "Cortex-M0+ ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c3, + "Cortex-M3 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c4, + "Cortex-M4 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c7, + "Cortex-M7 PPB ROM", + "(Private Peripheral Bus ROM Table)", + }, + { + ARM_ID, + 0x4c8, + "Cortex-M7 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4e0, + "Cortex-A35 ROM", + "(v7 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4e4, + "Cortex-A76 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x906, + "CoreSight CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x907, + "CoreSight ETB", + "(Trace Buffer)", + }, + { + ARM_ID, + 0x908, + "CoreSight CSTF", + "(Trace Funnel)", + }, + { + ARM_ID, + 0x909, + "CoreSight ATBR", + "(Advanced Trace Bus Replicator)", + }, + { + ARM_ID, + 0x910, + "CoreSight ETM9", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x912, + "CoreSight TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x913, + "CoreSight ITM", + "(Instrumentation Trace Macrocell)", + }, + { + ARM_ID, + 0x914, + "CoreSight SWO", + "(Single Wire Output)", + }, + { + ARM_ID, + 0x917, + "CoreSight HTM", + "(AHB Trace Macrocell)", + }, + { + ARM_ID, + 0x920, + "CoreSight ETM11", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x921, + "Cortex-A8 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x922, + "Cortex-A8 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x923, + "Cortex-M3 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x924, + "Cortex-M3 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x925, + "Cortex-M4 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x930, + "Cortex-R4 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x931, + "Cortex-R5 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x932, + "CoreSight MTB-M0+", + "(Micro Trace Buffer)", + }, + { + ARM_ID, + 0x941, + "CoreSight TPIU-Lite", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x950, + "Cortex-A9 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x955, + "Cortex-A5 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95a, + "Cortex-A72 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95b, + "Cortex-A17 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x95d, + "Cortex-A53 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95e, + "Cortex-A57 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95f, + "Cortex-A15 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x961, + "CoreSight TMC", + "(Trace Memory Controller)", + }, + { + ARM_ID, + 0x962, + "CoreSight STM", + "(System Trace Macrocell)", + }, + { + ARM_ID, + 0x975, + "Cortex-M7 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x9a0, + "CoreSight PMU", + "(Performance Monitoring Unit)", + }, + { + ARM_ID, + 0x9a1, + "Cortex-M4 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9a4, + "CoreSight GPR", + "(Granular Power Requester)", + }, + { + ARM_ID, + 0x9a5, + "Cortex-A5 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9a7, + "Cortex-A7 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9a8, + "Cortex-A53 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x9a9, + "Cortex-M7 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9ae, + "Cortex-A17 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9af, + "Cortex-A15 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9b6, + "Cortex-R52 PMU/CTI/ETM", + "(Performance Monitor Unit/Cross Trigger/ETM)", + }, + { + ARM_ID, + 0x9b7, + "Cortex-R7 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d3, + "Cortex-A53 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d7, + "Cortex-A57 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d8, + "Cortex-A72 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9da, + "Cortex-A35 PMU/CTI/ETM", + "(Performance Monitor Unit/Cross Trigger/ETM)", + }, + { + ARM_ID, + 0x9e2, + "SoC-600 APB-AP", + "(APB4 Memory Access Port)", + }, + { + ARM_ID, + 0x9e3, + "SoC-600 AHB-AP", + "(AHB5 Memory Access Port)", + }, + { + ARM_ID, + 0x9e4, + "SoC-600 AXI-AP", + "(AXI Memory Access Port)", + }, + { + ARM_ID, + 0x9e5, + "SoC-600 APv1 Adapter", + "(Access Port v1 Adapter)", + }, + { + ARM_ID, + 0x9e6, + "SoC-600 JTAG-AP", + "(JTAG Access Port)", + }, + { + ARM_ID, + 0x9e7, + "SoC-600 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9e8, + "SoC-600 TMC ETR/ETS", + "(Embedded Trace Router/Streamer)", + }, + { + ARM_ID, + 0x9e9, + "SoC-600 TMC ETB", + "(Embedded Trace Buffer)", + }, + { + ARM_ID, + 0x9ea, + "SoC-600 TMC ETF", + "(Embedded Trace FIFO)", + }, + { + ARM_ID, + 0x9eb, + "SoC-600 ATB Funnel", + "(Trace Funnel)", + }, + { + ARM_ID, + 0x9ec, + "SoC-600 ATB Replicator", + "(Trace Replicator)", + }, + { + ARM_ID, + 0x9ed, + "SoC-600 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x9ee, + "SoC-600 CATU", + "(Address Translation Unit)", + }, + { + ARM_ID, + 0xc05, + "Cortex-A5 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc07, + "Cortex-A7 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc08, + "Cortex-A8 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc09, + "Cortex-A9 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc0e, + "Cortex-A17 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc0f, + "Cortex-A15 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc14, + "Cortex-R4 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc15, + "Cortex-R5 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc17, + "Cortex-R7 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd03, + "Cortex-A53 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd04, + "Cortex-A35 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd07, + "Cortex-A57 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd08, + "Cortex-A72 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd0b, + "Cortex-A76 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd0c, + "Neoverse N1", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd13, + "Cortex-R52 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd49, + "Neoverse N2", + "(Debug Unit)", + }, + { + 0x017, + 0x120, + "TI SDTI", + "(System Debug Trace Interface)", + }, /* from OMAP3 memmap */ + { + 0x017, + 0x343, + "TI DAPCTL", + "", + }, /* from OMAP3 memmap */ + {0x017, 0x9af, "MSP432 ROM", "(ROM Table)"}, + {0x01f, 0xcd0, "Atmel CPU with DSU", "(CPU)"}, + {0x041, 0x1db, "XMC4500 ROM", "(ROM Table)"}, + {0x041, 0x1df, "XMC4700/4800 ROM", "(ROM Table)"}, + {0x041, 0x1ed, "XMC1000 ROM", "(ROM Table)"}, + { + 0x065, + 0x000, + "SHARC+/Blackfin+", + "", + }, + { + 0x070, + 0x440, + "Qualcomm QDSS Component v1", + "(Qualcomm Designed CoreSight Component v1)", + }, + { + 0x0bf, + 0x100, + "Brahma-B53 Debug", + "(Debug Unit)", + }, + { + 0x0bf, + 0x9d3, + "Brahma-B53 PMU", + "(Performance Monitor Unit)", + }, + { + 0x0bf, + 0x4a1, + "Brahma-B53 ROM", + "(ROM Table)", + }, + { + 0x0bf, + 0x721, + "Brahma-B53 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x181, + "Tegra 186 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x202, + "Denver ETM", + "(Denver Embedded Trace)", + }, + { + 0x1eb, + 0x211, + "Tegra 210 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x302, + "Denver Debug", + "(Debug Unit)", + }, + { + 0x1eb, + 0x402, + "Denver PMU", + "(Performance Monitor Unit)", + }, + {0x20, 0x410, "STM32F10 (med)", "(ROM Table)"}, + {0x20, 0x411, "STM32F2", "(ROM Table)"}, + {0x20, 0x412, "STM32F10 (low)", "(ROM Table)"}, + {0x20, 0x413, "STM32F40/41", "(ROM Table)"}, + {0x20, 0x414, "STM32F10 (high)", "(ROM Table)"}, + {0x20, 0x415, "STM32L47/48", "(ROM Table)"}, + {0x20, 0x416, "STM32L1xxx6/8/B", "(ROM Table)"}, + {0x20, 0x417, "STM32L05/06", "(ROM Table)"}, + {0x20, 0x418, "STM32F105xx/107", "(ROM Table)"}, + {0x20, 0x419, "STM32F42/43", "(ROM Table)"}, + {0x20, 0x420, "STM32F10 (med)", "(ROM Table)"}, + {0x20, 0x421, "STM32F446xx", "(ROM Table)"}, + {0x20, 0x422, "STM32FF358/02/03", "(ROM Table)"}, + {0x20, 0x423, "STM32F401xB/C", "(ROM Table)"}, + {0x20, 0x425, "STM32L031/41", "(ROM Table)"}, + {0x20, 0x427, "STM32L1xxxC", "(ROM Table)"}, + {0x20, 0x428, "STM32F10 (high)", "(ROM Table)"}, + {0x20, 0x429, "STM32L1xxx6A/8A/BA", "(ROM Table)"}, + {0x20, 0x430, "STM32F10 (xl)", "(ROM Table)"}, + {0x20, 0x431, "STM32F411xx", "(ROM Table)"}, + {0x20, 0x432, "STM32F373/8", "(ROM Table)"}, + {0x20, 0x433, "STM32F401xD/E", "(ROM Table)"}, + {0x20, 0x434, "STM32F469/79", "(ROM Table)"}, + {0x20, 0x435, "STM32L43/44", "(ROM Table)"}, + {0x20, 0x436, "STM32L1xxxD", "(ROM Table)"}, + {0x20, 0x437, "STM32L1xxxE", "(ROM Table)"}, + {0x20, 0x438, "STM32F303/34/28", "(ROM Table)"}, + {0x20, 0x439, "STM32F301/02/18 ", "(ROM Table)"}, + {0x20, 0x440, "STM32F03/5", "(ROM Table)"}, + {0x20, 0x441, "STM32F412xx", "(ROM Table)"}, + {0x20, 0x442, "STM32F03/9", "(ROM Table)"}, + {0x20, 0x444, "STM32F03xx4", "(ROM Table)"}, + {0x20, 0x445, "STM32F04/7", "(ROM Table)"}, + {0x20, 0x446, "STM32F302/03/98", "(ROM Table)"}, + {0x20, 0x447, "STM32L07/08", "(ROM Table)"}, + {0x20, 0x448, "STM32F070/1/2", "(ROM Table)"}, + {0x20, 0x449, "STM32F74/5", "(ROM Table)"}, + {0x20, 0x450, "STM32H74/5", "(ROM Table)"}, + {0x20, 0x451, "STM32F76/7", "(ROM Table)"}, + {0x20, 0x452, "STM32F72/3", "(ROM Table)"}, + {0x20, 0x457, "STM32L01/2", "(ROM Table)"}, + {0x20, 0x458, "STM32F410xx", "(ROM Table)"}, + {0x20, 0x460, "STM32G07/8", "(ROM Table)"}, + {0x20, 0x461, "STM32L496/A6", "(ROM Table)"}, + {0x20, 0x462, "STM32L45/46", "(ROM Table)"}, + {0x20, 0x463, "STM32F413/23", "(ROM Table)"}, + {0x20, 0x464, "STM32L412/22", "(ROM Table)"}, + {0x20, 0x466, "STM32G03/04", "(ROM Table)"}, + {0x20, 0x468, "STM32G431/41", "(ROM Table)"}, + {0x20, 0x469, "STM32G47/48", "(ROM Table)"}, + {0x20, 0x470, "STM32L4R/S", "(ROM Table)"}, + {0x20, 0x471, "STM32L4P5/Q5", "(ROM Table)"}, + {0x20, 0x479, "STM32G491xx", "(ROM Table)"}, + {0x20, 0x480, "STM32H7A/B", "(ROM Table)"}, + {0x20, 0x495, "STM32WB50/55", "(ROM Table)"}, + {0x20, 0x497, "STM32WLE5xx", "(ROM Table)"}}; + +const char* adi_devarch_desc(uint32_t devarch) { + if(!(devarch & ARM_CS_C9_DEVARCH_PRESENT)) { + return "not present"; + } + + for(unsigned int i = 0; i < ARRAY_SIZE(class0x9_devarch); i++) { + if((devarch & DEVARCH_ID_MASK) == class0x9_devarch[i].arch_id) { + return class0x9_devarch[i].description; + } + } + + return "unknown"; +} + +const struct dap_part_nums* adi_part_num(unsigned int des, unsigned int part) { + static char buf[32]; + static struct dap_part_nums unknown = { + .type = "Unrecognized", + .full = "", + }; + + for(unsigned int i = 0; i < ARRAY_SIZE(dap_part_nums); i++) { + if(dap_part_nums[i].designer_id == des && dap_part_nums[i].part_num == part) { + return &dap_part_nums[i]; + } + } + + snprintf(buf, sizeof(buf), "D:%x P:%x", des, part); + unknown.full = buf; + + return &unknown; +} + +bool adi_get_pidr(AppFSM* const ctx, uint32_t base, pidr_data_t* data) { + uint32_t pidrs[7]; + uint32_t offsets[] = {0xFE0, 0xFE4, 0xFE8, 0xFEC, 0xFD0, 0xFD4, 0xFD8, 0xFDC}; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < COUNT(pidrs); pos++) { + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + offsets[pos], &pidrs[pos]); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return false; + } + } + furi_mutex_release(ctx->swd_mutex); + + data->designer = ((pidrs[4] & 0x0F) << 7) | ((pidrs[2] & 0x07) << 4) | + ((pidrs[1] >> 4) & 0x0F); + data->part = (pidrs[0] & 0xFF) | ((pidrs[1] & 0x0F) << 8); + data->revand = ((pidrs[3] >> 4) & 0x0F); + data->cmod = (pidrs[3] & 0x0F); + data->revision = ((pidrs[2] >> 4) & 0x0F); + data->size = ((pidrs[2] >> 4) & 0x0F); + + return true; +} + +bool adi_get_class(AppFSM* const ctx, uint32_t base, uint8_t* class) { + uint32_t cidrs[4]; + uint32_t offsets[] = {0xFF0, 0xFF4, 0xFF8, 0xFFC}; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < COUNT(cidrs); pos++) { + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + offsets[pos], &cidrs[pos]); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return false; + } + } + furi_mutex_release(ctx->swd_mutex); + + if((cidrs[0] & 0xFF) != 0x0D) { + return false; + } + if((cidrs[1] & 0x0F) != 0x00) { + return false; + } + if((cidrs[2] & 0xFF) != 0x05) { + return false; + } + if((cidrs[3] & 0xFF) != 0xB1) { + return false; + } + + *class = ((cidrs[1] >> 4) & 0x0F); + + return true; +} + +const char* adi_romtable_type(AppFSM* const ctx, uint32_t base) { + pidr_data_t data; + + if(!adi_get_pidr(ctx, base, &data)) { + return "fail"; + } + const struct dap_part_nums* info = adi_part_num(data.designer, data.part); + + return info->type; +} + +const char* adi_romtable_full(AppFSM* const ctx, uint32_t base) { + pidr_data_t data; + + if(!adi_get_pidr(ctx, base, &data)) { + return "fail"; + } + const struct dap_part_nums* info = adi_part_num(data.designer, data.part); + + return info->full; +} + +uint32_t adi_romtable_entry_count(AppFSM* const ctx, uint32_t base) { + uint32_t count = 0; + uint32_t entry = 0; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < 960; pos++) { + uint8_t ret = 0; + for(int tries = 0; tries < 10 && ret != 1; tries++) { + ret = swd_read_memory(ctx, ctx->ap_pos, base + pos * 4, &entry); + } + if(ret != 1) { + DBGS("Read failed"); + break; + } + if(!(entry & 1)) { + break; + } + if(entry & 0x00000FFC) { + break; + } + count++; + } + furi_mutex_release(ctx->swd_mutex); + return count; +} + +uint32_t adi_romtable_get(AppFSM* const ctx, uint32_t base, uint32_t pos) { + uint32_t entry = 0; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + pos * 4, &entry); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return 0; + } + furi_mutex_release(ctx->swd_mutex); + + return base + (entry & 0xFFFFF000); +} + +bool adi_is_romtable(AppFSM* const ctx, uint32_t base) { + uint8_t class = 0; + + if(!adi_get_class(ctx, base, &class)) { + return false; + } + + if(class != CIDR_CLASS_ROMTABLE) { + return false; + } + + return true; +} diff --git a/applications/plugins/swd_probe/adi.h b/applications/plugins/swd_probe/adi.h new file mode 100644 index 0000000000..bade7736ab --- /dev/null +++ b/applications/plugins/swd_probe/adi.h @@ -0,0 +1,34 @@ + +#ifndef __ADI_H__ +#define __ADI_H__ + +#include "swd_probe_app.h" + +#define ARM_ID 0x23B + +#define ARCH_ID(architect, archid) ((architect) << 21) | (archid) + +#define BIT(nr) (1UL << (nr)) +#define ARM_CS_C9_DEVARCH_PRESENT BIT(20) +#define ARM_CS_C9_DEVARCH_ARCHITECT_MASK (0xFFE00000) +#define ARM_CS_C9_DEVARCH_ARCHID_MASK (0x0000FFFF) +#define DEVARCH_ID_MASK (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK) + +typedef struct { + uint16_t designer; + uint16_t part; + uint8_t revision; + uint8_t cmod; + uint8_t revand; + uint8_t size; +} pidr_data_t; + +typedef enum { CIDR_CLASS_ROMTABLE = 0x01, CIDR_CLASS_CORESIGHT = 0x09 } cidr_classes_t; + +uint32_t adi_romtable_entry_count(AppFSM* const ctx, uint32_t base); +uint32_t adi_romtable_get(AppFSM* const ctx, uint32_t base, uint32_t pos); +bool adi_is_romtable(AppFSM* const ctx, uint32_t base); +const char* adi_romtable_type(AppFSM* const ctx, uint32_t base); +const char* adi_romtable_full(AppFSM* const ctx, uint32_t base); + +#endif diff --git a/applications/plugins/swd_probe/application.fam b/applications/plugins/swd_probe/application.fam new file mode 100644 index 0000000000..64140d1301 --- /dev/null +++ b/applications/plugins/swd_probe/application.fam @@ -0,0 +1,13 @@ +App( + appid="swd_probe", + name="SWD Probe", + apptype=FlipperAppType.PLUGIN, + entry_point="swd_probe_app_main", + cdefines=["APP_SWD_PROBE"], + requires=["notification", "gui", "storage", "dialogs", "cli"], + stack_size=2 * 1024, + order=10, + fap_icon="icons/app.png", + fap_category="Tools", + fap_icon_assets="icons" +) diff --git a/applications/plugins/swd_probe/icons/ButtonDown_7x4.png b/applications/plugins/swd_probe/icons/ButtonDown_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..2954bb6a67d1c23c0bb5d765e8d2aa04b9b5adec GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J9|(o>FH3<^BV2haYO z-y5_sM4;GPjq%Ck6>60csmUj6EiNa>ORduPH4*)h!w|e3sE@(Z)z4*}Q$iC10Gods AV*mgE literal 0 HcmV?d00001 diff --git a/applications/plugins/swd_probe/icons/ButtonUp_7x4.png b/applications/plugins/swd_probe/icons/ButtonUp_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..1be79328b40a93297a5609756328406565c437c0 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J8d-yTOk1_O>mFaFD) zeWb+ZHz{mGZZ1QpXe09^4tcYT#4oe=UbmGC^A-KE*|F&zP#=S*tDnm{r-UX30HgpM AM*si- literal 0 HcmV?d00001 diff --git a/applications/plugins/swd_probe/icons/app.png b/applications/plugins/swd_probe/icons/app.png new file mode 100644 index 0000000000000000000000000000000000000000..6949ce78d11d5aa0a40b3cf5253e0e297aab47ad GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4u_bxCy8vk*`02d69!PN(ctjR6 zFz_7#VaBQ2e9}Nc_7YEDSN7*jtc=XO_pYWl0)-qrT^vIsE^qBKf4aTa()7BevL9RXp+soH$fK*4BF z7sn8Z%f0;vc^eFPm~)Q^Wqy}moBgCBgtd|Diu`fUl$SgUSaXvl{^#fIx+ax-f7<3f z-a(qKYfZ04oquest;Ep5VKn*7oHXV&CRGz^7;nBaIKXL8{2=SkWkwE#2tRl4D<^=~ OFnGH9xvX 126) { + return ""; + } + + /* index is zero based */ + id--; + + if(bank >= 14 || jep106[bank][id] == 0) return ""; + + return jep106[bank][id]; +} diff --git a/applications/plugins/swd_probe/jep106.h b/applications/plugins/swd_probe/jep106.h new file mode 100644 index 0000000000..17c87feaa1 --- /dev/null +++ b/applications/plugins/swd_probe/jep106.h @@ -0,0 +1,26 @@ +/* https://github.com/openocd-org/openocd/blob/master/src/helper/ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2015 Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + ***************************************************************************/ + +#ifndef OPENOCD_HELPER_JEP106_H +#define OPENOCD_HELPER_JEP106_H + +/** + * Get the manufacturer name associated with a JEP106 ID. + * @param bank The bank (number of continuation codes) of the manufacturer ID. + * @param id The 7-bit manufacturer ID (i.e. with parity stripped). + * @return A pointer to static const storage containing the name of the + * manufacturer associated with bank and id, or one of the strings + * "" and "". + */ +const char* jep106_table_manufacturer(unsigned int bank, unsigned int id); + +static inline const char* jep106_manufacturer(unsigned int manufacturer) { + return jep106_table_manufacturer(manufacturer >> 7, manufacturer & 0x7f); +} + +#endif /* OPENOCD_HELPER_JEP106_H */ diff --git a/applications/plugins/swd_probe/jep106.inc b/applications/plugins/swd_probe/jep106.inc new file mode 100644 index 0000000000..3adc131be8 --- /dev/null +++ b/applications/plugins/swd_probe/jep106.inc @@ -0,0 +1,1791 @@ +/* https://github.com/openocd-org/openocd/blob/master/src/helper/ */ + +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * The manufacturer's standard identification code list appears in JEP106. + * Copyright (c) 2022 JEDEC. All rights reserved. + * + * JEP106 is regularly updated. For the current manufacturer's standard + * identification code list, please visit the JEDEC website at www.jedec.org . + */ + +/* This file is aligned to revision JEP106BF.01 October 2022. */ + +[0][0x01 - 1] = "AMD", +[0][0x02 - 1] = "AMI", +[0][0x03 - 1] = "Fairchild", +[0][0x04 - 1] = "Fujitsu", +[0][0x05 - 1] = "GTE", +[0][0x06 - 1] = "Harris", +[0][0x07 - 1] = "Hitachi", +[0][0x08 - 1] = "Inmos", +[0][0x09 - 1] = "Intel", +[0][0x0a - 1] = "I.T.T.", +[0][0x0b - 1] = "Intersil", +[0][0x0c - 1] = "Monolithic Memories", +[0][0x0d - 1] = "Mostek", +[0][0x0e - 1] = "Freescale (Motorola)", +[0][0x0f - 1] = "National", +[0][0x10 - 1] = "NEC", +[0][0x11 - 1] = "RCA", +[0][0x12 - 1] = "Raytheon", +[0][0x13 - 1] = "Conexant (Rockwell)", +[0][0x14 - 1] = "Seeq", +[0][0x15 - 1] = "NXP (Philips)", +[0][0x16 - 1] = "Synertek", +[0][0x17 - 1] = "Texas Instruments", +[0][0x18 - 1] = "Kioxia Corporation", +[0][0x19 - 1] = "Xicor", +[0][0x1a - 1] = "Zilog", +[0][0x1b - 1] = "Eurotechnique", +[0][0x1c - 1] = "Mitsubishi", +[0][0x1d - 1] = "Lucent (AT&T)", +[0][0x1e - 1] = "Exel", +[0][0x1f - 1] = "Atmel", +[0][0x20 - 1] = "STMicroelectronics", +[0][0x21 - 1] = "Lattice Semi.", +[0][0x22 - 1] = "NCR", +[0][0x23 - 1] = "Wafer Scale Integration", +[0][0x24 - 1] = "IBM", +[0][0x25 - 1] = "Tristar", +[0][0x26 - 1] = "Visic", +[0][0x27 - 1] = "Intl. CMOS Technology", +[0][0x28 - 1] = "SSSI", +[0][0x29 - 1] = "Microchip Technology", +[0][0x2a - 1] = "Ricoh Ltd", +[0][0x2b - 1] = "VLSI", +[0][0x2c - 1] = "Micron Technology", +[0][0x2d - 1] = "SK Hynix", +[0][0x2e - 1] = "OKI Semiconductor", +[0][0x2f - 1] = "ACTEL", +[0][0x30 - 1] = "Sharp", +[0][0x31 - 1] = "Catalyst", +[0][0x32 - 1] = "Panasonic", +[0][0x33 - 1] = "IDT", +[0][0x34 - 1] = "Cypress", +[0][0x35 - 1] = "DEC", +[0][0x36 - 1] = "LSI Logic", +[0][0x37 - 1] = "Zarlink (Plessey)", +[0][0x38 - 1] = "UTMC", +[0][0x39 - 1] = "Thinking Machine", +[0][0x3a - 1] = "Thomson CSF", +[0][0x3b - 1] = "Integrated CMOS (Vertex)", +[0][0x3c - 1] = "Honeywell", +[0][0x3d - 1] = "Tektronix", +[0][0x3e - 1] = "Oracle Corporation", +[0][0x3f - 1] = "Silicon Storage Technology", +[0][0x40 - 1] = "ProMos/Mosel Vitelic", +[0][0x41 - 1] = "Infineon (Siemens)", +[0][0x42 - 1] = "Macronix", +[0][0x43 - 1] = "Xerox", +[0][0x44 - 1] = "Plus Logic", +[0][0x45 - 1] = "Western Digital Technologies Inc", +[0][0x46 - 1] = "Elan Circuit Tech.", +[0][0x47 - 1] = "European Silicon Str.", +[0][0x48 - 1] = "Apple Computer", +[0][0x49 - 1] = "Xilinx", +[0][0x4a - 1] = "Compaq", +[0][0x4b - 1] = "Protocol Engines", +[0][0x4c - 1] = "SCI", +[0][0x4d - 1] = "Seiko Instruments", +[0][0x4e - 1] = "Samsung", +[0][0x4f - 1] = "I3 Design System", +[0][0x50 - 1] = "Klic", +[0][0x51 - 1] = "Crosspoint Solutions", +[0][0x52 - 1] = "Alliance Memory Inc", +[0][0x53 - 1] = "Tandem", +[0][0x54 - 1] = "Hewlett-Packard", +[0][0x55 - 1] = "Integrated Silicon Solutions", +[0][0x56 - 1] = "Brooktree", +[0][0x57 - 1] = "New Media", +[0][0x58 - 1] = "MHS Electronic", +[0][0x59 - 1] = "Performance Semi.", +[0][0x5a - 1] = "Winbond Electronic", +[0][0x5b - 1] = "Kawasaki Steel", +[0][0x5c - 1] = "Bright Micro", +[0][0x5d - 1] = "TECMAR", +[0][0x5e - 1] = "Exar", +[0][0x5f - 1] = "PCMCIA", +[0][0x60 - 1] = "LG Semi (Goldstar)", +[0][0x61 - 1] = "Northern Telecom", +[0][0x62 - 1] = "Sanyo", +[0][0x63 - 1] = "Array Microsystems", +[0][0x64 - 1] = "Crystal Semiconductor", +[0][0x65 - 1] = "Analog Devices", +[0][0x66 - 1] = "PMC-Sierra", +[0][0x67 - 1] = "Asparix", +[0][0x68 - 1] = "Convex Computer", +[0][0x69 - 1] = "Quality Semiconductor", +[0][0x6a - 1] = "Nimbus Technology", +[0][0x6b - 1] = "Transwitch", +[0][0x6c - 1] = "Micronas (ITT Intermetall)", +[0][0x6d - 1] = "Cannon", +[0][0x6e - 1] = "Altera", +[0][0x6f - 1] = "NEXCOM", +[0][0x70 - 1] = "Qualcomm", +[0][0x71 - 1] = "Sony", +[0][0x72 - 1] = "Cray Research", +[0][0x73 - 1] = "AMS(Austria Micro)", +[0][0x74 - 1] = "Vitesse", +[0][0x75 - 1] = "Aster Electronics", +[0][0x76 - 1] = "Bay Networks (Synoptic)", +[0][0x77 - 1] = "Zentrum/ZMD", +[0][0x78 - 1] = "TRW", +[0][0x79 - 1] = "Thesys", +[0][0x7a - 1] = "Solbourne Computer", +[0][0x7b - 1] = "Allied-Signal", +[0][0x7c - 1] = "Dialog Semiconductor", +[0][0x7d - 1] = "Media Vision", +[0][0x7e - 1] = "Numonyx Corporation", +[1][0x01 - 1] = "Cirrus Logic", +[1][0x02 - 1] = "National Instruments", +[1][0x03 - 1] = "ILC Data Device", +[1][0x04 - 1] = "Alcatel Mietec", +[1][0x05 - 1] = "Micro Linear", +[1][0x06 - 1] = "Univ. of NC", +[1][0x07 - 1] = "JTAG Technologies", +[1][0x08 - 1] = "BAE Systems (Loral)", +[1][0x09 - 1] = "Nchip", +[1][0x0a - 1] = "Galileo Tech", +[1][0x0b - 1] = "Bestlink Systems", +[1][0x0c - 1] = "Graychip", +[1][0x0d - 1] = "GENNUM", +[1][0x0e - 1] = "Imagination Technologies Limited", +[1][0x0f - 1] = "Robert Bosch", +[1][0x10 - 1] = "Chip Express", +[1][0x11 - 1] = "DATARAM", +[1][0x12 - 1] = "United Microelectronics Corp", +[1][0x13 - 1] = "TCSI", +[1][0x14 - 1] = "Smart Modular", +[1][0x15 - 1] = "Hughes Aircraft", +[1][0x16 - 1] = "Lanstar Semiconductor", +[1][0x17 - 1] = "Qlogic", +[1][0x18 - 1] = "Kingston", +[1][0x19 - 1] = "Music Semi", +[1][0x1a - 1] = "Ericsson Components", +[1][0x1b - 1] = "SpaSE", +[1][0x1c - 1] = "Eon Silicon Devices", +[1][0x1d - 1] = "Integrated Silicon Solution (ISSI)", +[1][0x1e - 1] = "DoD", +[1][0x1f - 1] = "Integ. Memories Tech.", +[1][0x20 - 1] = "Corollary Inc", +[1][0x21 - 1] = "Dallas Semiconductor", +[1][0x22 - 1] = "Omnivision", +[1][0x23 - 1] = "EIV(Switzerland)", +[1][0x24 - 1] = "Novatel Wireless", +[1][0x25 - 1] = "Zarlink (Mitel)", +[1][0x26 - 1] = "Clearpoint", +[1][0x27 - 1] = "Cabletron", +[1][0x28 - 1] = "STEC (Silicon Tech)", +[1][0x29 - 1] = "Vanguard", +[1][0x2a - 1] = "Hagiwara Sys-Com", +[1][0x2b - 1] = "Vantis", +[1][0x2c - 1] = "Celestica", +[1][0x2d - 1] = "Century", +[1][0x2e - 1] = "Hal Computers", +[1][0x2f - 1] = "Rohm Company Ltd", +[1][0x30 - 1] = "Juniper Networks", +[1][0x31 - 1] = "Libit Signal Processing", +[1][0x32 - 1] = "Mushkin Enhanced Memory", +[1][0x33 - 1] = "Tundra Semiconductor", +[1][0x34 - 1] = "Adaptec Inc", +[1][0x35 - 1] = "LightSpeed Semi.", +[1][0x36 - 1] = "ZSP Corp", +[1][0x37 - 1] = "AMIC Technology", +[1][0x38 - 1] = "Adobe Systems", +[1][0x39 - 1] = "Dynachip", +[1][0x3a - 1] = "PNY Technologies Inc", +[1][0x3b - 1] = "Newport Digital", +[1][0x3c - 1] = "MMC Networks", +[1][0x3d - 1] = "T Square", +[1][0x3e - 1] = "Seiko Epson", +[1][0x3f - 1] = "Broadcom", +[1][0x40 - 1] = "Viking Components", +[1][0x41 - 1] = "V3 Semiconductor", +[1][0x42 - 1] = "Flextronics (Orbit Semiconductor)", +[1][0x43 - 1] = "Suwa Electronics", +[1][0x44 - 1] = "Transmeta", +[1][0x45 - 1] = "Micron CMS", +[1][0x46 - 1] = "American Computer & Digital Components Inc", +[1][0x47 - 1] = "Enhance 3000 Inc", +[1][0x48 - 1] = "Tower Semiconductor", +[1][0x49 - 1] = "CPU Design", +[1][0x4a - 1] = "Price Point", +[1][0x4b - 1] = "Maxim Integrated Product", +[1][0x4c - 1] = "Tellabs", +[1][0x4d - 1] = "Centaur Technology", +[1][0x4e - 1] = "Unigen Corporation", +[1][0x4f - 1] = "Transcend Information", +[1][0x50 - 1] = "Memory Card Technology", +[1][0x51 - 1] = "CKD Corporation Ltd", +[1][0x52 - 1] = "Capital Instruments Inc", +[1][0x53 - 1] = "Aica Kogyo Ltd", +[1][0x54 - 1] = "Linvex Technology", +[1][0x55 - 1] = "MSC Vertriebs GmbH", +[1][0x56 - 1] = "AKM Company Ltd", +[1][0x57 - 1] = "Dynamem Inc", +[1][0x58 - 1] = "NERA ASA", +[1][0x59 - 1] = "GSI Technology", +[1][0x5a - 1] = "Dane-Elec (C Memory)", +[1][0x5b - 1] = "Acorn Computers", +[1][0x5c - 1] = "Lara Technology", +[1][0x5d - 1] = "Oak Technology Inc", +[1][0x5e - 1] = "Itec Memory", +[1][0x5f - 1] = "Tanisys Technology", +[1][0x60 - 1] = "Truevision", +[1][0x61 - 1] = "Wintec Industries", +[1][0x62 - 1] = "Super PC Memory", +[1][0x63 - 1] = "MGV Memory", +[1][0x64 - 1] = "Galvantech", +[1][0x65 - 1] = "Gadzoox Networks", +[1][0x66 - 1] = "Multi Dimensional Cons.", +[1][0x67 - 1] = "GateField", +[1][0x68 - 1] = "Integrated Memory System", +[1][0x69 - 1] = "Triscend", +[1][0x6a - 1] = "XaQti", +[1][0x6b - 1] = "Goldenram", +[1][0x6c - 1] = "Clear Logic", +[1][0x6d - 1] = "Cimaron Communications", +[1][0x6e - 1] = "Nippon Steel Semi. Corp", +[1][0x6f - 1] = "Advantage Memory", +[1][0x70 - 1] = "AMCC", +[1][0x71 - 1] = "LeCroy", +[1][0x72 - 1] = "Yamaha Corporation", +[1][0x73 - 1] = "Digital Microwave", +[1][0x74 - 1] = "NetLogic Microsystems", +[1][0x75 - 1] = "MIMOS Semiconductor", +[1][0x76 - 1] = "Advanced Fibre", +[1][0x77 - 1] = "BF Goodrich Data.", +[1][0x78 - 1] = "Epigram", +[1][0x79 - 1] = "Acbel Polytech Inc", +[1][0x7a - 1] = "Apacer Technology", +[1][0x7b - 1] = "Admor Memory", +[1][0x7c - 1] = "FOXCONN", +[1][0x7d - 1] = "Quadratics Superconductor", +[1][0x7e - 1] = "3COM", +[2][0x01 - 1] = "Camintonn Corporation", +[2][0x02 - 1] = "ISOA Incorporated", +[2][0x03 - 1] = "Agate Semiconductor", +[2][0x04 - 1] = "ADMtek Incorporated", +[2][0x05 - 1] = "HYPERTEC", +[2][0x06 - 1] = "Adhoc Technologies", +[2][0x07 - 1] = "MOSAID Technologies", +[2][0x08 - 1] = "Ardent Technologies", +[2][0x09 - 1] = "Switchcore", +[2][0x0a - 1] = "Cisco Systems Inc", +[2][0x0b - 1] = "Allayer Technologies", +[2][0x0c - 1] = "WorkX AG (Wichman)", +[2][0x0d - 1] = "Oasis Semiconductor", +[2][0x0e - 1] = "Novanet Semiconductor", +[2][0x0f - 1] = "E-M Solutions", +[2][0x10 - 1] = "Power General", +[2][0x11 - 1] = "Advanced Hardware Arch.", +[2][0x12 - 1] = "Inova Semiconductors GmbH", +[2][0x13 - 1] = "Telocity", +[2][0x14 - 1] = "Delkin Devices", +[2][0x15 - 1] = "Symagery Microsystems", +[2][0x16 - 1] = "C-Port Corporation", +[2][0x17 - 1] = "SiberCore Technologies", +[2][0x18 - 1] = "Southland Microsystems", +[2][0x19 - 1] = "Malleable Technologies", +[2][0x1a - 1] = "Kendin Communications", +[2][0x1b - 1] = "Great Technology Microcomputer", +[2][0x1c - 1] = "Sanmina Corporation", +[2][0x1d - 1] = "HADCO Corporation", +[2][0x1e - 1] = "Corsair", +[2][0x1f - 1] = "Actrans System Inc", +[2][0x20 - 1] = "ALPHA Technologies", +[2][0x21 - 1] = "Silicon Laboratories Inc (Cygnal)", +[2][0x22 - 1] = "Artesyn Technologies", +[2][0x23 - 1] = "Align Manufacturing", +[2][0x24 - 1] = "Peregrine Semiconductor", +[2][0x25 - 1] = "Chameleon Systems", +[2][0x26 - 1] = "Aplus Flash Technology", +[2][0x27 - 1] = "MIPS Technologies", +[2][0x28 - 1] = "Chrysalis ITS", +[2][0x29 - 1] = "ADTEC Corporation", +[2][0x2a - 1] = "Kentron Technologies", +[2][0x2b - 1] = "Win Technologies", +[2][0x2c - 1] = "Tezzaron Semiconductor", +[2][0x2d - 1] = "Extreme Packet Devices", +[2][0x2e - 1] = "RF Micro Devices", +[2][0x2f - 1] = "Siemens AG", +[2][0x30 - 1] = "Sarnoff Corporation", +[2][0x31 - 1] = "Itautec SA", +[2][0x32 - 1] = "Radiata Inc", +[2][0x33 - 1] = "Benchmark Elect. (AVEX)", +[2][0x34 - 1] = "Legend", +[2][0x35 - 1] = "SpecTek Incorporated", +[2][0x36 - 1] = "Hi/fn", +[2][0x37 - 1] = "Enikia Incorporated", +[2][0x38 - 1] = "SwitchOn Networks", +[2][0x39 - 1] = "AANetcom Incorporated", +[2][0x3a - 1] = "Micro Memory Bank", +[2][0x3b - 1] = "ESS Technology", +[2][0x3c - 1] = "Virata Corporation", +[2][0x3d - 1] = "Excess Bandwidth", +[2][0x3e - 1] = "West Bay Semiconductor", +[2][0x3f - 1] = "DSP Group", +[2][0x40 - 1] = "Newport Communications", +[2][0x41 - 1] = "Chip2Chip Incorporated", +[2][0x42 - 1] = "Phobos Corporation", +[2][0x43 - 1] = "Intellitech Corporation", +[2][0x44 - 1] = "Nordic VLSI ASA", +[2][0x45 - 1] = "Ishoni Networks", +[2][0x46 - 1] = "Silicon Spice", +[2][0x47 - 1] = "Alchemy Semiconductor", +[2][0x48 - 1] = "Agilent Technologies", +[2][0x49 - 1] = "Centillium Communications", +[2][0x4a - 1] = "W.L. Gore", +[2][0x4b - 1] = "HanBit Electronics", +[2][0x4c - 1] = "GlobeSpan", +[2][0x4d - 1] = "Element 14", +[2][0x4e - 1] = "Pycon", +[2][0x4f - 1] = "Saifun Semiconductors", +[2][0x50 - 1] = "Sibyte Incorporated", +[2][0x51 - 1] = "MetaLink Technologies", +[2][0x52 - 1] = "Feiya Technology", +[2][0x53 - 1] = "I & C Technology", +[2][0x54 - 1] = "Shikatronics", +[2][0x55 - 1] = "Elektrobit", +[2][0x56 - 1] = "Megic", +[2][0x57 - 1] = "Com-Tier", +[2][0x58 - 1] = "Malaysia Micro Solutions", +[2][0x59 - 1] = "Hyperchip", +[2][0x5a - 1] = "Gemstone Communications", +[2][0x5b - 1] = "Anadigm (Anadyne)", +[2][0x5c - 1] = "3ParData", +[2][0x5d - 1] = "Mellanox Technologies", +[2][0x5e - 1] = "Tenx Technologies", +[2][0x5f - 1] = "Helix AG", +[2][0x60 - 1] = "Domosys", +[2][0x61 - 1] = "Skyup Technology", +[2][0x62 - 1] = "HiNT Corporation", +[2][0x63 - 1] = "Chiaro", +[2][0x64 - 1] = "MDT Technologies GmbH", +[2][0x65 - 1] = "Exbit Technology A/S", +[2][0x66 - 1] = "Integrated Technology Express", +[2][0x67 - 1] = "AVED Memory", +[2][0x68 - 1] = "Legerity", +[2][0x69 - 1] = "Jasmine Networks", +[2][0x6a - 1] = "Caspian Networks", +[2][0x6b - 1] = "nCUBE", +[2][0x6c - 1] = "Silicon Access Networks", +[2][0x6d - 1] = "FDK Corporation", +[2][0x6e - 1] = "High Bandwidth Access", +[2][0x6f - 1] = "MultiLink Technology", +[2][0x70 - 1] = "BRECIS", +[2][0x71 - 1] = "World Wide Packets", +[2][0x72 - 1] = "APW", +[2][0x73 - 1] = "Chicory Systems", +[2][0x74 - 1] = "Xstream Logic", +[2][0x75 - 1] = "Fast-Chip", +[2][0x76 - 1] = "Zucotto Wireless", +[2][0x77 - 1] = "Realchip", +[2][0x78 - 1] = "Galaxy Power", +[2][0x79 - 1] = "eSilicon", +[2][0x7a - 1] = "Morphics Technology", +[2][0x7b - 1] = "Accelerant Networks", +[2][0x7c - 1] = "Silicon Wave", +[2][0x7d - 1] = "SandCraft", +[2][0x7e - 1] = "Elpida", +[3][0x01 - 1] = "Solectron", +[3][0x02 - 1] = "Optosys Technologies", +[3][0x03 - 1] = "Buffalo (Formerly Melco)", +[3][0x04 - 1] = "TriMedia Technologies", +[3][0x05 - 1] = "Cyan Technologies", +[3][0x06 - 1] = "Global Locate", +[3][0x07 - 1] = "Optillion", +[3][0x08 - 1] = "Terago Communications", +[3][0x09 - 1] = "Ikanos Communications", +[3][0x0a - 1] = "Princeton Technology", +[3][0x0b - 1] = "Nanya Technology", +[3][0x0c - 1] = "Elite Flash Storage", +[3][0x0d - 1] = "Mysticom", +[3][0x0e - 1] = "LightSand Communications", +[3][0x0f - 1] = "ATI Technologies", +[3][0x10 - 1] = "Agere Systems", +[3][0x11 - 1] = "NeoMagic", +[3][0x12 - 1] = "AuroraNetics", +[3][0x13 - 1] = "Golden Empire", +[3][0x14 - 1] = "Mushkin", +[3][0x15 - 1] = "Tioga Technologies", +[3][0x16 - 1] = "Netlist", +[3][0x17 - 1] = "TeraLogic", +[3][0x18 - 1] = "Cicada Semiconductor", +[3][0x19 - 1] = "Centon Electronics", +[3][0x1a - 1] = "Tyco Electronics", +[3][0x1b - 1] = "Magis Works", +[3][0x1c - 1] = "Zettacom", +[3][0x1d - 1] = "Cogency Semiconductor", +[3][0x1e - 1] = "Chipcon AS", +[3][0x1f - 1] = "Aspex Technology", +[3][0x20 - 1] = "F5 Networks", +[3][0x21 - 1] = "Programmable Silicon Solutions", +[3][0x22 - 1] = "ChipWrights", +[3][0x23 - 1] = "Acorn Networks", +[3][0x24 - 1] = "Quicklogic", +[3][0x25 - 1] = "Kingmax Semiconductor", +[3][0x26 - 1] = "BOPS", +[3][0x27 - 1] = "Flasys", +[3][0x28 - 1] = "BitBlitz Communications", +[3][0x29 - 1] = "eMemory Technology", +[3][0x2a - 1] = "Procket Networks", +[3][0x2b - 1] = "Purple Ray", +[3][0x2c - 1] = "Trebia Networks", +[3][0x2d - 1] = "Delta Electronics", +[3][0x2e - 1] = "Onex Communications", +[3][0x2f - 1] = "Ample Communications", +[3][0x30 - 1] = "Memory Experts Intl", +[3][0x31 - 1] = "Astute Networks", +[3][0x32 - 1] = "Azanda Network Devices", +[3][0x33 - 1] = "Dibcom", +[3][0x34 - 1] = "Tekmos", +[3][0x35 - 1] = "API NetWorks", +[3][0x36 - 1] = "Bay Microsystems", +[3][0x37 - 1] = "Firecron Ltd", +[3][0x38 - 1] = "Resonext Communications", +[3][0x39 - 1] = "Tachys Technologies", +[3][0x3a - 1] = "Equator Technology", +[3][0x3b - 1] = "Concept Computer", +[3][0x3c - 1] = "SILCOM", +[3][0x3d - 1] = "3Dlabs", +[3][0x3e - 1] = "c't Magazine", +[3][0x3f - 1] = "Sanera Systems", +[3][0x40 - 1] = "Silicon Packets", +[3][0x41 - 1] = "Viasystems Group", +[3][0x42 - 1] = "Simtek", +[3][0x43 - 1] = "Semicon Devices Singapore", +[3][0x44 - 1] = "Satron Handelsges", +[3][0x45 - 1] = "Improv Systems", +[3][0x46 - 1] = "INDUSYS GmbH", +[3][0x47 - 1] = "Corrent", +[3][0x48 - 1] = "Infrant Technologies", +[3][0x49 - 1] = "Ritek Corp", +[3][0x4a - 1] = "empowerTel Networks", +[3][0x4b - 1] = "Hypertec", +[3][0x4c - 1] = "Cavium Networks", +[3][0x4d - 1] = "PLX Technology", +[3][0x4e - 1] = "Massana Design", +[3][0x4f - 1] = "Intrinsity", +[3][0x50 - 1] = "Valence Semiconductor", +[3][0x51 - 1] = "Terawave Communications", +[3][0x52 - 1] = "IceFyre Semiconductor", +[3][0x53 - 1] = "Primarion", +[3][0x54 - 1] = "Picochip Designs Ltd", +[3][0x55 - 1] = "Silverback Systems", +[3][0x56 - 1] = "Jade Star Technologies", +[3][0x57 - 1] = "Pijnenburg Securealink", +[3][0x58 - 1] = "takeMS - Ultron AG", +[3][0x59 - 1] = "Cambridge Silicon Radio", +[3][0x5a - 1] = "Swissbit", +[3][0x5b - 1] = "Nazomi Communications", +[3][0x5c - 1] = "eWave System", +[3][0x5d - 1] = "Rockwell Collins", +[3][0x5e - 1] = "Picocel Co Ltd (Paion)", +[3][0x5f - 1] = "Alphamosaic Ltd", +[3][0x60 - 1] = "Sandburst", +[3][0x61 - 1] = "SiCon Video", +[3][0x62 - 1] = "NanoAmp Solutions", +[3][0x63 - 1] = "Ericsson Technology", +[3][0x64 - 1] = "PrairieComm", +[3][0x65 - 1] = "Mitac International", +[3][0x66 - 1] = "Layer N Networks", +[3][0x67 - 1] = "MtekVision (Atsana)", +[3][0x68 - 1] = "Allegro Networks", +[3][0x69 - 1] = "Marvell Semiconductors", +[3][0x6a - 1] = "Netergy Microelectronic", +[3][0x6b - 1] = "NVIDIA", +[3][0x6c - 1] = "Internet Machines", +[3][0x6d - 1] = "Memorysolution GmbH", +[3][0x6e - 1] = "Litchfield Communication", +[3][0x6f - 1] = "Accton Technology", +[3][0x70 - 1] = "Teradiant Networks", +[3][0x71 - 1] = "Scaleo Chip", +[3][0x72 - 1] = "Cortina Systems", +[3][0x73 - 1] = "RAM Components", +[3][0x74 - 1] = "Raqia Networks", +[3][0x75 - 1] = "ClearSpeed", +[3][0x76 - 1] = "Matsushita Battery", +[3][0x77 - 1] = "Xelerated", +[3][0x78 - 1] = "SimpleTech", +[3][0x79 - 1] = "Utron Technology", +[3][0x7a - 1] = "Astec International", +[3][0x7b - 1] = "AVM gmbH", +[3][0x7c - 1] = "Redux Communications", +[3][0x7d - 1] = "Dot Hill Systems", +[3][0x7e - 1] = "TeraChip", +[4][0x01 - 1] = "T-RAM Incorporated", +[4][0x02 - 1] = "Innovics Wireless", +[4][0x03 - 1] = "Teknovus", +[4][0x04 - 1] = "KeyEye Communications", +[4][0x05 - 1] = "Runcom Technologies", +[4][0x06 - 1] = "RedSwitch", +[4][0x07 - 1] = "Dotcast", +[4][0x08 - 1] = "Silicon Mountain Memory", +[4][0x09 - 1] = "Signia Technologies", +[4][0x0a - 1] = "Pixim", +[4][0x0b - 1] = "Galazar Networks", +[4][0x0c - 1] = "White Electronic Designs", +[4][0x0d - 1] = "Patriot Scientific", +[4][0x0e - 1] = "Neoaxiom Corporation", +[4][0x0f - 1] = "3Y Power Technology", +[4][0x10 - 1] = "Scaleo Chip", +[4][0x11 - 1] = "Potentia Power Systems", +[4][0x12 - 1] = "C-guys Incorporated", +[4][0x13 - 1] = "Digital Communications Technology Inc", +[4][0x14 - 1] = "Silicon-Based Technology", +[4][0x15 - 1] = "Fulcrum Microsystems", +[4][0x16 - 1] = "Positivo Informatica Ltd", +[4][0x17 - 1] = "XIOtech Corporation", +[4][0x18 - 1] = "PortalPlayer", +[4][0x19 - 1] = "Zhiying Software", +[4][0x1a - 1] = "ParkerVision Inc", +[4][0x1b - 1] = "Phonex Broadband", +[4][0x1c - 1] = "Skyworks Solutions", +[4][0x1d - 1] = "Entropic Communications", +[4][0x1e - 1] = "I'M Intelligent Memory Ltd", +[4][0x1f - 1] = "Zensys A/S", +[4][0x20 - 1] = "Legend Silicon Corp", +[4][0x21 - 1] = "Sci-worx GmbH", +[4][0x22 - 1] = "SMSC (Standard Microsystems)", +[4][0x23 - 1] = "Renesas Electronics", +[4][0x24 - 1] = "Raza Microelectronics", +[4][0x25 - 1] = "Phyworks", +[4][0x26 - 1] = "MediaTek", +[4][0x27 - 1] = "Non-cents Productions", +[4][0x28 - 1] = "US Modular", +[4][0x29 - 1] = "Wintegra Ltd", +[4][0x2a - 1] = "Mathstar", +[4][0x2b - 1] = "StarCore", +[4][0x2c - 1] = "Oplus Technologies", +[4][0x2d - 1] = "Mindspeed", +[4][0x2e - 1] = "Just Young Computer", +[4][0x2f - 1] = "Radia Communications", +[4][0x30 - 1] = "OCZ", +[4][0x31 - 1] = "Emuzed", +[4][0x32 - 1] = "LOGIC Devices", +[4][0x33 - 1] = "Inphi Corporation", +[4][0x34 - 1] = "Quake Technologies", +[4][0x35 - 1] = "Vixel", +[4][0x36 - 1] = "SolusTek", +[4][0x37 - 1] = "Kongsberg Maritime", +[4][0x38 - 1] = "Faraday Technology", +[4][0x39 - 1] = "Altium Ltd", +[4][0x3a - 1] = "Insyte", +[4][0x3b - 1] = "ARM Ltd", +[4][0x3c - 1] = "DigiVision", +[4][0x3d - 1] = "Vativ Technologies", +[4][0x3e - 1] = "Endicott Interconnect Technologies", +[4][0x3f - 1] = "Pericom", +[4][0x40 - 1] = "Bandspeed", +[4][0x41 - 1] = "LeWiz Communications", +[4][0x42 - 1] = "CPU Technology", +[4][0x43 - 1] = "Ramaxel Technology", +[4][0x44 - 1] = "DSP Group", +[4][0x45 - 1] = "Axis Communications", +[4][0x46 - 1] = "Legacy Electronics", +[4][0x47 - 1] = "Chrontel", +[4][0x48 - 1] = "Powerchip Semiconductor", +[4][0x49 - 1] = "MobilEye Technologies", +[4][0x4a - 1] = "Excel Semiconductor", +[4][0x4b - 1] = "A-DATA Technology", +[4][0x4c - 1] = "VirtualDigm", +[4][0x4d - 1] = "G Skill Intl", +[4][0x4e - 1] = "Quanta Computer", +[4][0x4f - 1] = "Yield Microelectronics", +[4][0x50 - 1] = "Afa Technologies", +[4][0x51 - 1] = "KINGBOX Technology Co Ltd", +[4][0x52 - 1] = "Ceva", +[4][0x53 - 1] = "iStor Networks", +[4][0x54 - 1] = "Advance Modules", +[4][0x55 - 1] = "Microsoft", +[4][0x56 - 1] = "Open-Silicon", +[4][0x57 - 1] = "Goal Semiconductor", +[4][0x58 - 1] = "ARC International", +[4][0x59 - 1] = "Simmtec", +[4][0x5a - 1] = "Metanoia", +[4][0x5b - 1] = "Key Stream", +[4][0x5c - 1] = "Lowrance Electronics", +[4][0x5d - 1] = "Adimos", +[4][0x5e - 1] = "SiGe Semiconductor", +[4][0x5f - 1] = "Fodus Communications", +[4][0x60 - 1] = "Credence Systems Corp", +[4][0x61 - 1] = "Genesis Microchip Inc", +[4][0x62 - 1] = "Vihana Inc", +[4][0x63 - 1] = "WIS Technologies", +[4][0x64 - 1] = "GateChange Technologies", +[4][0x65 - 1] = "High Density Devices AS", +[4][0x66 - 1] = "Synopsys", +[4][0x67 - 1] = "Gigaram", +[4][0x68 - 1] = "Enigma Semiconductor Inc", +[4][0x69 - 1] = "Century Micro Inc", +[4][0x6a - 1] = "Icera Semiconductor", +[4][0x6b - 1] = "Mediaworks Integrated Systems", +[4][0x6c - 1] = "O'Neil Product Development", +[4][0x6d - 1] = "Supreme Top Technology Ltd", +[4][0x6e - 1] = "MicroDisplay Corporation", +[4][0x6f - 1] = "Team Group Inc", +[4][0x70 - 1] = "Sinett Corporation", +[4][0x71 - 1] = "Toshiba Corporation", +[4][0x72 - 1] = "Tensilica", +[4][0x73 - 1] = "SiRF Technology", +[4][0x74 - 1] = "Bacoc Inc", +[4][0x75 - 1] = "SMaL Camera Technologies", +[4][0x76 - 1] = "Thomson SC", +[4][0x77 - 1] = "Airgo Networks", +[4][0x78 - 1] = "Wisair Ltd", +[4][0x79 - 1] = "SigmaTel", +[4][0x7a - 1] = "Arkados", +[4][0x7b - 1] = "Compete IT gmbH Co KG", +[4][0x7c - 1] = "Eudar Technology Inc", +[4][0x7d - 1] = "Focus Enhancements", +[4][0x7e - 1] = "Xyratex", +[5][0x01 - 1] = "Specular Networks", +[5][0x02 - 1] = "Patriot Memory (PDP Systems)", +[5][0x03 - 1] = "U-Chip Technology Corp", +[5][0x04 - 1] = "Silicon Optix", +[5][0x05 - 1] = "Greenfield Networks", +[5][0x06 - 1] = "CompuRAM GmbH", +[5][0x07 - 1] = "Stargen Inc", +[5][0x08 - 1] = "NetCell Corporation", +[5][0x09 - 1] = "Excalibrus Technologies Ltd", +[5][0x0a - 1] = "SCM Microsystems", +[5][0x0b - 1] = "Xsigo Systems Inc", +[5][0x0c - 1] = "CHIPS & Systems Inc", +[5][0x0d - 1] = "Tier 1 Multichip Solutions", +[5][0x0e - 1] = "CWRL Labs", +[5][0x0f - 1] = "Teradici", +[5][0x10 - 1] = "Gigaram Inc", +[5][0x11 - 1] = "g2 Microsystems", +[5][0x12 - 1] = "PowerFlash Semiconductor", +[5][0x13 - 1] = "P.A. Semi Inc", +[5][0x14 - 1] = "NovaTech Solutions S.A.", +[5][0x15 - 1] = "c2 Microsystems Inc", +[5][0x16 - 1] = "Level5 Networks", +[5][0x17 - 1] = "COS Memory AG", +[5][0x18 - 1] = "Innovasic Semiconductor", +[5][0x19 - 1] = "02IC Co Ltd", +[5][0x1a - 1] = "Tabula Inc", +[5][0x1b - 1] = "Crucial Technology", +[5][0x1c - 1] = "Chelsio Communications", +[5][0x1d - 1] = "Solarflare Communications", +[5][0x1e - 1] = "Xambala Inc", +[5][0x1f - 1] = "EADS Astrium", +[5][0x20 - 1] = "Terra Semiconductor Inc", +[5][0x21 - 1] = "Imaging Works Inc", +[5][0x22 - 1] = "Astute Networks Inc", +[5][0x23 - 1] = "Tzero", +[5][0x24 - 1] = "Emulex", +[5][0x25 - 1] = "Power-One", +[5][0x26 - 1] = "Pulse~LINK Inc", +[5][0x27 - 1] = "Hon Hai Precision Industry", +[5][0x28 - 1] = "White Rock Networks Inc", +[5][0x29 - 1] = "Telegent Systems USA Inc", +[5][0x2a - 1] = "Atrua Technologies Inc", +[5][0x2b - 1] = "Acbel Polytech Inc", +[5][0x2c - 1] = "eRide Inc", +[5][0x2d - 1] = "ULi Electronics Inc", +[5][0x2e - 1] = "Magnum Semiconductor Inc", +[5][0x2f - 1] = "neoOne Technology Inc", +[5][0x30 - 1] = "Connex Technology Inc", +[5][0x31 - 1] = "Stream Processors Inc", +[5][0x32 - 1] = "Focus Enhancements", +[5][0x33 - 1] = "Telecis Wireless Inc", +[5][0x34 - 1] = "uNav Microelectronics", +[5][0x35 - 1] = "Tarari Inc", +[5][0x36 - 1] = "Ambric Inc", +[5][0x37 - 1] = "Newport Media Inc", +[5][0x38 - 1] = "VMTS", +[5][0x39 - 1] = "Enuclia Semiconductor Inc", +[5][0x3a - 1] = "Virtium Technology Inc", +[5][0x3b - 1] = "Solid State System Co Ltd", +[5][0x3c - 1] = "Kian Tech LLC", +[5][0x3d - 1] = "Artimi", +[5][0x3e - 1] = "Power Quotient International", +[5][0x3f - 1] = "Avago Technologies", +[5][0x40 - 1] = "ADTechnology", +[5][0x41 - 1] = "Sigma Designs", +[5][0x42 - 1] = "SiCortex Inc", +[5][0x43 - 1] = "Ventura Technology Group", +[5][0x44 - 1] = "eASIC", +[5][0x45 - 1] = "M.H.S. SAS", +[5][0x46 - 1] = "Micro Star International", +[5][0x47 - 1] = "Rapport Inc", +[5][0x48 - 1] = "Makway International", +[5][0x49 - 1] = "Broad Reach Engineering Co", +[5][0x4a - 1] = "Semiconductor Mfg Intl Corp", +[5][0x4b - 1] = "SiConnect", +[5][0x4c - 1] = "FCI USA Inc", +[5][0x4d - 1] = "Validity Sensors", +[5][0x4e - 1] = "Coney Technology Co Ltd", +[5][0x4f - 1] = "Spans Logic", +[5][0x50 - 1] = "Neterion Inc", +[5][0x51 - 1] = "Qimonda", +[5][0x52 - 1] = "New Japan Radio Co Ltd", +[5][0x53 - 1] = "Velogix", +[5][0x54 - 1] = "Montalvo Systems", +[5][0x55 - 1] = "iVivity Inc", +[5][0x56 - 1] = "Walton Chaintech", +[5][0x57 - 1] = "AENEON", +[5][0x58 - 1] = "Lorom Industrial Co Ltd", +[5][0x59 - 1] = "Radiospire Networks", +[5][0x5a - 1] = "Sensio Technologies Inc", +[5][0x5b - 1] = "Nethra Imaging", +[5][0x5c - 1] = "Hexon Technology Pte Ltd", +[5][0x5d - 1] = "CompuStocx (CSX)", +[5][0x5e - 1] = "Methode Electronics Inc", +[5][0x5f - 1] = "Connect One Ltd", +[5][0x60 - 1] = "Opulan Technologies", +[5][0x61 - 1] = "Septentrio NV", +[5][0x62 - 1] = "Goldenmars Technology Inc", +[5][0x63 - 1] = "Kreton Corporation", +[5][0x64 - 1] = "Cochlear Ltd", +[5][0x65 - 1] = "Altair Semiconductor", +[5][0x66 - 1] = "NetEffect Inc", +[5][0x67 - 1] = "Spansion Inc", +[5][0x68 - 1] = "Taiwan Semiconductor Mfg", +[5][0x69 - 1] = "Emphany Systems Inc", +[5][0x6a - 1] = "ApaceWave Technologies", +[5][0x6b - 1] = "Mobilygen Corporation", +[5][0x6c - 1] = "Tego", +[5][0x6d - 1] = "Cswitch Corporation", +[5][0x6e - 1] = "Haier (Beijing) IC Design Co", +[5][0x6f - 1] = "MetaRAM", +[5][0x70 - 1] = "Axel Electronics Co Ltd", +[5][0x71 - 1] = "Tilera Corporation", +[5][0x72 - 1] = "Aquantia", +[5][0x73 - 1] = "Vivace Semiconductor", +[5][0x74 - 1] = "Redpine Signals", +[5][0x75 - 1] = "Octalica", +[5][0x76 - 1] = "InterDigital Communications", +[5][0x77 - 1] = "Avant Technology", +[5][0x78 - 1] = "Asrock Inc", +[5][0x79 - 1] = "Availink", +[5][0x7a - 1] = "Quartics Inc", +[5][0x7b - 1] = "Element CXI", +[5][0x7c - 1] = "Innovaciones Microelectronicas", +[5][0x7d - 1] = "VeriSilicon Microelectronics", +[5][0x7e - 1] = "W5 Networks", +[6][0x01 - 1] = "MOVEKING", +[6][0x02 - 1] = "Mavrix Technology Inc", +[6][0x03 - 1] = "CellGuide Ltd", +[6][0x04 - 1] = "Faraday Technology", +[6][0x05 - 1] = "Diablo Technologies Inc", +[6][0x06 - 1] = "Jennic", +[6][0x07 - 1] = "Octasic", +[6][0x08 - 1] = "Molex Incorporated", +[6][0x09 - 1] = "3Leaf Networks", +[6][0x0a - 1] = "Bright Micron Technology", +[6][0x0b - 1] = "Netxen", +[6][0x0c - 1] = "NextWave Broadband Inc", +[6][0x0d - 1] = "DisplayLink", +[6][0x0e - 1] = "ZMOS Technology", +[6][0x0f - 1] = "Tec-Hill", +[6][0x10 - 1] = "Multigig Inc", +[6][0x11 - 1] = "Amimon", +[6][0x12 - 1] = "Euphonic Technologies Inc", +[6][0x13 - 1] = "BRN Phoenix", +[6][0x14 - 1] = "InSilica", +[6][0x15 - 1] = "Ember Corporation", +[6][0x16 - 1] = "Avexir Technologies Corporation", +[6][0x17 - 1] = "Echelon Corporation", +[6][0x18 - 1] = "Edgewater Computer Systems", +[6][0x19 - 1] = "XMOS Semiconductor Ltd", +[6][0x1a - 1] = "GENUSION Inc", +[6][0x1b - 1] = "Memory Corp NV", +[6][0x1c - 1] = "SiliconBlue Technologies", +[6][0x1d - 1] = "Rambus Inc", +[6][0x1e - 1] = "Andes Technology Corporation", +[6][0x1f - 1] = "Coronis Systems", +[6][0x20 - 1] = "Achronix Semiconductor", +[6][0x21 - 1] = "Siano Mobile Silicon Ltd", +[6][0x22 - 1] = "Semtech Corporation", +[6][0x23 - 1] = "Pixelworks Inc", +[6][0x24 - 1] = "Gaisler Research AB", +[6][0x25 - 1] = "Teranetics", +[6][0x26 - 1] = "Toppan Printing Co Ltd", +[6][0x27 - 1] = "Kingxcon", +[6][0x28 - 1] = "Silicon Integrated Systems", +[6][0x29 - 1] = "I-O Data Device Inc", +[6][0x2a - 1] = "NDS Americas Inc", +[6][0x2b - 1] = "Solomon Systech Limited", +[6][0x2c - 1] = "On Demand Microelectronics", +[6][0x2d - 1] = "Amicus Wireless Inc", +[6][0x2e - 1] = "SMARDTV SNC", +[6][0x2f - 1] = "Comsys Communication Ltd", +[6][0x30 - 1] = "Movidia Ltd", +[6][0x31 - 1] = "Javad GNSS Inc", +[6][0x32 - 1] = "Montage Technology Group", +[6][0x33 - 1] = "Trident Microsystems", +[6][0x34 - 1] = "Super Talent", +[6][0x35 - 1] = "Optichron Inc", +[6][0x36 - 1] = "Future Waves UK Ltd", +[6][0x37 - 1] = "SiBEAM Inc", +[6][0x38 - 1] = "InicoreInc", +[6][0x39 - 1] = "Virident Systems", +[6][0x3a - 1] = "M2000 Inc", +[6][0x3b - 1] = "ZeroG Wireless Inc", +[6][0x3c - 1] = "Gingle Technology Co Ltd", +[6][0x3d - 1] = "Space Micro Inc", +[6][0x3e - 1] = "Wilocity", +[6][0x3f - 1] = "Novafora Inc", +[6][0x40 - 1] = "iKoa Corporation", +[6][0x41 - 1] = "ASint Technology", +[6][0x42 - 1] = "Ramtron", +[6][0x43 - 1] = "Plato Networks Inc", +[6][0x44 - 1] = "IPtronics AS", +[6][0x45 - 1] = "Infinite-Memories", +[6][0x46 - 1] = "Parade Technologies Inc", +[6][0x47 - 1] = "Dune Networks", +[6][0x48 - 1] = "GigaDevice Semiconductor", +[6][0x49 - 1] = "Modu Ltd", +[6][0x4a - 1] = "CEITEC", +[6][0x4b - 1] = "Northrop Grumman", +[6][0x4c - 1] = "XRONET Corporation", +[6][0x4d - 1] = "Sicon Semiconductor AB", +[6][0x4e - 1] = "Atla Electronics Co Ltd", +[6][0x4f - 1] = "TOPRAM Technology", +[6][0x50 - 1] = "Silego Technology Inc", +[6][0x51 - 1] = "Kinglife", +[6][0x52 - 1] = "Ability Industries Ltd", +[6][0x53 - 1] = "Silicon Power Computer & Communications", +[6][0x54 - 1] = "Augusta Technology Inc", +[6][0x55 - 1] = "Nantronics Semiconductors", +[6][0x56 - 1] = "Hilscher Gesellschaft", +[6][0x57 - 1] = "Quixant Ltd", +[6][0x58 - 1] = "Percello Ltd", +[6][0x59 - 1] = "NextIO Inc", +[6][0x5a - 1] = "Scanimetrics Inc", +[6][0x5b - 1] = "FS-Semi Company Ltd", +[6][0x5c - 1] = "Infinera Corporation", +[6][0x5d - 1] = "SandForce Inc", +[6][0x5e - 1] = "Lexar Media", +[6][0x5f - 1] = "Teradyne Inc", +[6][0x60 - 1] = "Memory Exchange Corp", +[6][0x61 - 1] = "Suzhou Smartek Electronics", +[6][0x62 - 1] = "Avantium Corporation", +[6][0x63 - 1] = "ATP Electronics Inc", +[6][0x64 - 1] = "Valens Semiconductor Ltd", +[6][0x65 - 1] = "Agate Logic Inc", +[6][0x66 - 1] = "Netronome", +[6][0x67 - 1] = "Zenverge Inc", +[6][0x68 - 1] = "N-trig Ltd", +[6][0x69 - 1] = "SanMax Technologies Inc", +[6][0x6a - 1] = "Contour Semiconductor Inc", +[6][0x6b - 1] = "TwinMOS", +[6][0x6c - 1] = "Silicon Systems Inc", +[6][0x6d - 1] = "V-Color Technology Inc", +[6][0x6e - 1] = "Certicom Corporation", +[6][0x6f - 1] = "JSC ICC Milandr", +[6][0x70 - 1] = "PhotoFast Global Inc", +[6][0x71 - 1] = "InnoDisk Corporation", +[6][0x72 - 1] = "Muscle Power", +[6][0x73 - 1] = "Energy Micro", +[6][0x74 - 1] = "Innofidei", +[6][0x75 - 1] = "CopperGate Communications", +[6][0x76 - 1] = "Holtek Semiconductor Inc", +[6][0x77 - 1] = "Myson Century Inc", +[6][0x78 - 1] = "FIDELIX", +[6][0x79 - 1] = "Red Digital Cinema", +[6][0x7a - 1] = "Densbits Technology", +[6][0x7b - 1] = "Zempro", +[6][0x7c - 1] = "MoSys", +[6][0x7d - 1] = "Provigent", +[6][0x7e - 1] = "Triad Semiconductor Inc", +[7][0x01 - 1] = "Siklu Communication Ltd", +[7][0x02 - 1] = "A Force Manufacturing Ltd", +[7][0x03 - 1] = "Strontium", +[7][0x04 - 1] = "ALi Corp (Abilis Systems)", +[7][0x05 - 1] = "Siglead Inc", +[7][0x06 - 1] = "Ubicom Inc", +[7][0x07 - 1] = "Unifosa Corporation", +[7][0x08 - 1] = "Stretch Inc", +[7][0x09 - 1] = "Lantiq Deutschland GmbH", +[7][0x0a - 1] = "Visipro.", +[7][0x0b - 1] = "EKMemory", +[7][0x0c - 1] = "Microelectronics Institute ZTE", +[7][0x0d - 1] = "u-blox AG", +[7][0x0e - 1] = "Carry Technology Co Ltd", +[7][0x0f - 1] = "Nokia", +[7][0x10 - 1] = "King Tiger Technology", +[7][0x11 - 1] = "Sierra Wireless", +[7][0x12 - 1] = "HT Micron", +[7][0x13 - 1] = "Albatron Technology Co Ltd", +[7][0x14 - 1] = "Leica Geosystems AG", +[7][0x15 - 1] = "BroadLight", +[7][0x16 - 1] = "AEXEA", +[7][0x17 - 1] = "ClariPhy Communications Inc", +[7][0x18 - 1] = "Green Plug", +[7][0x19 - 1] = "Design Art Networks", +[7][0x1a - 1] = "Mach Xtreme Technology Ltd", +[7][0x1b - 1] = "ATO Solutions Co Ltd", +[7][0x1c - 1] = "Ramsta", +[7][0x1d - 1] = "Greenliant Systems Ltd", +[7][0x1e - 1] = "Teikon", +[7][0x1f - 1] = "Antec Hadron", +[7][0x20 - 1] = "NavCom Technology Inc", +[7][0x21 - 1] = "Shanghai Fudan Microelectronics", +[7][0x22 - 1] = "Calxeda Inc", +[7][0x23 - 1] = "JSC EDC Electronics", +[7][0x24 - 1] = "Kandit Technology Co Ltd", +[7][0x25 - 1] = "Ramos Technology", +[7][0x26 - 1] = "Goldenmars Technology", +[7][0x27 - 1] = "XeL Technology Inc", +[7][0x28 - 1] = "Newzone Corporation", +[7][0x29 - 1] = "ShenZhen MercyPower Tech", +[7][0x2a - 1] = "Nanjing Yihuo Technology", +[7][0x2b - 1] = "Nethra Imaging Inc", +[7][0x2c - 1] = "SiTel Semiconductor BV", +[7][0x2d - 1] = "SolidGear Corporation", +[7][0x2e - 1] = "Topower Computer Ind Co Ltd", +[7][0x2f - 1] = "Wilocity", +[7][0x30 - 1] = "Profichip GmbH", +[7][0x31 - 1] = "Gerad Technologies", +[7][0x32 - 1] = "Ritek Corporation", +[7][0x33 - 1] = "Gomos Technology Limited", +[7][0x34 - 1] = "Memoright Corporation", +[7][0x35 - 1] = "D-Broad Inc", +[7][0x36 - 1] = "HiSilicon Technologies", +[7][0x37 - 1] = "Syndiant Inc.", +[7][0x38 - 1] = "Enverv Inc", +[7][0x39 - 1] = "Cognex", +[7][0x3a - 1] = "Xinnova Technology Inc", +[7][0x3b - 1] = "Ultron AG", +[7][0x3c - 1] = "Concord Idea Corporation", +[7][0x3d - 1] = "AIM Corporation", +[7][0x3e - 1] = "Lifetime Memory Products", +[7][0x3f - 1] = "Ramsway", +[7][0x40 - 1] = "Recore Systems B.V.", +[7][0x41 - 1] = "Haotian Jinshibo Science Tech", +[7][0x42 - 1] = "Being Advanced Memory", +[7][0x43 - 1] = "Adesto Technologies", +[7][0x44 - 1] = "Giantec Semiconductor Inc", +[7][0x45 - 1] = "HMD Electronics AG", +[7][0x46 - 1] = "Gloway International (HK)", +[7][0x47 - 1] = "Kingcore", +[7][0x48 - 1] = "Anucell Technology Holding", +[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd", +[7][0x4a - 1] = "Active-Semi Inc", +[7][0x4b - 1] = "Denso Corporation", +[7][0x4c - 1] = "TLSI Inc", +[7][0x4d - 1] = "Qidan", +[7][0x4e - 1] = "Mustang", +[7][0x4f - 1] = "Orca Systems", +[7][0x50 - 1] = "Passif Semiconductor", +[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc", +[7][0x52 - 1] = "Memphis Electronic", +[7][0x53 - 1] = "Beckhoff Automation GmbH", +[7][0x54 - 1] = "Harmony Semiconductor Corp", +[7][0x55 - 1] = "Air Computers SRL", +[7][0x56 - 1] = "TMT Memory", +[7][0x57 - 1] = "Eorex Corporation", +[7][0x58 - 1] = "Xingtera", +[7][0x59 - 1] = "Netsol", +[7][0x5a - 1] = "Bestdon Technology Co Ltd", +[7][0x5b - 1] = "Baysand Inc", +[7][0x5c - 1] = "Uroad Technology Co Ltd", +[7][0x5d - 1] = "Wilk Elektronik S.A.", +[7][0x5e - 1] = "AAI", +[7][0x5f - 1] = "Harman", +[7][0x60 - 1] = "Berg Microelectronics Inc", +[7][0x61 - 1] = "ASSIA Inc", +[7][0x62 - 1] = "Visiontek Products LLC", +[7][0x63 - 1] = "OCMEMORY", +[7][0x64 - 1] = "Welink Solution Inc", +[7][0x65 - 1] = "Shark Gaming", +[7][0x66 - 1] = "Avalanche Technology", +[7][0x67 - 1] = "R&D Center ELVEES OJSC", +[7][0x68 - 1] = "KingboMars Technology Co Ltd", +[7][0x69 - 1] = "High Bridge Solutions Industria Eletronica", +[7][0x6a - 1] = "Transcend Technology Co Ltd", +[7][0x6b - 1] = "Everspin Technologies", +[7][0x6c - 1] = "Hon-Hai Precision", +[7][0x6d - 1] = "Smart Storage Systems", +[7][0x6e - 1] = "Toumaz Group", +[7][0x6f - 1] = "Zentel Electronics Corporation", +[7][0x70 - 1] = "Panram International Corporation", +[7][0x71 - 1] = "Silicon Space Technology", +[7][0x72 - 1] = "LITE-ON IT Corporation", +[7][0x73 - 1] = "Inuitive", +[7][0x74 - 1] = "HMicro", +[7][0x75 - 1] = "BittWare Inc", +[7][0x76 - 1] = "GLOBALFOUNDRIES", +[7][0x77 - 1] = "ACPI Digital Co Ltd", +[7][0x78 - 1] = "Annapurna Labs", +[7][0x79 - 1] = "AcSiP Technology Corporation", +[7][0x7a - 1] = "Idea! Electronic Systems", +[7][0x7b - 1] = "Gowe Technology Co Ltd", +[7][0x7c - 1] = "Hermes Testing Solutions Inc", +[7][0x7d - 1] = "Positivo BGH", +[7][0x7e - 1] = "Intelligence Silicon Technology", +[8][0x01 - 1] = "3D PLUS", +[8][0x02 - 1] = "Diehl Aerospace", +[8][0x03 - 1] = "Fairchild", +[8][0x04 - 1] = "Mercury Systems", +[8][0x05 - 1] = "Sonics Inc", +[8][0x06 - 1] = "Emerson Automation Solutions", +[8][0x07 - 1] = "Shenzhen Jinge Information Co Ltd", +[8][0x08 - 1] = "SCWW", +[8][0x09 - 1] = "Silicon Motion Inc", +[8][0x0a - 1] = "Anurag", +[8][0x0b - 1] = "King Kong", +[8][0x0c - 1] = "FROM30 Co Ltd", +[8][0x0d - 1] = "Gowin Semiconductor Corp", +[8][0x0e - 1] = "Fremont Micro Devices Ltd", +[8][0x0f - 1] = "Ericsson Modems", +[8][0x10 - 1] = "Exelis", +[8][0x11 - 1] = "Satixfy Ltd", +[8][0x12 - 1] = "Galaxy Microsystems Ltd", +[8][0x13 - 1] = "Gloway International Co Ltd", +[8][0x14 - 1] = "Lab", +[8][0x15 - 1] = "Smart Energy Instruments", +[8][0x16 - 1] = "Approved Memory Corporation", +[8][0x17 - 1] = "Axell Corporation", +[8][0x18 - 1] = "Essencore Limited", +[8][0x19 - 1] = "Phytium", +[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", +[8][0x1b - 1] = "Ambiq Micro", +[8][0x1c - 1] = "eveRAM Technology Inc", +[8][0x1d - 1] = "Infomax", +[8][0x1e - 1] = "Butterfly Network Inc", +[8][0x1f - 1] = "Shenzhen City Gcai Electronics", +[8][0x20 - 1] = "Stack Devices Corporation", +[8][0x21 - 1] = "ADK Media Group", +[8][0x22 - 1] = "TSP Global Co Ltd", +[8][0x23 - 1] = "HighX", +[8][0x24 - 1] = "Shenzhen Elicks Technology", +[8][0x25 - 1] = "XinKai/Silicon Kaiser", +[8][0x26 - 1] = "Google Inc", +[8][0x27 - 1] = "Dasima International Development", +[8][0x28 - 1] = "Leahkinn Technology Limited", +[8][0x29 - 1] = "HIMA Paul Hildebrandt GmbH Co KG", +[8][0x2a - 1] = "Keysight Technologies", +[8][0x2b - 1] = "Techcomp International (Fastable)", +[8][0x2c - 1] = "Ancore Technology Corporation", +[8][0x2d - 1] = "Nuvoton", +[8][0x2e - 1] = "Korea Uhbele International Group Ltd", +[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd", +[8][0x30 - 1] = "RelChip Inc", +[8][0x31 - 1] = "Baikal Electronics", +[8][0x32 - 1] = "Nemostech Inc", +[8][0x33 - 1] = "Memorysolution GmbH", +[8][0x34 - 1] = "Silicon Integrated Systems Corporation", +[8][0x35 - 1] = "Xiede", +[8][0x36 - 1] = "BRC", +[8][0x37 - 1] = "Flash Chi", +[8][0x38 - 1] = "Jone", +[8][0x39 - 1] = "GCT Semiconductor Inc", +[8][0x3a - 1] = "Hong Kong Zetta Device Technology", +[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd", +[8][0x3c - 1] = "Cuso", +[8][0x3d - 1] = "Kuso", +[8][0x3e - 1] = "Uniquify Inc", +[8][0x3f - 1] = "Skymedi Corporation", +[8][0x40 - 1] = "Core Chance Co Ltd", +[8][0x41 - 1] = "Tekism Co Ltd", +[8][0x42 - 1] = "Seagate Technology PLC", +[8][0x43 - 1] = "Hong Kong Gaia Group Co Limited", +[8][0x44 - 1] = "Gigacom Semiconductor LLC", +[8][0x45 - 1] = "V2 Technologies", +[8][0x46 - 1] = "TLi", +[8][0x47 - 1] = "Neotion", +[8][0x48 - 1] = "Lenovo", +[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp Ltd", +[8][0x4a - 1] = "Compound Photonics", +[8][0x4b - 1] = "in2H2 inc", +[8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd", +[8][0x4d - 1] = "Vasekey", +[8][0x4e - 1] = "Cal-Comp Industria de Semicondutores", +[8][0x4f - 1] = "Eyenix Co Ltd", +[8][0x50 - 1] = "Heoriady", +[8][0x51 - 1] = "Accelerated Memory Production Inc", +[8][0x52 - 1] = "INVECAS Inc", +[8][0x53 - 1] = "AP Memory", +[8][0x54 - 1] = "Douqi Technology", +[8][0x55 - 1] = "Etron Technology Inc", +[8][0x56 - 1] = "Indie Semiconductor", +[8][0x57 - 1] = "Socionext Inc", +[8][0x58 - 1] = "HGST", +[8][0x59 - 1] = "EVGA", +[8][0x5a - 1] = "Audience Inc", +[8][0x5b - 1] = "EpicGear", +[8][0x5c - 1] = "Vitesse Enterprise Co", +[8][0x5d - 1] = "Foxtronn International Corporation", +[8][0x5e - 1] = "Bretelon Inc", +[8][0x5f - 1] = "Graphcore", +[8][0x60 - 1] = "Eoplex Inc", +[8][0x61 - 1] = "MaxLinear Inc", +[8][0x62 - 1] = "ETA Devices", +[8][0x63 - 1] = "LOKI", +[8][0x64 - 1] = "IMS Electronics Co Ltd", +[8][0x65 - 1] = "Dosilicon Co Ltd", +[8][0x66 - 1] = "Dolphin Integration", +[8][0x67 - 1] = "Shenzhen Mic Electronics Technolog", +[8][0x68 - 1] = "Boya Microelectronics Inc", +[8][0x69 - 1] = "Geniachip (Roche)", +[8][0x6a - 1] = "Axign", +[8][0x6b - 1] = "Kingred Electronic Technology Ltd", +[8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.", +[8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.", +[8][0x6e - 1] = "Crocus Technology Inc", +[8][0x6f - 1] = "Creative Chips GmbH", +[8][0x70 - 1] = "GE Aviation Systems LLC.", +[8][0x71 - 1] = "Asgard", +[8][0x72 - 1] = "Good Wealth Technology Ltd", +[8][0x73 - 1] = "TriCor Technologies", +[8][0x74 - 1] = "Nova-Systems GmbH", +[8][0x75 - 1] = "JUHOR", +[8][0x76 - 1] = "Zhuhai Douke Commerce Co Ltd", +[8][0x77 - 1] = "DSL Memory", +[8][0x78 - 1] = "Anvo-Systems Dresden GmbH", +[8][0x79 - 1] = "Realtek", +[8][0x7a - 1] = "AltoBeam", +[8][0x7b - 1] = "Wave Computing", +[8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd", +[8][0x7d - 1] = "Innovium Inc", +[8][0x7e - 1] = "Starsway Technology Limited", +[9][0x01 - 1] = "Weltronics Co LTD", +[9][0x02 - 1] = "VMware Inc", +[9][0x03 - 1] = "Hewlett Packard Enterprise", +[9][0x04 - 1] = "INTENSO", +[9][0x05 - 1] = "Puya Semiconductor", +[9][0x06 - 1] = "MEMORFI", +[9][0x07 - 1] = "MSC Technologies GmbH", +[9][0x08 - 1] = "Txrui", +[9][0x09 - 1] = "SiFive Inc", +[9][0x0a - 1] = "Spreadtrum Communications", +[9][0x0b - 1] = "XTX Technology Limited", +[9][0x0c - 1] = "UMAX Technology", +[9][0x0d - 1] = "Shenzhen Yong Sheng Technology", +[9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)", +[9][0x0f - 1] = "Daten Tecnologia LTDA", +[9][0x10 - 1] = "Shenzhen XinRuiYan Electronics", +[9][0x11 - 1] = "Eta Compute", +[9][0x12 - 1] = "Energous", +[9][0x13 - 1] = "Raspberry Pi Trading Ltd", +[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co Ltd", +[9][0x15 - 1] = "Silicon Mobility", +[9][0x16 - 1] = "IQ-Analog Corporation", +[9][0x17 - 1] = "Uhnder Inc", +[9][0x18 - 1] = "Impinj", +[9][0x19 - 1] = "DEPO Computers", +[9][0x1a - 1] = "Nespeed Sysems", +[9][0x1b - 1] = "Yangtze Memory Technologies Co Ltd", +[9][0x1c - 1] = "MemxPro Inc", +[9][0x1d - 1] = "Tammuz Co Ltd", +[9][0x1e - 1] = "Allwinner Technology", +[9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm", +[9][0x20 - 1] = "XMC", +[9][0x21 - 1] = "Teclast", +[9][0x22 - 1] = "Maxsun", +[9][0x23 - 1] = "Haiguang Integrated Circuit Design", +[9][0x24 - 1] = "RamCENTER Technology", +[9][0x25 - 1] = "Phison Electronics Corporation", +[9][0x26 - 1] = "Guizhou Huaxintong Semi-Conductor", +[9][0x27 - 1] = "Network Intelligence", +[9][0x28 - 1] = "Continental Technology (Holdings)", +[9][0x29 - 1] = "Guangzhou Huayan Suning Electronic", +[9][0x2a - 1] = "Guangzhou Zhouji Electronic Co Ltd", +[9][0x2b - 1] = "Shenzhen Giant Hui Kang Tech Co Ltd", +[9][0x2c - 1] = "Shenzhen Yilong Innovative Co Ltd", +[9][0x2d - 1] = "Neo Forza", +[9][0x2e - 1] = "Lyontek Inc", +[9][0x2f - 1] = "Shanghai Kuxin Microelectronics Ltd", +[9][0x30 - 1] = "Shenzhen Larix Technology Co Ltd", +[9][0x31 - 1] = "Qbit Semiconductor Ltd", +[9][0x32 - 1] = "Insignis Technology Corporation", +[9][0x33 - 1] = "Lanson Memory Co Ltd", +[9][0x34 - 1] = "Shenzhen Superway Electronics Co Ltd", +[9][0x35 - 1] = "Canaan-Creative Co Ltd", +[9][0x36 - 1] = "Black Diamond Memory", +[9][0x37 - 1] = "Shenzhen City Parker Baking Electronics", +[9][0x38 - 1] = "Shenzhen Baihong Technology Co Ltd", +[9][0x39 - 1] = "GEO Semiconductors", +[9][0x3a - 1] = "OCPC", +[9][0x3b - 1] = "Artery Technology Co Ltd", +[9][0x3c - 1] = "Jinyu", +[9][0x3d - 1] = "ShenzhenYing Chi Technology Development", +[9][0x3e - 1] = "Shenzhen Pengcheng Xin Technology", +[9][0x3f - 1] = "Pegasus Semiconductor (Shanghai) Co", +[9][0x40 - 1] = "Mythic Inc", +[9][0x41 - 1] = "Elmos Semiconductor AG", +[9][0x42 - 1] = "Kllisre", +[9][0x43 - 1] = "Shenzhen Winconway Technology", +[9][0x44 - 1] = "Shenzhen Xingmem Technology Corp", +[9][0x45 - 1] = "Gold Key Technology Co Ltd", +[9][0x46 - 1] = "Habana Labs Ltd", +[9][0x47 - 1] = "Hoodisk Electronics Co Ltd", +[9][0x48 - 1] = "SemsoTai (SZ) Technology Co Ltd", +[9][0x49 - 1] = "OM Nanotech Pvt. Ltd", +[9][0x4a - 1] = "Shenzhen Zhifeng Weiye Technology", +[9][0x4b - 1] = "Xinshirui (Shenzhen) Electronics Co", +[9][0x4c - 1] = "Guangzhou Zhong Hao Tian Electronic", +[9][0x4d - 1] = "Shenzhen Longsys Electronics Co Ltd", +[9][0x4e - 1] = "Deciso B.V.", +[9][0x4f - 1] = "Puya Semiconductor (Shenzhen)", +[9][0x50 - 1] = "Shenzhen Veineda Technology Co Ltd", +[9][0x51 - 1] = "Antec Memory", +[9][0x52 - 1] = "Cortus SAS", +[9][0x53 - 1] = "Dust Leopard", +[9][0x54 - 1] = "MyWo AS", +[9][0x55 - 1] = "J&A Information Inc", +[9][0x56 - 1] = "Shenzhen JIEPEI Technology Co Ltd", +[9][0x57 - 1] = "Heidelberg University", +[9][0x58 - 1] = "Flexxon PTE Ltd", +[9][0x59 - 1] = "Wiliot", +[9][0x5a - 1] = "Raysun Electronics International Ltd", +[9][0x5b - 1] = "Aquarius Production Company LLC", +[9][0x5c - 1] = "MACNICA DHW LTDA", +[9][0x5d - 1] = "Intelimem", +[9][0x5e - 1] = "Zbit Semiconductor Inc", +[9][0x5f - 1] = "Shenzhen Technology Co Ltd", +[9][0x60 - 1] = "Signalchip", +[9][0x61 - 1] = "Shenzen Recadata Storage Technology", +[9][0x62 - 1] = "Hyundai Technology", +[9][0x63 - 1] = "Shanghai Fudi Investment Development", +[9][0x64 - 1] = "Aixi Technology", +[9][0x65 - 1] = "Tecon MT", +[9][0x66 - 1] = "Onda Electric Co Ltd", +[9][0x67 - 1] = "Jinshen", +[9][0x68 - 1] = "Kimtigo Semiconductor (HK) Limited", +[9][0x69 - 1] = "IIT Madras", +[9][0x6a - 1] = "Shenshan (Shenzhen) Electronic", +[9][0x6b - 1] = "Hefei Core Storage Electronic Limited", +[9][0x6c - 1] = "Colorful Technology Ltd", +[9][0x6d - 1] = "Visenta (Xiamen) Technology Co Ltd", +[9][0x6e - 1] = "Roa Logic BV", +[9][0x6f - 1] = "NSITEXE Inc", +[9][0x70 - 1] = "Hong Kong Hyunion Electronics", +[9][0x71 - 1] = "ASK Technology Group Limited", +[9][0x72 - 1] = "GIGA-BYTE Technology Co Ltd", +[9][0x73 - 1] = "Terabyte Co Ltd", +[9][0x74 - 1] = "Hyundai Inc", +[9][0x75 - 1] = "EXCELERAM", +[9][0x76 - 1] = "PsiKick", +[9][0x77 - 1] = "Netac Technology Co Ltd", +[9][0x78 - 1] = "PCCOOLER", +[9][0x79 - 1] = "Jiangsu Huacun Electronic Technology", +[9][0x7a - 1] = "Shenzhen Micro Innovation Industry", +[9][0x7b - 1] = "Beijing Tongfang Microelectronics Co", +[9][0x7c - 1] = "XZN Storage Technology", +[9][0x7d - 1] = "ChipCraft Sp. z.o.o.", +[9][0x7e - 1] = "ALLFLASH Technology Limited", +[10][0x01 - 1] = "Foerd Technology Co Ltd", +[10][0x02 - 1] = "KingSpec", +[10][0x03 - 1] = "Codasip GmbH", +[10][0x04 - 1] = "SL Link Co Ltd", +[10][0x05 - 1] = "Shenzhen Kefu Technology Co Limited", +[10][0x06 - 1] = "Shenzhen ZST Electronics Technology", +[10][0x07 - 1] = "Kyokuto Electronic Inc", +[10][0x08 - 1] = "Warrior Technology", +[10][0x09 - 1] = "TRINAMIC Motion Control GmbH & Co", +[10][0x0a - 1] = "PixelDisplay Inc", +[10][0x0b - 1] = "Shenzhen Futian District Bo Yueda Elec", +[10][0x0c - 1] = "Richtek Power", +[10][0x0d - 1] = "Shenzhen LianTeng Electronics Co Ltd", +[10][0x0e - 1] = "AITC Memory", +[10][0x0f - 1] = "UNIC Memory Technology Co Ltd", +[10][0x10 - 1] = "Shenzhen Huafeng Science Technology", +[10][0x11 - 1] = "CXMT", +[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm", +[10][0x13 - 1] = "SambaNova Systems", +[10][0x14 - 1] = "V-GEN", +[10][0x15 - 1] = "Jump Trading", +[10][0x16 - 1] = "Ampere Computing", +[10][0x17 - 1] = "Shenzhen Zhongshi Technology Co Ltd", +[10][0x18 - 1] = "Shenzhen Zhongtian Bozhong Technology", +[10][0x19 - 1] = "Tri-Tech International", +[10][0x1a - 1] = "Silicon Intergrated Systems Corporation", +[10][0x1b - 1] = "Shenzhen HongDingChen Information", +[10][0x1c - 1] = "Plexton Holdings Limited", +[10][0x1d - 1] = "AMS (Jiangsu Advanced Memory Semi)", +[10][0x1e - 1] = "Wuhan Jing Tian Interconnected Tech Co", +[10][0x1f - 1] = "Axia Memory Technology", +[10][0x20 - 1] = "Chipset Technology Holding Limited", +[10][0x21 - 1] = "Shenzhen Xinshida Technology Co Ltd", +[10][0x22 - 1] = "Shenzhen Chuangshifeida Technology", +[10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology", +[10][0x24 - 1] = "ADVAN Inc", +[10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd", +[10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading", +[10][0x27 - 1] = "StarRam International Co Ltd", +[10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd", +[10][0x29 - 1] = "UltraMemory Inc", +[10][0x2a - 1] = "New Coastline Global Tech Industry Co", +[10][0x2b - 1] = "Sinker", +[10][0x2c - 1] = "Diamond", +[10][0x2d - 1] = "PUSKILL", +[10][0x2e - 1] = "Guangzhou Hao Jia Ye Technology Co", +[10][0x2f - 1] = "Ming Xin Limited", +[10][0x30 - 1] = "Barefoot Networks", +[10][0x31 - 1] = "Biwin Semiconductor (HK) Co Ltd", +[10][0x32 - 1] = "UD INFO Corporation", +[10][0x33 - 1] = "Trek Technology (S) PTE Ltd", +[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd", +[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd", +[10][0x36 - 1] = "Nuclei System Technology Co Ltd", +[10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology", +[10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd", +[10][0x39 - 1] = "Zotac Technology Ltd", +[10][0x3a - 1] = "Foxline", +[10][0x3b - 1] = "Shenzhen Farasia Science Technology", +[10][0x3c - 1] = "Efinix Inc", +[10][0x3d - 1] = "Hua Nan San Xian Technology Co Ltd", +[10][0x3e - 1] = "Goldtech Electronics Co Ltd", +[10][0x3f - 1] = "Shanghai Han Rong Microelectronics Co", +[10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading", +[10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics", +[10][0x42 - 1] = "Thermaltake Technology Co Ltd", +[10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd", +[10][0x44 - 1] = "UPMEM", +[10][0x45 - 1] = "Chun Well Technology Holding Limited", +[10][0x46 - 1] = "Astera Labs Inc", +[10][0x47 - 1] = "Winconway", +[10][0x48 - 1] = "Advantech Co Ltd", +[10][0x49 - 1] = "Chengdu Fengcai Electronic Technology", +[10][0x4a - 1] = "The Boeing Company", +[10][0x4b - 1] = "Blaize Inc", +[10][0x4c - 1] = "Ramonster Technology Co Ltd", +[10][0x4d - 1] = "Wuhan Naonongmai Technology Co Ltd", +[10][0x4e - 1] = "Shenzhen Hui ShingTong Technology", +[10][0x4f - 1] = "Yourlyon", +[10][0x50 - 1] = "Fabu Technology", +[10][0x51 - 1] = "Shenzhen Yikesheng Technology Co Ltd", +[10][0x52 - 1] = "NOR-MEM", +[10][0x53 - 1] = "Cervoz Co Ltd", +[10][0x54 - 1] = "Bitmain Technologies Inc.", +[10][0x55 - 1] = "Facebook Inc", +[10][0x56 - 1] = "Shenzhen Longsys Electronics Co Ltd", +[10][0x57 - 1] = "Guangzhou Siye Electronic Technology", +[10][0x58 - 1] = "Silergy", +[10][0x59 - 1] = "Adamway", +[10][0x5a - 1] = "PZG", +[10][0x5b - 1] = "Shenzhen King Power Electronics", +[10][0x5c - 1] = "Guangzhou ZiaoFu Tranding Co Ltd", +[10][0x5d - 1] = "Shenzhen SKIHOTAR Semiconductor", +[10][0x5e - 1] = "PulseRain Technology", +[10][0x5f - 1] = "Seeker Technology Limited", +[10][0x60 - 1] = "Shenzhen OSCOO Tech Co Ltd", +[10][0x61 - 1] = "Shenzhen Yze Technology Co Ltd", +[10][0x62 - 1] = "Shenzhen Jieshuo Electronic Commerce", +[10][0x63 - 1] = "Gazda", +[10][0x64 - 1] = "Hua Wei Technology Co Ltd", +[10][0x65 - 1] = "Esperanto Technologies", +[10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", +[10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", +[10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", +[10][0x69 - 1] = "Fraunhofer IIS", +[10][0x6a - 1] = "Kandou Bus SA", +[10][0x6b - 1] = "Acer", +[10][0x6c - 1] = "Artmem Technology Co Ltd", +[10][0x6d - 1] = "Gstar Semiconductor Co Ltd", +[10][0x6e - 1] = "ShineDisk", +[10][0x6f - 1] = "Shenzhen CHN Technology Co Ltd", +[10][0x70 - 1] = "UnionChip Semiconductor Co Ltd", +[10][0x71 - 1] = "Tanbassh", +[10][0x72 - 1] = "Shenzhen Tianyu Jieyun Intl Logistics", +[10][0x73 - 1] = "MCLogic Inc", +[10][0x74 - 1] = "Eorex Corporation", +[10][0x75 - 1] = "Arm Technology (China) Co Ltd", +[10][0x76 - 1] = "Lexar Co Limited", +[10][0x77 - 1] = "QinetiQ Group plc", +[10][0x78 - 1] = "Exascend", +[10][0x79 - 1] = "Hong Kong Hyunion Electronics Co Ltd", +[10][0x7a - 1] = "Shenzhen Banghong Electronics Co Ltd", +[10][0x7b - 1] = "MBit Wireless Inc", +[10][0x7c - 1] = "Hex Five Security Inc", +[10][0x7d - 1] = "ShenZhen Juhor Precision Tech Co Ltd", +[10][0x7e - 1] = "Shenzhen Reeinno Technology Co Ltd", +[11][0x01 - 1] = "ABIT Electronics (Shenzhen) Co Ltd", +[11][0x02 - 1] = "Semidrive", +[11][0x03 - 1] = "MyTek Electronics Corp", +[11][0x04 - 1] = "Wxilicon Technology Co Ltd", +[11][0x05 - 1] = "Shenzhen Meixin Electronics Ltd", +[11][0x06 - 1] = "Ghost Wolf", +[11][0x07 - 1] = "LiSion Technologies Inc", +[11][0x08 - 1] = "Power Active Co Ltd", +[11][0x09 - 1] = "Pioneer High Fidelity Taiwan Co. Ltd", +[11][0x0a - 1] = "LuoSilk", +[11][0x0b - 1] = "Shenzhen Chuangshifeida Technology", +[11][0x0c - 1] = "Black Sesame Technologies Inc", +[11][0x0d - 1] = "Jiangsu Xinsheng Intelligent Technology", +[11][0x0e - 1] = "MLOONG", +[11][0x0f - 1] = "Quadratica LLC", +[11][0x10 - 1] = "Anpec Electronics", +[11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co", +[11][0x12 - 1] = "Kingbank Technology Co Ltd", +[11][0x13 - 1] = "ITRenew Inc", +[11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd", +[11][0x15 - 1] = "Jazer", +[11][0x16 - 1] = "Xiamen Semiconductor Investment Group", +[11][0x17 - 1] = "Guangzhou Longdao Network Tech Co", +[11][0x18 - 1] = "Shenzhen Futian SEC Electronic Market", +[11][0x19 - 1] = "Allegro Microsystems LLC", +[11][0x1a - 1] = "Hunan RunCore Innovation Technology", +[11][0x1b - 1] = "C-Corsa Technology", +[11][0x1c - 1] = "Zhuhai Chuangfeixin Technology Co Ltd", +[11][0x1d - 1] = "Beijing InnoMem Technologies Co Ltd", +[11][0x1e - 1] = "YooTin", +[11][0x1f - 1] = "Shenzhen Pengxiong Technology Co Ltd", +[11][0x20 - 1] = "Dongguan Yingbang Commercial Trading Co", +[11][0x21 - 1] = "Shenzhen Ronisys Electronics Co Ltd", +[11][0x22 - 1] = "Hongkong Xinlan Guangke Co Ltd", +[11][0x23 - 1] = "Apex Microelectronics Co Ltd", +[11][0x24 - 1] = "Beijing Hongda Jinming Technology Co Ltd", +[11][0x25 - 1] = "Ling Rui Technology (Shenzhen) Co Ltd", +[11][0x26 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[11][0x27 - 1] = "Starsystems Inc", +[11][0x28 - 1] = "Shenzhen Yingjiaxun Industrial Co Ltd", +[11][0x29 - 1] = "Dongguan Crown Code Electronic Commerce", +[11][0x2a - 1] = "Monolithic Power Systems Inc", +[11][0x2b - 1] = "WuHan SenNaiBo E-Commerce Co Ltd", +[11][0x2c - 1] = "Hangzhou Hikstorage Technology Co", +[11][0x2d - 1] = "Shenzhen Goodix Technology Co Ltd", +[11][0x2e - 1] = "Aigo Electronic Technology Co Ltd", +[11][0x2f - 1] = "Hefei Konsemi Storage Technology Co Ltd", +[11][0x30 - 1] = "Cactus Technologies Limited", +[11][0x31 - 1] = "DSIN", +[11][0x32 - 1] = "Blu Wireless Technology", +[11][0x33 - 1] = "Nanjing UCUN Technology Inc", +[11][0x34 - 1] = "Acacia Communications", +[11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", +[11][0x36 - 1] = "Zyzyx", +[11][0x37 - 1] = "T-HEAD Semiconductor Co Ltd", +[11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", +[11][0x39 - 1] = "Syzexion", +[11][0x3a - 1] = "Kembona", +[11][0x3b - 1] = "Qingdao Thunderobot Technology Co Ltd", +[11][0x3c - 1] = "Morse Micro", +[11][0x3d - 1] = "Shenzhen Envida Technology Co Ltd", +[11][0x3e - 1] = "UDStore Solution Limited", +[11][0x3f - 1] = "Shunlie", +[11][0x40 - 1] = "Shenzhen Xin Hong Rui Tech Ltd", +[11][0x41 - 1] = "Shenzhen Yze Technology Co Ltd", +[11][0x42 - 1] = "Shenzhen Huang Pu He Xin Technology", +[11][0x43 - 1] = "Xiamen Pengpai Microelectronics Co Ltd", +[11][0x44 - 1] = "JISHUN", +[11][0x45 - 1] = "Shenzhen WODPOSIT Technology Co", +[11][0x46 - 1] = "Unistar", +[11][0x47 - 1] = "UNICORE Electronic (Suzhou) Co Ltd", +[11][0x48 - 1] = "Axonne Inc", +[11][0x49 - 1] = "Shenzhen SOVERECA Technology Co", +[11][0x4a - 1] = "Dire Wolf", +[11][0x4b - 1] = "Whampoa Core Technology Co Ltd", +[11][0x4c - 1] = "CSI Halbleiter GmbH", +[11][0x4d - 1] = "ONE Semiconductor", +[11][0x4e - 1] = "SimpleMachines Inc", +[11][0x4f - 1] = "Shenzhen Chengyi Qingdian Electronic", +[11][0x50 - 1] = "Shenzhen Xinlianxin Network Technology", +[11][0x51 - 1] = "Vayyar Imaging Ltd", +[11][0x52 - 1] = "Paisen Network Technology Co Ltd", +[11][0x53 - 1] = "Shenzhen Fengwensi Technology Co Ltd", +[11][0x54 - 1] = "Caplink Technology Limited", +[11][0x55 - 1] = "JJT Solution Co Ltd", +[11][0x56 - 1] = "HOSIN Global Electronics Co Ltd", +[11][0x57 - 1] = "Shenzhen KingDisk Century Technology", +[11][0x58 - 1] = "SOYO", +[11][0x59 - 1] = "DIT Technology Co Ltd", +[11][0x5a - 1] = "iFound", +[11][0x5b - 1] = "Aril Computer Company", +[11][0x5c - 1] = "ASUS", +[11][0x5d - 1] = "Shenzhen Ruiyingtong Technology Co", +[11][0x5e - 1] = "HANA Micron", +[11][0x5f - 1] = "RANSOR", +[11][0x60 - 1] = "Axiado Corporation", +[11][0x61 - 1] = "Tesla Corporation", +[11][0x62 - 1] = "Pingtouge (Shanghai) Semiconductor Co", +[11][0x63 - 1] = "S3Plus Technologies SA", +[11][0x64 - 1] = "Integrated Silicon Solution Israel Ltd", +[11][0x65 - 1] = "GreenWaves Technologies", +[11][0x66 - 1] = "NUVIA Inc", +[11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co", +[11][0x68 - 1] = "Shenzhen Hangshun Chip Technology", +[11][0x69 - 1] = "Chengboliwei Electronic Business", +[11][0x6a - 1] = "Kowin Technology HK Limited", +[11][0x6b - 1] = "Euronet Technology Inc", +[11][0x6c - 1] = "SCY", +[11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical", +[11][0x6e - 1] = "PICOCOM", +[11][0x6f - 1] = "Shenzhen Toooogo Memory Technology", +[11][0x70 - 1] = "VLSI Solution", +[11][0x71 - 1] = "Costar Electronics Inc", +[11][0x72 - 1] = "Shenzhen Huatop Technology Co Ltd", +[11][0x73 - 1] = "Inspur Electronic Information Industry", +[11][0x74 - 1] = "Shenzhen Boyuan Computer Technology", +[11][0x75 - 1] = "Beijing Welldisk Electronics Co Ltd", +[11][0x76 - 1] = "Suzhou EP Semicon Co Ltd", +[11][0x77 - 1] = "Zhejiang Dahua Memory Technology", +[11][0x78 - 1] = "Virtu Financial", +[11][0x79 - 1] = "Datotek International Co Ltd", +[11][0x7a - 1] = "Telecom and Microelectronics Industries", +[11][0x7b - 1] = "Echow Technology Ltd", +[11][0x7c - 1] = "APEX-INFO", +[11][0x7d - 1] = "Yingpark", +[11][0x7e - 1] = "Shenzhen Bigway Tech Co Ltd", +[12][0x01 - 1] = "Beijing Haawking Technology Co Ltd", +[12][0x02 - 1] = "Open HW Group", +[12][0x03 - 1] = "JHICC", +[12][0x04 - 1] = "ncoder AG", +[12][0x05 - 1] = "ThinkTech Information Technology Co", +[12][0x06 - 1] = "Shenzhen Chixingzhe Technology Co Ltd", +[12][0x07 - 1] = "Biao Ram Technology Co Ltd", +[12][0x08 - 1] = "Shenzhen Kaizhuoyue Electronics Co Ltd", +[12][0x09 - 1] = "Shenzhen YC Storage Technology Co Ltd", +[12][0x0a - 1] = "Shenzhen Chixingzhe Technology Co", +[12][0x0b - 1] = "Wink Semiconductor (Shenzhen) Co Ltd", +[12][0x0c - 1] = "AISTOR", +[12][0x0d - 1] = "Palma Ceia SemiDesign", +[12][0x0e - 1] = "EM Microelectronic-Marin SA", +[12][0x0f - 1] = "Shenzhen Monarch Memory Technology", +[12][0x10 - 1] = "Reliance Memory Inc", +[12][0x11 - 1] = "Jesis", +[12][0x12 - 1] = "Espressif Systems (Shanghai) Co Ltd", +[12][0x13 - 1] = "Shenzhen Sati Smart Technology Co Ltd", +[12][0x14 - 1] = "NeuMem Co Ltd", +[12][0x15 - 1] = "Lifelong", +[12][0x16 - 1] = "Beijing Oitech Technology Co Ltd", +[12][0x17 - 1] = "Groupe LDLC", +[12][0x18 - 1] = "Semidynamics Technology Services SLU", +[12][0x19 - 1] = "swordbill", +[12][0x1a - 1] = "YIREN", +[12][0x1b - 1] = "Shenzhen Yinxiang Technology Co Ltd", +[12][0x1c - 1] = "PoweV Electronic Technology Co Ltd", +[12][0x1d - 1] = "LEORICE", +[12][0x1e - 1] = "Waymo LLC", +[12][0x1f - 1] = "Ventana Micro Systems", +[12][0x20 - 1] = "Hefei Guangxin Microelectronics Co Ltd", +[12][0x21 - 1] = "Shenzhen Sooner Industrial Co Ltd", +[12][0x22 - 1] = "Horizon Robotics", +[12][0x23 - 1] = "Tangem AG", +[12][0x24 - 1] = "FuturePath Technology (Shenzhen) Co", +[12][0x25 - 1] = "RC Module", +[12][0x26 - 1] = "Timetec International Inc", +[12][0x27 - 1] = "ICMAX Technologies Co Limited", +[12][0x28 - 1] = "Lynxi Technologies Ltd Co", +[12][0x29 - 1] = "Guangzhou Taisupanke Computer Equipment", +[12][0x2a - 1] = "Ceremorphic Inc", +[12][0x2b - 1] = "Biwin Storage Technology Co Ltd", +[12][0x2c - 1] = "Beijing ESWIN Computing Technology", +[12][0x2d - 1] = "WeForce Co Ltd", +[12][0x2e - 1] = "Shenzhen Fanxiang Information Technology", +[12][0x2f - 1] = "Unisoc", +[12][0x30 - 1] = "YingChu", +[12][0x31 - 1] = "GUANCUN", +[12][0x32 - 1] = "IPASON", +[12][0x33 - 1] = "Ayar Labs", +[12][0x34 - 1] = "Amazon", +[12][0x35 - 1] = "Shenzhen Xinxinshun Technology Co", +[12][0x36 - 1] = "Galois Inc", +[12][0x37 - 1] = "Ubilite Inc", +[12][0x38 - 1] = "Shenzhen Quanxing Technology Co Ltd", +[12][0x39 - 1] = "Group RZX Technology LTDA", +[12][0x3a - 1] = "Yottac Technology (XI'AN) Cooperation", +[12][0x3b - 1] = "Shenzhen RuiRen Technology Co Ltd", +[12][0x3c - 1] = "Group Star Technology Co Ltd", +[12][0x3d - 1] = "RWA (Hong Kong) Ltd", +[12][0x3e - 1] = "Genesys Logic Inc", +[12][0x3f - 1] = "T3 Robotics Inc.", +[12][0x40 - 1] = "Biostar Microtech International Corp", +[12][0x41 - 1] = "Shenzhen SXmicro Technology Co Ltd", +[12][0x42 - 1] = "Shanghai Yili Computer Technology Co", +[12][0x43 - 1] = "Zhixin Semicoducotor Co Ltd", +[12][0x44 - 1] = "uFound", +[12][0x45 - 1] = "Aigo Data Security Technology Co. Ltd", +[12][0x46 - 1] = ".GXore Technologies", +[12][0x47 - 1] = "Shenzhen Pradeon Intelligent Technology", +[12][0x48 - 1] = "Power LSI", +[12][0x49 - 1] = "PRIME", +[12][0x4a - 1] = "Shenzhen Juyang Innovative Technology", +[12][0x4b - 1] = "CERVO", +[12][0x4c - 1] = "SiEngine Technology Co., Ltd.", +[12][0x4d - 1] = "Beijing Unigroup Tsingteng MicroSystem", +[12][0x4e - 1] = "Brainsao GmbH", +[12][0x4f - 1] = "Credo Technology Group Ltd", +[12][0x50 - 1] = "Shanghai Biren Technology Co Ltd", +[12][0x51 - 1] = "Nucleu Semiconductor", +[12][0x52 - 1] = "Shenzhen Guangshuo Electronics Co Ltd", +[12][0x53 - 1] = "ZhongsihangTechnology Co Ltd", +[12][0x54 - 1] = "Suzhou Mainshine Electronic Co Ltd.", +[12][0x55 - 1] = "Guangzhou Riss Electronic Technology", +[12][0x56 - 1] = "Shenzhen Cloud Security Storage Co", +[12][0x57 - 1] = "ROG", +[12][0x58 - 1] = "Perceive", +[12][0x59 - 1] = "e-peas", +[12][0x5a - 1] = "Fraunhofer IPMS", +[12][0x5b - 1] = "Shenzhen Daxinlang Electronic Tech Co", +[12][0x5c - 1] = "Abacus Peripherals Private Limited", +[12][0x5d - 1] = "OLOy Technology", +[12][0x5e - 1] = "Wuhan P&S Semiconductor Co Ltd", +[12][0x5f - 1] = "Sitrus Technology", +[12][0x60 - 1] = "AnHui Conner Storage Co Ltd", +[12][0x61 - 1] = "Rochester Electronics", +[12][0x62 - 1] = "Wuxi Petabyte Technologies Co Ltd", +[12][0x63 - 1] = "Star Memory", +[12][0x64 - 1] = "Agile Memory Technology Co Ltd", +[12][0x65 - 1] = "MEJEC", +[12][0x66 - 1] = "Rockchip Electronics Co Ltd", +[12][0x67 - 1] = "Dongguan Guanma e-commerce Co Ltd", +[12][0x68 - 1] = "Rayson Hi-Tech (SZ) Limited", +[12][0x69 - 1] = "MINRES Technologies GmbH", +[12][0x6a - 1] = "Himax Technologies Inc", +[12][0x6b - 1] = "Shenzhen Cwinner Technology Co Ltd", +[12][0x6c - 1] = "Tecmiyo", +[12][0x6d - 1] = "Shenzhen Suhuicun Technology Co Ltd", +[12][0x6e - 1] = "Vickter Electronics Co. Ltd.", +[12][0x6f - 1] = "lowRISC", +[12][0x70 - 1] = "EXEGate FZE", +[12][0x71 - 1] = "Shenzhen 9 Chapter Technologies Co", +[12][0x72 - 1] = "Addlink", +[12][0x73 - 1] = "Starsway", +[12][0x74 - 1] = "Pensando Systems Inc.", +[12][0x75 - 1] = "AirDisk", +[12][0x76 - 1] = "Shenzhen Speedmobile Technology Co", +[12][0x77 - 1] = "PEZY Computing", +[12][0x78 - 1] = "Extreme Engineering Solutions Inc", +[12][0x79 - 1] = "Shangxin Technology Co Ltd", +[12][0x7a - 1] = "Shanghai Zhaoxin Semiconductor Co", +[12][0x7b - 1] = "Xsight Labs Ltd", +[12][0x7c - 1] = "Hangzhou Hikstorage Technology Co", +[12][0x7d - 1] = "Dell Technologies", +[12][0x7e - 1] = "Guangdong StarFive Technology Co", +[13][0x01 - 1] = "TECOTON", +[13][0x02 - 1] = "Abko Co Ltd", +[13][0x03 - 1] = "Shenzhen Feisrike Technology Co Ltd", +[13][0x04 - 1] = "Shenzhen Sunhome Electronics Co Ltd", +[13][0x05 - 1] = "Global Mixed-mode Technology Inc", +[13][0x06 - 1] = "Shenzhen Weien Electronics Co. Ltd.", +[13][0x07 - 1] = "Shenzhen Cooyes Technology Co Ltd", +[13][0x08 - 1] = "Keymos Electronics Co., Limited", +[13][0x09 - 1] = "E-Rockic Technology Company Limited", +[13][0x0a - 1] = "Aerospace Science Memory Shenzhen", +[13][0x0b - 1] = "Shenzhen Quanji Technology Co Ltd", +[13][0x0c - 1] = "Dukosi", +[13][0x0d - 1] = "Maxell Corporation of America", +[13][0x0e - 1] = "Shenshen Xinxintao Electronics Co Ltd", +[13][0x0f - 1] = "Zhuhai Sanxia Semiconductor Co Ltd", +[13][0x10 - 1] = "Groq Inc", +[13][0x11 - 1] = "AstraTek", +[13][0x12 - 1] = "Shenzhen Xinyuze Technology Co Ltd", +[13][0x13 - 1] = "All Bit Semiconductor", +[13][0x14 - 1] = "ACFlow", +[13][0x15 - 1] = "Shenzhen Sipeed Technology Co Ltd", +[13][0x16 - 1] = "Linzhi Hong Kong Co Limited", +[13][0x17 - 1] = "Supreme Wise Limited", +[13][0x18 - 1] = "Blue Cheetah Analog Design Inc", +[13][0x19 - 1] = "Hefei Laiku Technology Co Ltd", +[13][0x1a - 1] = "Zord", +[13][0x1b - 1] = "SBO Hearing A/S", +[13][0x1c - 1] = "Regent Sharp International Limited", +[13][0x1d - 1] = "Permanent Potential Limited", +[13][0x1e - 1] = "Creative World International Limited", +[13][0x1f - 1] = "Base Creation International Limited", +[13][0x20 - 1] = "Shenzhen Zhixin Chuanglian Technology", +[13][0x21 - 1] = "Protected Logic Corporation", +[13][0x22 - 1] = "Sabrent", +[13][0x23 - 1] = "Union Memory", +[13][0x24 - 1] = "NEUCHIPS Corporation", +[13][0x25 - 1] = "Ingenic Semiconductor Co Ltd", +[13][0x26 - 1] = "SiPearl", +[13][0x27 - 1] = "Shenzhen Actseno Information Technology", +[13][0x28 - 1] = "RIVAI Technologies (Shenzhen) Co Ltd", +[13][0x29 - 1] = "Shenzhen Sunny Technology Co Ltd", +[13][0x2a - 1] = "Cott Electronics Ltd", +[13][0x2b - 1] = "Shanghai Synsense Technologies Co Ltd", +[13][0x2c - 1] = "Shenzhen Jintang Fuming Optoelectronics", +[13][0x2d - 1] = "CloudBEAR LLC", +[13][0x2e - 1] = "Emzior, LLC", +[13][0x2f - 1] = "Ehiway Microelectronic Science Tech Co", +[13][0x30 - 1] = "UNIM Innovation Technology (Wu XI)", +[13][0x31 - 1] = "GDRAMARS", +[13][0x32 - 1] = "Meminsights Technology", +[13][0x33 - 1] = "Zhuzhou Hongda Electronics Corp Ltd", +[13][0x34 - 1] = "Luminous Computing Inc", +[13][0x35 - 1] = "PROXMEM", +[13][0x36 - 1] = "Draper Labs", +[13][0x37 - 1] = "ORICO Technologies Co. Ltd.", +[13][0x38 - 1] = "Space Exploration Technologies Corp", +[13][0x39 - 1] = "AONDEVICES Inc", +[13][0x3a - 1] = "Shenzhen Netforward Micro Electronic", +[13][0x3b - 1] = "Syntacore Ltd", +[13][0x3c - 1] = "Shenzhen Secmem Microelectronics Co", +[13][0x3d - 1] = "ONiO As", +[13][0x3e - 1] = "Shenzhen Peladn Technology Co Ltd", +[13][0x3f - 1] = "O-Cubes Shanghai Microelectronics", +[13][0x40 - 1] = "ASTC", +[13][0x41 - 1] = "UMIS", +[13][0x42 - 1] = "Paradromics", +[13][0x43 - 1] = "Sinh Micro Co Ltd", +[13][0x44 - 1] = "Metorage Semiconductor Technology Co", +[13][0x45 - 1] = "Aeva Inc", +[13][0x46 - 1] = "HongKong Hyunion Electronics Co Ltd", +[13][0x47 - 1] = "China Flash Co Ltd", +[13][0x48 - 1] = "Sunplus Technology Co Ltd", +[13][0x49 - 1] = "Idaho Scientific", +[13][0x4a - 1] = "Suzhou SF Micro Electronics Co Ltd", +[13][0x4b - 1] = "IMEX Cap AG", +[13][0x4c - 1] = "Fitipower Integrated Technology Co Ltd", +[13][0x4d - 1] = "ShenzhenWooacme Technology Co Ltd", +[13][0x4e - 1] = "KeepData Original Chips", +[13][0x4f - 1] = "Rivos Inc", +[13][0x50 - 1] = "Big Innovation Company Limited", +[13][0x51 - 1] = "Wuhan YuXin Semiconductor Co Ltd", +[13][0x52 - 1] = "United Memory Technology (Jiangsu)", +[13][0x53 - 1] = "PQShield Ltd", +[13][0x54 - 1] = "ArchiTek Corporation", +[13][0x55 - 1] = "ShenZhen AZW Technology Co Ltd", +[13][0x56 - 1] = "Hengchi Zhixin (Dongguan) Technology", +[13][0x57 - 1] = "Eggtronic Engineering Spa", +[13][0x58 - 1] = "Fusontai Technology", +[13][0x59 - 1] = "PULP Platform", +[13][0x5a - 1] = "Koitek Electronic Technology (Shenzhen) Co", +[13][0x5b - 1] = "Shenzhen Jiteng Network Technology Co", +[13][0x5c - 1] = "Aviva Links Inc", +[13][0x5d - 1] = "Trilinear Technologies Inc", +[13][0x5e - 1] = "Shenzhen Developer Microelectronics Co", +[13][0x5f - 1] = "Guangdong OPPO Mobile Telecommunication", +[13][0x60 - 1] = "Akeana", +[13][0x61 - 1] = "Lyczar", +[13][0x62 - 1] = "Shenzhen Qiji Technology Co Ltd", +[13][0x63 - 1] = "Shenzhen Shangzhaoyuan Technology", +[13][0x64 - 1] = "Han Stor", +[13][0x65 - 1] = "China Micro Semicon Co., Ltd.", +[13][0x66 - 1] = "Shenzhen Zhuqin Technology Co Ltd", +[13][0x67 - 1] = "Shanghai Ningyuan Electronic Technology", +[13][0x68 - 1] = "Auradine", +[13][0x69 - 1] = "Suzhou Yishuo Electronics Co Ltd", +[13][0x6a - 1] = "Faurecia Clarion Electronics", +[13][0x6b - 1] = "SiMa Technologies", +[13][0x6c - 1] = "CFD Sales Inc", +[13][0x6d - 1] = "Suzhou Comay Information Co Ltd", +[13][0x6e - 1] = "Yentek", +[13][0x6f - 1] = "Qorvo Inc", +[13][0x70 - 1] = "Shenzhen Youzhi Computer Technology", +[13][0x71 - 1] = "Sychw Technology (Shenzhen) Co Ltd", +[13][0x72 - 1] = "MK Founder Technology Co Ltd", +[13][0x73 - 1] = "Siliconwaves Technologies Co Ltd", +[13][0x74 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[13][0x75 - 1] = "Shenzhen Xinxinzhitao Electronics Business", +[13][0x76 - 1] = "Shenzhen HenQi Electronic Commerce Co", +[13][0x77 - 1] = "Shenzhen Jingyi Technology Co Ltd", +[13][0x78 - 1] = "Xiaohua Semiconductor Co. Ltd.", +[13][0x79 - 1] = "Shenzhen Dalu Semiconductor Technology", +[13][0x7a - 1] = "Shenzhen Ninespeed Electronics Co Ltd", +[13][0x7b - 1] = "ICYC Semiconductor Co Ltd", +[13][0x7c - 1] = "Shenzhen Jaguar Microsystems Co Ltd", +[13][0x7d - 1] = "Beijing EC-Founder Co Ltd", +[13][0x7e - 1] = "Shenzhen Taike Industrial Automation Co", +[14][0x01 - 1] = "Kalray SA", +[14][0x02 - 1] = "Shanghai Iluvatar CoreX Semiconductor Co", +[14][0x03 - 1] = "Fungible Inc", +[14][0x04 - 1] = "Song Industria E Comercio de Eletronicos", +[14][0x05 - 1] = "DreamBig Semiconductor Inc", +[14][0x06 - 1] = "ChampTek Electronics Corp", +[14][0x07 - 1] = "Fusontai Technology", +[14][0x08 - 1] = "Endress Hauser AG", +[14][0x09 - 1] = "altec ComputerSysteme GmbH", +[14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd", +[14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd", +[14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd", +/* EOF */ diff --git a/applications/plugins/swd_probe/model/chip.ply b/applications/plugins/swd_probe/model/chip.ply new file mode 100644 index 0000000000..7dc20abfaf --- /dev/null +++ b/applications/plugins/swd_probe/model/chip.ply @@ -0,0 +1,216 @@ +ply +format ascii 1.0 +comment Created by Blender 3.3.1 - www.blender.org +element vertex 136 +property float x +property float y +property float z +element face 70 +property list uchar uint vertex_indices +end_header +1.000000 1.000000 0.152153 +-1.000000 1.000000 0.152153 +-1.000000 -1.000000 0.152153 +1.000000 -1.000000 0.152153 +1.000000 -1.000000 -0.185787 +-1.000000 -1.000000 -0.185787 +-1.000000 1.000000 -0.185787 +1.000000 1.000000 -0.185787 +-1.000043 -0.785071 -0.015780 +-1.155724 -0.785071 -0.015780 +-1.155724 -0.918718 -0.015780 +-1.000043 -0.918718 -0.015780 +-1.155724 -0.785071 0.127052 +-1.000043 -0.785071 0.127052 +-1.000043 -0.918718 0.127052 +-1.155724 -0.918718 0.127052 +-1.234192 -0.918846 -0.087021 +-1.234397 -0.785201 -0.086336 +-1.235319 -0.784943 -0.229143 +-1.235114 -0.918588 -0.229828 +-1.388133 -0.919573 -0.078673 +-1.389056 -0.919314 -0.221479 +-1.389261 -0.785669 -0.220795 +-1.388338 -0.785927 -0.077988 +-1.000043 -0.219627 -0.015780 +-1.155724 -0.219627 -0.015780 +-1.155724 -0.353273 -0.015780 +-1.000043 -0.353273 -0.015780 +-1.155724 -0.219627 0.127052 +-1.000043 -0.219627 0.127052 +-1.000043 -0.353273 0.127052 +-1.155724 -0.353273 0.127052 +-1.234192 -0.353402 -0.087021 +-1.234397 -0.219756 -0.086336 +-1.235319 -0.219498 -0.229143 +-1.235114 -0.353143 -0.229828 +-1.388133 -0.354128 -0.078673 +-1.389056 -0.353870 -0.221479 +-1.389261 -0.220224 -0.220795 +-1.388338 -0.220482 -0.077988 +-1.000043 0.345818 -0.015780 +-1.155724 0.345818 -0.015780 +-1.155724 0.212172 -0.015780 +-1.000043 0.212172 -0.015780 +-1.155724 0.345818 0.127052 +-1.000043 0.345818 0.127052 +-1.000043 0.212172 0.127052 +-1.155724 0.212172 0.127052 +-1.234192 0.212043 -0.087021 +-1.234397 0.345689 -0.086336 +-1.235319 0.345947 -0.229143 +-1.235114 0.212301 -0.229828 +-1.388133 0.211317 -0.078673 +-1.389056 0.211575 -0.221479 +-1.389261 0.345221 -0.220795 +-1.388338 0.344962 -0.077988 +-1.000043 0.911263 -0.015780 +-1.155724 0.911263 -0.015780 +-1.155724 0.777617 -0.015780 +-1.000043 0.777617 -0.015780 +-1.155724 0.911263 0.127052 +-1.000043 0.911263 0.127052 +-1.000043 0.777617 0.127052 +-1.155724 0.777617 0.127052 +-1.234192 0.777488 -0.087021 +-1.234397 0.911133 -0.086336 +-1.235319 0.911392 -0.229143 +-1.235114 0.777746 -0.229828 +-1.388133 0.776762 -0.078673 +-1.389056 0.777020 -0.221479 +-1.389261 0.910665 -0.220795 +-1.388338 0.910407 -0.077988 +1.000043 -0.785071 -0.015780 +1.000043 -0.918718 -0.015780 +1.155723 -0.918718 -0.015780 +1.155723 -0.785071 -0.015780 +1.155723 -0.785071 0.127052 +1.155723 -0.918718 0.127052 +1.000043 -0.918718 0.127052 +1.000043 -0.785071 0.127052 +1.234397 -0.785201 -0.086336 +1.234192 -0.918846 -0.087021 +1.235114 -0.918588 -0.229828 +1.235319 -0.784943 -0.229143 +1.388133 -0.919573 -0.078673 +1.388338 -0.785927 -0.077988 +1.389260 -0.785669 -0.220795 +1.389056 -0.919314 -0.221479 +1.000043 -0.219627 -0.015780 +1.000043 -0.353273 -0.015780 +1.155723 -0.353273 -0.015780 +1.155723 -0.219627 -0.015780 +1.155723 -0.219627 0.127052 +1.155723 -0.353273 0.127052 +1.000043 -0.353273 0.127052 +1.000043 -0.219627 0.127052 +1.234397 -0.219756 -0.086336 +1.234192 -0.353402 -0.087021 +1.235114 -0.353143 -0.229828 +1.235319 -0.219498 -0.229143 +1.388133 -0.354128 -0.078673 +1.388338 -0.220482 -0.077988 +1.389260 -0.220224 -0.220795 +1.389056 -0.353870 -0.221479 +1.000043 0.345818 -0.015780 +1.000043 0.212172 -0.015780 +1.155723 0.212172 -0.015780 +1.155723 0.345818 -0.015780 +1.155723 0.345818 0.127052 +1.155723 0.212172 0.127052 +1.000043 0.212172 0.127052 +1.000043 0.345818 0.127052 +1.234397 0.345689 -0.086336 +1.234192 0.212043 -0.087021 +1.235114 0.212301 -0.229828 +1.235319 0.345947 -0.229143 +1.388133 0.211317 -0.078673 +1.388338 0.344962 -0.077988 +1.389260 0.345221 -0.220795 +1.389056 0.211575 -0.221479 +1.000043 0.911263 -0.015780 +1.000043 0.777616 -0.015780 +1.155723 0.777616 -0.015780 +1.155723 0.911263 -0.015780 +1.155723 0.911263 0.127052 +1.155723 0.777616 0.127052 +1.000043 0.777616 0.127052 +1.000043 0.911263 0.127052 +1.234397 0.911133 -0.086336 +1.234192 0.777488 -0.087021 +1.235114 0.777746 -0.229828 +1.235319 0.911392 -0.229143 +1.388133 0.776762 -0.078673 +1.388338 0.910407 -0.077988 +1.389260 0.910665 -0.220795 +1.389056 0.777020 -0.221479 +4 0 1 2 3 +4 4 3 2 5 +4 5 2 1 6 +4 6 7 4 5 +4 7 0 3 4 +4 6 1 0 7 +4 8 9 10 11 +4 12 13 14 15 +4 13 8 11 14 +4 12 15 16 17 +4 10 9 18 19 +4 20 21 22 23 +4 17 16 20 23 +4 19 18 22 21 +4 24 25 26 27 +4 28 29 30 31 +4 29 24 27 30 +4 28 31 32 33 +4 26 25 34 35 +4 36 37 38 39 +4 33 32 36 39 +4 35 34 38 37 +4 40 41 42 43 +4 44 45 46 47 +4 45 40 43 46 +4 44 47 48 49 +4 42 41 50 51 +4 52 53 54 55 +4 49 48 52 55 +4 51 50 54 53 +4 56 57 58 59 +4 60 61 62 63 +4 61 56 59 62 +4 60 63 64 65 +4 58 57 66 67 +4 68 69 70 71 +4 65 64 68 71 +4 67 66 70 69 +4 72 73 74 75 +4 76 77 78 79 +4 79 78 73 72 +4 76 80 81 77 +4 74 82 83 75 +4 84 85 86 87 +4 80 85 84 81 +4 82 87 86 83 +4 88 89 90 91 +4 92 93 94 95 +4 95 94 89 88 +4 92 96 97 93 +4 90 98 99 91 +4 100 101 102 103 +4 96 101 100 97 +4 98 103 102 99 +4 104 105 106 107 +4 108 109 110 111 +4 111 110 105 104 +4 108 112 113 109 +4 106 114 115 107 +4 116 117 118 119 +4 112 117 116 113 +4 114 119 118 115 +4 120 121 122 123 +4 124 125 126 127 +4 127 126 121 120 +4 124 128 129 125 +4 122 130 131 123 +4 132 133 134 135 +4 128 133 132 129 +4 130 135 134 131 diff --git a/applications/plugins/swd_probe/model/convert.py b/applications/plugins/swd_probe/model/convert.py new file mode 100644 index 0000000000..7c99ca215e --- /dev/null +++ b/applications/plugins/swd_probe/model/convert.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import plyfile +import argparse + +parser = argparse.ArgumentParser(description='Convert a PLY file to C arrays.') +parser.add_argument('input_file', help='the input PLY file') +parser.add_argument('output_file', help='the output C file') +args = parser.parse_args() + +# Open the PLY file +plydata = plyfile.PlyData.read(args.input_file) + +# Extract the vertices +vertices = plydata['vertex'].data +num_vertices = len(vertices) + +with open(args.output_file, 'w') as f: + f.write('#define NUM_VERTICES %d\n' % num_vertices) + f.write('float vertexCoords[NUM_VERTICES][3] = {\n') + for i in range(num_vertices): + x, y, z = vertices[i][0], vertices[i][1], vertices[i][2] + f.write(' {%f, %f, %f},\n' % (x, y, z)) + f.write('};') + + # Extract the faces + faces = plydata['face'].data + num_faces = len(faces) + f.write('int edgeIndices[][3] = {\n') + for i in range(num_faces): + face = faces[i][0] + if len(face) == 3: + f.write(' {%d, %d, %d},\n' % (face[0], face[1], face[2])) + elif len(face) == 4: + # Convert 4-index face to 2-index edges + edges = [(face[0], face[1]), (face[1], face[2]), (face[2], face[3]), (face[3], face[0])] + for edge in edges: + f.write(' {%d, %d},\n' % (edge[0], edge[1])) + f.write('};\n') diff --git a/applications/plugins/swd_probe/model/model_chip.h b/applications/plugins/swd_probe/model/model_chip.h new file mode 100644 index 0000000000..ed96105af9 --- /dev/null +++ b/applications/plugins/swd_probe/model/model_chip.h @@ -0,0 +1,420 @@ +#define NUM_VERTICES 136 +float vertexCoords[NUM_VERTICES][3] = { + {1.000000, 1.000000, 0.152153}, + {-1.000000, 1.000000, 0.152153}, + {-1.000000, -1.000000, 0.152153}, + {1.000000, -1.000000, 0.152153}, + {1.000000, -1.000000, -0.185787}, + {-1.000000, -1.000000, -0.185787}, + {-1.000000, 1.000000, -0.185787}, + {1.000000, 1.000000, -0.185787}, + {-1.000043, -0.785071, -0.015780}, + {-1.155724, -0.785071, -0.015780}, + {-1.155724, -0.918718, -0.015780}, + {-1.000043, -0.918718, -0.015780}, + {-1.155724, -0.785071, 0.127052}, + {-1.000043, -0.785071, 0.127052}, + {-1.000043, -0.918718, 0.127052}, + {-1.155724, -0.918718, 0.127052}, + {-1.234192, -0.918846, -0.087021}, + {-1.234397, -0.785201, -0.086336}, + {-1.235319, -0.784943, -0.229143}, + {-1.235114, -0.918588, -0.229828}, + {-1.388133, -0.919573, -0.078673}, + {-1.389056, -0.919314, -0.221479}, + {-1.389261, -0.785669, -0.220795}, + {-1.388338, -0.785927, -0.077988}, + {-1.000043, -0.219627, -0.015780}, + {-1.155724, -0.219627, -0.015780}, + {-1.155724, -0.353273, -0.015780}, + {-1.000043, -0.353273, -0.015780}, + {-1.155724, -0.219627, 0.127052}, + {-1.000043, -0.219627, 0.127052}, + {-1.000043, -0.353273, 0.127052}, + {-1.155724, -0.353273, 0.127052}, + {-1.234192, -0.353402, -0.087021}, + {-1.234397, -0.219756, -0.086336}, + {-1.235319, -0.219498, -0.229143}, + {-1.235114, -0.353143, -0.229828}, + {-1.388133, -0.354128, -0.078673}, + {-1.389056, -0.353870, -0.221479}, + {-1.389261, -0.220224, -0.220795}, + {-1.388338, -0.220482, -0.077988}, + {-1.000043, 0.345818, -0.015780}, + {-1.155724, 0.345818, -0.015780}, + {-1.155724, 0.212172, -0.015780}, + {-1.000043, 0.212172, -0.015780}, + {-1.155724, 0.345818, 0.127052}, + {-1.000043, 0.345818, 0.127052}, + {-1.000043, 0.212172, 0.127052}, + {-1.155724, 0.212172, 0.127052}, + {-1.234192, 0.212043, -0.087021}, + {-1.234397, 0.345689, -0.086336}, + {-1.235319, 0.345947, -0.229143}, + {-1.235114, 0.212301, -0.229828}, + {-1.388133, 0.211317, -0.078673}, + {-1.389056, 0.211575, -0.221479}, + {-1.389261, 0.345221, -0.220795}, + {-1.388338, 0.344962, -0.077988}, + {-1.000043, 0.911263, -0.015780}, + {-1.155724, 0.911263, -0.015780}, + {-1.155724, 0.777617, -0.015780}, + {-1.000043, 0.777617, -0.015780}, + {-1.155724, 0.911263, 0.127052}, + {-1.000043, 0.911263, 0.127052}, + {-1.000043, 0.777617, 0.127052}, + {-1.155724, 0.777617, 0.127052}, + {-1.234192, 0.777488, -0.087021}, + {-1.234397, 0.911133, -0.086336}, + {-1.235319, 0.911392, -0.229143}, + {-1.235114, 0.777746, -0.229828}, + {-1.388133, 0.776762, -0.078673}, + {-1.389056, 0.777020, -0.221479}, + {-1.389261, 0.910665, -0.220795}, + {-1.388338, 0.910407, -0.077988}, + {1.000043, -0.785071, -0.015780}, + {1.000043, -0.918718, -0.015780}, + {1.155723, -0.918718, -0.015780}, + {1.155723, -0.785071, -0.015780}, + {1.155723, -0.785071, 0.127052}, + {1.155723, -0.918718, 0.127052}, + {1.000043, -0.918718, 0.127052}, + {1.000043, -0.785071, 0.127052}, + {1.234397, -0.785201, -0.086336}, + {1.234192, -0.918846, -0.087021}, + {1.235114, -0.918588, -0.229828}, + {1.235319, -0.784943, -0.229143}, + {1.388133, -0.919573, -0.078673}, + {1.388338, -0.785927, -0.077988}, + {1.389260, -0.785669, -0.220795}, + {1.389056, -0.919314, -0.221479}, + {1.000043, -0.219627, -0.015780}, + {1.000043, -0.353273, -0.015780}, + {1.155723, -0.353273, -0.015780}, + {1.155723, -0.219627, -0.015780}, + {1.155723, -0.219627, 0.127052}, + {1.155723, -0.353273, 0.127052}, + {1.000043, -0.353273, 0.127052}, + {1.000043, -0.219627, 0.127052}, + {1.234397, -0.219756, -0.086336}, + {1.234192, -0.353402, -0.087021}, + {1.235114, -0.353143, -0.229828}, + {1.235319, -0.219498, -0.229143}, + {1.388133, -0.354128, -0.078673}, + {1.388338, -0.220482, -0.077988}, + {1.389260, -0.220224, -0.220795}, + {1.389056, -0.353870, -0.221479}, + {1.000043, 0.345818, -0.015780}, + {1.000043, 0.212172, -0.015780}, + {1.155723, 0.212172, -0.015780}, + {1.155723, 0.345818, -0.015780}, + {1.155723, 0.345818, 0.127052}, + {1.155723, 0.212172, 0.127052}, + {1.000043, 0.212172, 0.127052}, + {1.000043, 0.345818, 0.127052}, + {1.234397, 0.345689, -0.086336}, + {1.234192, 0.212043, -0.087021}, + {1.235114, 0.212301, -0.229828}, + {1.235319, 0.345947, -0.229143}, + {1.388133, 0.211317, -0.078673}, + {1.388338, 0.344962, -0.077988}, + {1.389260, 0.345221, -0.220795}, + {1.389056, 0.211575, -0.221479}, + {1.000043, 0.911263, -0.015780}, + {1.000043, 0.777616, -0.015780}, + {1.155723, 0.777616, -0.015780}, + {1.155723, 0.911263, -0.015780}, + {1.155723, 0.911263, 0.127052}, + {1.155723, 0.777616, 0.127052}, + {1.000043, 0.777616, 0.127052}, + {1.000043, 0.911263, 0.127052}, + {1.234397, 0.911133, -0.086336}, + {1.234192, 0.777488, -0.087021}, + {1.235114, 0.777746, -0.229828}, + {1.235319, 0.911392, -0.229143}, + {1.388133, 0.776762, -0.078673}, + {1.388338, 0.910407, -0.077988}, + {1.389260, 0.910665, -0.220795}, + {1.389056, 0.777020, -0.221479}, +};int edgeIndices[][3] = { + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + {4, 3}, + {3, 2}, + {2, 5}, + {5, 4}, + {5, 2}, + {2, 1}, + {1, 6}, + {6, 5}, + {6, 7}, + {7, 4}, + {4, 5}, + {5, 6}, + {7, 0}, + {0, 3}, + {3, 4}, + {4, 7}, + {6, 1}, + {1, 0}, + {0, 7}, + {7, 6}, + {8, 9}, + {9, 10}, + {10, 11}, + {11, 8}, + {12, 13}, + {13, 14}, + {14, 15}, + {15, 12}, + {13, 8}, + {8, 11}, + {11, 14}, + {14, 13}, + {12, 15}, + {15, 16}, + {16, 17}, + {17, 12}, + {10, 9}, + {9, 18}, + {18, 19}, + {19, 10}, + {20, 21}, + {21, 22}, + {22, 23}, + {23, 20}, + {17, 16}, + {16, 20}, + {20, 23}, + {23, 17}, + {19, 18}, + {18, 22}, + {22, 21}, + {21, 19}, + {24, 25}, + {25, 26}, + {26, 27}, + {27, 24}, + {28, 29}, + {29, 30}, + {30, 31}, + {31, 28}, + {29, 24}, + {24, 27}, + {27, 30}, + {30, 29}, + {28, 31}, + {31, 32}, + {32, 33}, + {33, 28}, + {26, 25}, + {25, 34}, + {34, 35}, + {35, 26}, + {36, 37}, + {37, 38}, + {38, 39}, + {39, 36}, + {33, 32}, + {32, 36}, + {36, 39}, + {39, 33}, + {35, 34}, + {34, 38}, + {38, 37}, + {37, 35}, + {40, 41}, + {41, 42}, + {42, 43}, + {43, 40}, + {44, 45}, + {45, 46}, + {46, 47}, + {47, 44}, + {45, 40}, + {40, 43}, + {43, 46}, + {46, 45}, + {44, 47}, + {47, 48}, + {48, 49}, + {49, 44}, + {42, 41}, + {41, 50}, + {50, 51}, + {51, 42}, + {52, 53}, + {53, 54}, + {54, 55}, + {55, 52}, + {49, 48}, + {48, 52}, + {52, 55}, + {55, 49}, + {51, 50}, + {50, 54}, + {54, 53}, + {53, 51}, + {56, 57}, + {57, 58}, + {58, 59}, + {59, 56}, + {60, 61}, + {61, 62}, + {62, 63}, + {63, 60}, + {61, 56}, + {56, 59}, + {59, 62}, + {62, 61}, + {60, 63}, + {63, 64}, + {64, 65}, + {65, 60}, + {58, 57}, + {57, 66}, + {66, 67}, + {67, 58}, + {68, 69}, + {69, 70}, + {70, 71}, + {71, 68}, + {65, 64}, + {64, 68}, + {68, 71}, + {71, 65}, + {67, 66}, + {66, 70}, + {70, 69}, + {69, 67}, + {72, 73}, + {73, 74}, + {74, 75}, + {75, 72}, + {76, 77}, + {77, 78}, + {78, 79}, + {79, 76}, + {79, 78}, + {78, 73}, + {73, 72}, + {72, 79}, + {76, 80}, + {80, 81}, + {81, 77}, + {77, 76}, + {74, 82}, + {82, 83}, + {83, 75}, + {75, 74}, + {84, 85}, + {85, 86}, + {86, 87}, + {87, 84}, + {80, 85}, + {85, 84}, + {84, 81}, + {81, 80}, + {82, 87}, + {87, 86}, + {86, 83}, + {83, 82}, + {88, 89}, + {89, 90}, + {90, 91}, + {91, 88}, + {92, 93}, + {93, 94}, + {94, 95}, + {95, 92}, + {95, 94}, + {94, 89}, + {89, 88}, + {88, 95}, + {92, 96}, + {96, 97}, + {97, 93}, + {93, 92}, + {90, 98}, + {98, 99}, + {99, 91}, + {91, 90}, + {100, 101}, + {101, 102}, + {102, 103}, + {103, 100}, + {96, 101}, + {101, 100}, + {100, 97}, + {97, 96}, + {98, 103}, + {103, 102}, + {102, 99}, + {99, 98}, + {104, 105}, + {105, 106}, + {106, 107}, + {107, 104}, + {108, 109}, + {109, 110}, + {110, 111}, + {111, 108}, + {111, 110}, + {110, 105}, + {105, 104}, + {104, 111}, + {108, 112}, + {112, 113}, + {113, 109}, + {109, 108}, + {106, 114}, + {114, 115}, + {115, 107}, + {107, 106}, + {116, 117}, + {117, 118}, + {118, 119}, + {119, 116}, + {112, 117}, + {117, 116}, + {116, 113}, + {113, 112}, + {114, 119}, + {119, 118}, + {118, 115}, + {115, 114}, + {120, 121}, + {121, 122}, + {122, 123}, + {123, 120}, + {124, 125}, + {125, 126}, + {126, 127}, + {127, 124}, + {127, 126}, + {126, 121}, + {121, 120}, + {120, 127}, + {124, 128}, + {128, 129}, + {129, 125}, + {125, 124}, + {122, 130}, + {130, 131}, + {131, 123}, + {123, 122}, + {132, 133}, + {133, 134}, + {134, 135}, + {135, 132}, + {128, 133}, + {133, 132}, + {132, 129}, + {129, 128}, + {130, 135}, + {135, 134}, + {134, 131}, + {131, 130}, +}; diff --git a/applications/plugins/swd_probe/swd_probe_app.c b/applications/plugins/swd_probe/swd_probe_app.c new file mode 100644 index 0000000000..fcebd8348f --- /dev/null +++ b/applications/plugins/swd_probe/swd_probe_app.c @@ -0,0 +1,2840 @@ + + +#include "swd_probe_app.h" +#include "swd_probe_icons.h" +#include "jep106.h" +#include "adi.h" + +static void render_callback(Canvas* const canvas, void* cb_ctx); +static bool swd_message_process(AppFSM* ctx); +static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data); +static bool swd_execute_script(AppFSM* const ctx, const char* filename); + +static const GpioPin* gpios[] = { + &gpio_ext_pc0, + &gpio_ext_pc1, + &gpio_ext_pc3, + &gpio_ext_pb2, + &gpio_ext_pb3, + &gpio_ext_pa4, + &gpio_ext_pa6, + &gpio_ext_pa7}; + +static const char* gpio_names[] = {"PC0", "PC1", "PC3", "PB2", "PB3", "PA4", "PA6", "PA7"}; + +/* bit set: clock, else data */ +static const uint8_t gpio_direction_mask[6] = + {0b10101010, 0b01010101, 0b11001100, 0b00110011, 0b11110000, 0b00001111}; + +const NotificationSequence seq_c_minor = { + &message_note_c4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_g4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +const NotificationSequence seq_error = { + + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + + &message_note_g4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_c4, + &message_delay_500, + &message_sound_off, + &message_delay_10, + NULL, +}; + +const NotificationSequence* seq_sounds[] = {&seq_c_minor, &seq_error}; + +static bool has_multiple_bits(uint8_t x) { + return (x & (x - 1)) != 0; +} + +static uint8_t get_bit_num(uint8_t x) { + return (uint8_t)__builtin_ctz(x); +} + +static const char* gpio_name(uint8_t mask) { + if(has_multiple_bits(mask)) { + return "Pxx"; + } + uint8_t io = get_bit_num(mask); + if(io >= COUNT(gpio_names)) { + return "Pxx"; + } + + return gpio_names[io]; +} + +static void swd_configure_pins(AppFSM* const ctx, bool output) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swc < 8 && ctx->io_num_swd < 8) { + furi_hal_gpio_init( + gpios[ctx->io_num_swc], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + if(!output) { + furi_hal_gpio_init( + gpios[ctx->io_num_swd], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + } else { + furi_hal_gpio_init( + gpios[ctx->io_num_swd], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); + } + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if neither candidate for SWC nor SWD then skip */ + if(!(ctx->io_swc & bitmask) && !(ctx->io_swd & bitmask)) { + furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + continue; + } + + if(ctx->current_mask & bitmask) { + /* set for clock */ + furi_hal_gpio_init(gpios[io], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else { + /* set for data */ + if(!output) { + furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + } else { + furi_hal_gpio_init( + gpios[io], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); + } + } + } +} + +static void swd_set_clock(AppFSM* const ctx, const uint8_t level) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swc < 8) { + furi_hal_gpio_write(gpios[ctx->io_num_swc], level); + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWC then skip */ + if(!(ctx->io_swc & bitmask)) { + continue; + } + + if(ctx->current_mask & bitmask) { + furi_hal_gpio_write(gpios[io], level); + } + } +} + +static void swd_set_data(AppFSM* const ctx, const uint8_t level) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swd < 8) { + furi_hal_gpio_write(gpios[ctx->io_num_swd], level); + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWD then skip */ + if(!(ctx->io_swd & bitmask)) { + continue; + } + + if(!(ctx->current_mask & bitmask)) { + furi_hal_gpio_write(gpios[io], level); + } + } +} + +static uint8_t swd_get_data(AppFSM* const ctx) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swd < 8) { + return furi_hal_gpio_read(gpios[ctx->io_num_swd]); + } + + uint8_t bits = 0; + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWD then skip */ + if(!(ctx->io_swd & bitmask)) { + continue; + } + bits |= furi_hal_gpio_read(gpios[io]) ? bitmask : 0; + } + return bits; +} + +static void swd_clock_delay(AppFSM* const ctx) { + if(ctx->swd_clock_delay) { + furi_delay_us(ctx->swd_clock_delay); + } +} + +static void swd_write_bit(AppFSM* const ctx, bool level) { + swd_set_clock(ctx, 0); + swd_set_data(ctx, level); + swd_clock_delay(ctx); + swd_set_clock(ctx, 1); + swd_clock_delay(ctx); + swd_set_clock(ctx, 0); +} + +static uint8_t swd_read_bit(AppFSM* const ctx) { + swd_set_clock(ctx, 1); + swd_clock_delay(ctx); + swd_set_clock(ctx, 0); + uint8_t bits = swd_get_data(ctx); + swd_clock_delay(ctx); + swd_set_clock(ctx, 1); + + return bits; +} + +/* send a byte or less LSB-first */ +static void swd_write_byte(AppFSM* const ctx, const uint8_t data, size_t bits) { + for(size_t pos = 0; pos < bits; pos++) { + swd_write_bit(ctx, data & (1 << pos)); + } +} + +/* send a sequence of bytes LSB-first */ +static void swd_write(AppFSM* const ctx, const uint8_t* data, size_t bits) { + size_t byte_pos = 0; + while(bits > 0) { + size_t remain = (bits > 8) ? 8 : bits; + swd_write_byte(ctx, data[byte_pos++], remain); + bits -= remain; + } +} + +static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data) { + //notification_message(ctx->notification, &sequence_set_blue_255); + //notification_message(ctx->notification, &sequence_reset_red); + + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + uint32_t idle = 0; + swd_write(ctx, (uint8_t*)&idle, ctx->swd_idle_bits); + + uint8_t request[] = {0}; + + request[0] |= 0x01; /* start bit*/ + request[0] |= ap ? 0x02 : 0; /* APnDP */ + request[0] |= write ? 0 : 0x04; /* operation */ + request[0] |= (a23 & 0x01) ? 0x08 : 0; /* A[2:3] */ + request[0] |= (a23 & 0x02) ? 0x10 : 0; /* A[2:3] */ + request[0] |= 0x80; /* park bit */ + request[0] |= __builtin_parity(request[0]) ? 0x20 : 0; /* parity */ + + swd_write(ctx, request, sizeof(request) * 8); + + /* turnaround cycle */ + swd_configure_pins(ctx, false); + + uint8_t ack = 0; + + /* receive 3 ACK bits */ + for(int pos = 0; pos < 3; pos++) { + ack >>= 1; + ack |= swd_read_bit(ctx) ? 0x04 : 0; + } + + /* force ABORT/CTRL to always work */ + if(!ap && a23 == 0) { + ack = 1; + } + + if(ack != 0x01) { + //notification_message(ctx->notification, &sequence_reset_blue); + //notification_message(ctx->notification, &sequence_set_red_255); + return ack; + } + + if(write) { + swd_write_bit(ctx, 0); + swd_configure_pins(ctx, true); + + /* send 32 WDATA bits */ + for(int pos = 0; pos < 32; pos++) { + swd_write_bit(ctx, *data & (1 << pos)); + } + + /* send parity bit */ + swd_write_bit(ctx, __builtin_parity(*data)); + } else { + *data = 0; + /* receive 32 RDATA bits */ + for(int pos = 0; pos < 32; pos++) { + *data >>= 1; + *data |= swd_read_bit(ctx) ? 0x80000000 : 0; + } + + /* receive parity bit */ + bool parity = swd_read_bit(ctx); + + if(parity != __builtin_parity(*data)) { + //notification_message(ctx->notification, &sequence_reset_blue); + //notification_message(ctx->notification, &sequence_set_red_255); + return 8; + } + } + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + //notification_message(ctx->notification, &sequence_reset_blue); + + return ack; +} + +/* A line reset is achieved by holding the data signal HIGH for at least 50 clock cycles, followed by at least two idle cycles. */ +static void swd_line_reset(AppFSM* const ctx) { + //notification_message(ctx->notification, &sequence_set_red_255); + for(int bitcount = 0; bitcount < 50; bitcount += 8) { + swd_write_byte(ctx, 0xFF, 8); + } + swd_write_byte(ctx, 0, 8); + ctx->dp_regs.select_ok = false; + //notification_message(ctx->notification, &sequence_reset_red); +} + +static void swd_abort(AppFSM* const ctx) { + uint32_t dpidr; + + /* first reset the line */ + swd_line_reset(ctx); + swd_transfer(ctx, false, false, 0, &dpidr); + uint32_t abort = 0x0E; + swd_transfer(ctx, false, true, 0, &abort); +} + +static void swd_abort_simple(AppFSM* const ctx) { + uint32_t abort = 0x0E; + swd_transfer(ctx, false, true, 0, &abort); + + uint32_t dpidr; + if(swd_transfer(ctx, false, false, 0, &dpidr) != 1) { + swd_abort(ctx); + } +} + +static uint8_t swd_select(AppFSM* const ctx, uint8_t ap_sel, uint8_t ap_bank, uint8_t dp_bank) { + uint32_t bank_reg = (ap_sel << 24) | ((ap_bank & 0x0F) << 4) | (dp_bank & 0x0F); + + if(ctx->dp_regs.select_ok && bank_reg == ctx->dp_regs.select) { + return 1; + } + + uint8_t ret = swd_transfer(ctx, false, true, REG_SELECT, &bank_reg); + if(ret != 1) { + ctx->dp_regs.select_ok = false; + DBG("failed: %d", ret); + return ret; + } + + ctx->dp_regs.select = bank_reg; + ctx->dp_regs.select_ok = true; + return ret; +} + +static uint8_t + swd_read_dpbank(AppFSM* const ctx, uint8_t dp_off, uint8_t dp_bank, uint32_t* data) { + uint8_t ret = 0; + + /* select target bank */ + if(dp_bank < 0x10) { + uint8_t ret = swd_select(ctx, 0, 0, dp_bank); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + } + + /* read data from it */ + *data = 0; + ret = swd_transfer(ctx, false, false, dp_off, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t + swd_write_dpbank(AppFSM* const ctx, uint8_t dp_off, uint8_t dp_bank, uint32_t* data) { + uint8_t ret = 0; + + /* select target bank */ + if(dp_bank < 0x10) { + ret = swd_select(ctx, 0, 0, dp_bank); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + } + + /* write it */ + ret = swd_transfer(ctx, false, true, dp_off, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_read_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) { + /* select target bank */ + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + *data = 0; + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_read_ap_single(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) { + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + *data = 0; + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_write_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t data) { + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + ret = swd_transfer(ctx, true, true, (ap_off >> 2) & 3, &data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_write_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t data) { + uint8_t ret = 0; + uint32_t csw = 0x23000002; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_write_ap(ctx, ap, MEMAP_DRW, data); + DBG("write 0x%08lX to 0x%08lX", data, address); + + if(ret != 1) { + swd_abort(ctx); + } + return ret; +} + +uint8_t swd_read_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t* data) { + uint8_t ret = 0; + uint32_t csw = 0x23000002; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_read_ap(ctx, ap, MEMAP_DRW, data); + + if(ret != 1) { + swd_abort(ctx); + } + return ret; +} + +static uint8_t swd_read_memory_block( + AppFSM* const ctx, + uint8_t ap, + uint32_t address, + uint8_t* buf, + uint32_t len) { + uint8_t ret = 0; + uint32_t data = 0; + uint32_t csw = 0x23000012; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data); + + for(size_t pos = 0; pos < len; pos += 4) { + data = 0xDEADBEEF; + ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data); + DBG("read %lX", data); + + memcpy(&buf[pos], &data, 4); + + if(ret != 1) { + swd_abort(ctx); + return ret; + } + } + return ret; +} + +static uint32_t swd_detect(AppFSM* const ctx) { + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + uint8_t data[] = {0xA5}; + swd_write(ctx, data, sizeof(data) * 8); + + /* turnaround cycle */ + swd_configure_pins(ctx, false); + + uint8_t ack_bits[3]; + uint8_t rdata[32]; + + /* receive 3 ACK bits */ + for(int pos = 0; pos < 3; pos++) { + ack_bits[pos] = swd_read_bit(ctx); + } + + /* receive 32 RDATA bits */ + for(int pos = 0; pos < 32; pos++) { + rdata[pos] = swd_read_bit(ctx); + } + + /* receive parity bit */ + uint8_t parity = swd_read_bit(ctx); + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* skip if it's a clock */ + if(ctx->current_mask & bitmask) { + continue; + } + + uint8_t ack = 0; + for(int pos = 0; pos < 3; pos++) { + ack >>= 1; + ack |= (ack_bits[pos] & bitmask) ? 4 : 0; + } + + uint32_t dpidr = 0; + for(int pos = 0; pos < 32; pos++) { + dpidr >>= 1; + dpidr |= (rdata[pos] & bitmask) ? 0x80000000 : 0; + } + + if(ack == 1 && dpidr != 0 && dpidr != 0xFFFFFFFF) { + bool received_parity = (parity & bitmask); + if(__builtin_parity(dpidr) == received_parity) { + ctx->dp_regs.dpidr = dpidr; + ctx->dp_regs.dpidr_ok = true; + ctx->detected = true; + ctx->io_swd = bitmask; + ctx->io_swc &= ctx->current_mask; + LOG("swd_detect: data: %08lX, io_swd %02X, io_swc %02X", + dpidr, + ctx->io_swd, + ctx->io_swc); + + if(!has_multiple_bits(ctx->io_swc)) { + ctx->io_num_swd = get_bit_num(ctx->io_swd); + ctx->io_num_swc = get_bit_num(ctx->io_swc); + } + } + } + } + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + return 0; +} + +static void swd_scan(AppFSM* const ctx) { + /* To switch SWJ-DP from JTAG to SWD operation: + 1. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that the current interface is in its reset state. The JTAG interface only detects the 16-bit JTAG-to-SWD sequence starting from the Test-Logic-Reset state. + 2. Send the 16-bit JTAG-to-SWD select sequence 0x79e7 on SWDIOTMS. + 3. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that if SWJ-DP was already in SWD operation before sending the select sequence, the SWD interface enters line reset state. + */ + swd_configure_pins(ctx, true); + + /* reset JTAG interface */ + for(int bitcount = 0; bitcount < 50; bitcount += 8) { + swd_write_byte(ctx, 0xFF, 8); + } + + /* Send the 16-bit JTAG-to-SWD select sequence */ + swd_write_byte(ctx, 0x9E, 8); + swd_write_byte(ctx, 0xE7, 8); + + /* resynchronize SWD */ + swd_line_reset(ctx); + + swd_detect(ctx); +} + +static bool swd_ensure_powerup(AppFSM* const ctx) { + bool ret = true; + + if(!(ctx->dp_regs.ctrlstat & (CSYSPWRUPREQ | CDBGPWRUPREQ))) { + DBGS("no (CSYSPWRUPREQ | CDBGPWRUPREQ)"); + + /* fetch current CTRL/STAT */ + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", ctx->dp_regs.ctrlstat, ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + /* enable requests */ + ctx->dp_regs.ctrlstat |= (CSYSPWRUPREQ | CDBGPWRUPREQ); + + swd_write_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + + ret = false; + } + if(!(ctx->dp_regs.ctrlstat & CDBGPWRUPACK)) { + DBGS("no CDBGPWRUPACK"); + /* fetch current CTRL/STAT */ + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + ret = false; + } + + if(!ret) { + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", ctx->dp_regs.ctrlstat, ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + } + + return ret; +} + +static void swd_apscan_reset(AppFSM* const ctx) { + for(size_t reset_ap = 0; reset_ap < COUNT(ctx->apidr_info); reset_ap++) { + ctx->apidr_info[reset_ap].tested = false; + } +} + +static bool swd_apscan_test(AppFSM* const ctx, uint32_t ap) { + furi_assert(ctx); + furi_assert(ap < sizeof(ctx->apidr_info)); + bool ret = true; + + ctx->apidr_info[ap].tested = true; + + uint32_t data = 0; + if(swd_read_ap(ctx, ap, AP_IDR, &data) != 1) { + swd_abort(ctx); + return false; + } + if(data == 0) { + return false; + } + DBG("AP%lu detected", ap); + ctx->apidr_info[ap].ok = true; + ctx->apidr_info[ap].revision = (data >> 24) & 0x0F; + ctx->apidr_info[ap].designer = (data >> 17) & 0x3FF; + ctx->apidr_info[ap].class = (data >> 13) & 0x0F; + ctx->apidr_info[ap].variant = (data >> 4) & 0x0F; + ctx->apidr_info[ap].type = (data >> 0) & 0x0F; + + if(swd_read_ap(ctx, ap, AP_BASE, &ctx->apidr_info[ap].base) != 1) { + swd_abort(ctx); + ret = false; + } + return ret; +} + +/************************** script helpers **************************/ + +static void swd_script_log(ScriptContext* ctx, FuriLogLevel level, const char* format, ...) { + bool commandline = false; + ScriptContext* cur = ctx; + char buffer[256]; + va_list argp; + va_start(argp, format); + + do { + if(cur == ctx->app->commandline) { + commandline = true; + } + cur = cur->parent; + } while(cur); + + if(commandline) { + const char* prefix = ""; + + switch(level) { + case FuriLogLevelWarn: + prefix = "Warning: "; + break; + case FuriLogLevelError: + prefix = "ERROR: "; + break; + default: + break; + } + + strcpy(buffer, prefix); + size_t pos = strlen(buffer); + vsnprintf(&buffer[pos], sizeof(buffer) - pos - 2, format, argp); + strcat(buffer, "\n"); + usb_uart_tx_data(ctx->app->uart, (uint8_t*)buffer, strlen(buffer)); + } else { + LOG(buffer); + } + va_end(argp); +} + +/* read characters until newline was read */ +static bool swd_script_seek_newline(ScriptContext* ctx) { + while(true) { + uint8_t ch = 0; + + if(ctx->script_file) { + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + return false; + } + } else { + ch = ctx->line_data[ctx->line_pos]; + if(ch == 0) { + return false; + } + ctx->line_pos++; + } + if(ch == '\n') { + return true; + } + } +} + +/* read whitespaces until the next character is read. + returns false if EOF or newline was read */ +static bool swd_script_skip_whitespace(ScriptContext* ctx) { + while(true) { + uint8_t ch = 0; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + return false; + } + } else { + start_pos = ctx->line_pos; + ch = ctx->line_data[ctx->line_pos]; + + if(ch == 0) { + return false; + } + ctx->line_pos++; + } + if(ch == '\n') { + return false; + } + if(ch != ' ') { + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + } else { + ctx->line_pos = start_pos; + } + return true; + } + } +} + +static bool swd_script_get_string(ScriptContext* ctx, char* str, size_t max_length) { + bool quot = false; + size_t pos = 0; + + str[pos] = '\000'; + + while(true) { + char ch = 0; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + DBGS("end reached"); + return false; + } + } else { + start_pos = ctx->line_pos; + ch = ctx->line_data[ctx->line_pos]; + + if(ch == 0) { + DBGS("end reached"); + return false; + } + ctx->line_pos++; + } + + if(ch == '"') { + quot = !quot; + continue; + } + if(!quot) { + if(ch == ' ') { + break; + } + if(ch == '\r' || ch == '\n') { + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + } else { + ctx->line_pos = start_pos; + } + break; + } + } + if(pos + 2 > max_length) { + DBGS("too long"); + return false; + } + str[pos++] = ch; + str[pos] = '\000'; + } + DBG("got '%s'", str); + + return true; +} + +static bool swd_script_get_number(ScriptContext* ctx, uint32_t* number) { + char str[16]; + + if(!swd_script_get_string(ctx, str, sizeof(str))) { + DBGS("could not get string"); + return false; + } + DBG("got '%s'", str); + + size_t pos = 0; + *number = 0; + + /* hex number? */ + if(!strncmp(str, "0x", 2)) { + pos += 2; + while(str[pos]) { + uint8_t ch = str[pos++]; + uint8_t ch_num = ch - '0'; + uint8_t ch_hex = (ch & ~0x20) - 'A'; + + *number <<= 4; + + if(ch_num <= 10) { + *number += ch_num; + } else if(ch_hex <= 5) { + *number += 10 + ch_hex; + } else { + return false; + } + } + } else { + while(str[pos]) { + uint8_t ch = str[pos++]; + uint8_t ch_num = ch - '0'; + + *number *= 10; + + if(ch_num < 10) { + *number += ch_num; + } else { + return false; + } + } + } + + return true; +} + +static void swd_script_gui_refresh(ScriptContext* ctx) { + if(furi_message_queue_get_count(ctx->app->event_queue) > 0) { + swd_message_process(ctx->app); + } + if(!ctx->status_ignore) { + DBG("Status: %s", ctx->app->state_string); + view_port_update(ctx->app->view_port); + } +} + +/************************** script functions **************************/ + +static bool swd_scriptfunc_comment(ScriptContext* ctx) { + DBGS("comment"); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_label(ScriptContext* ctx) { + char label[256]; + DBGS("label"); + + swd_script_skip_whitespace(ctx); + if(!swd_script_get_string(ctx, label, sizeof(label))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse label"); + return false; + } + + if(!strcmp(label, ctx->goto_label)) { + ctx->goto_active = false; + DBG("matches '%s'", ctx->goto_label); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_goto(ScriptContext* ctx) { + DBGS("goto"); + + swd_script_skip_whitespace(ctx); + + if(!swd_script_get_string(ctx, ctx->goto_label, sizeof(ctx->goto_label))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse target label"); + return false; + } + + /* start from beginning and rerun starting from label */ + ctx->goto_active = true; + ctx->restart = true; + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_call(ScriptContext* ctx) { + DBGS("call"); + + swd_script_skip_whitespace(ctx); + + /* fetch previous file directory */ + char filename[MAX_FILE_LENGTH]; + strncpy(filename, ctx->filename, sizeof(filename)); + char* path = strrchr(filename, '/'); + path[1] = '\000'; + + /* append filename */ + if(!swd_script_get_string(ctx, &path[1], sizeof(filename) - strlen(path))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse filename"); + return false; + } + + swd_script_seek_newline(ctx); + + /* append extension */ + if(strlen(filename) + 5 >= sizeof(filename)) { + swd_script_log(ctx, FuriLogLevelError, "name too long"); + return false; + } + + strcat(filename, ".swd"); + + bool ret = swd_execute_script(ctx->app, filename); + + if(!ret) { + swd_script_log(ctx, FuriLogLevelError, "failed to exec '%s'", filename); + return false; + } + + return true; +} + +static bool swd_scriptfunc_status(ScriptContext* ctx) { + uint32_t status = 1; + DBGS("status"); + + swd_script_skip_whitespace(ctx); + swd_script_get_number(ctx, &status); + + ctx->status_ignore = (status == 0); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_errors(ScriptContext* ctx) { + char type[32]; + DBGS("errors"); + + swd_script_skip_whitespace(ctx); + + if(!swd_script_get_string(ctx, type, sizeof(type))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(!strcmp(type, "ignore")) { + ctx->errors_ignore = true; + } + if(!strcmp(type, "fail")) { + ctx->errors_ignore = false; + } + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_beep(ScriptContext* ctx) { + uint32_t sound = 0; + DBGS("beep"); + + swd_script_skip_whitespace(ctx); + swd_script_get_number(ctx, &sound); + + notification_message_block(ctx->app->notification, seq_sounds[sound]); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_message(ScriptContext* ctx) { + uint32_t wait_time = 0; + char message[256]; + char type[256]; + bool success = true; + bool show_dialog = false; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &wait_time)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse wait_time"); + return false; + } + + if(!swd_script_get_string(ctx, message, sizeof(message))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse message"); + return false; + } + + if(swd_script_get_string(ctx, type, sizeof(type))) { + if(!strcmp(type, "dialog")) { + show_dialog = true; + } + } + + if(wait_time <= 60 * 1000) { + strncpy(ctx->app->state_string, message, sizeof(ctx->app->state_string)); + swd_script_gui_refresh(ctx); + furi_delay_ms(wait_time); + if(show_dialog) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, ctx->app->state_string, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Abort", "Ok", NULL); + success = dialog_message_show(ctx->app->dialogs, message) == DialogMessageButtonCenter; + dialog_message_free(message); + } + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_swd_idle_bits(ScriptContext* ctx) { + uint32_t swd_idle_bits = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &swd_idle_bits)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(swd_idle_bits <= 32) { + ctx->app->swd_idle_bits = swd_idle_bits; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 1 and 32"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_swd_clock_delay(ScriptContext* ctx) { + uint32_t swd_clock_delay = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &swd_clock_delay)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(swd_clock_delay <= 1000000) { + ctx->app->swd_clock_delay = swd_clock_delay; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 1 and 1000000"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_maxtries(ScriptContext* ctx) { + uint32_t max_tries = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &max_tries)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(max_tries >= 1 && max_tries <= 1024) { + ctx->max_tries = max_tries; + } else { + DBGS("value must be between 1 and 1024"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_blocksize(ScriptContext* ctx) { + uint32_t block_size = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &block_size)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(block_size >= 4 && block_size <= 0x1000) { + ctx->block_size = block_size; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 4 and 4096"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_apselect(ScriptContext* ctx) { + uint32_t ap = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &ap)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP"); + return false; + } + + if(!swd_apscan_test(ctx->app, ap)) { + swd_script_log(ctx, FuriLogLevelError, "no selected AP"); + return false; + } + + ctx->selected_ap = ap; + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_apscan(ScriptContext* ctx) { + DBGS("Scanning APs"); + for(uint32_t ap = 0; ap < 255; ap++) { + snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Scan AP %lu", ap); + swd_script_gui_refresh(ctx); + if(swd_apscan_test(ctx->app, ap)) { + DBG(" AP%lu detected", ap); + } + } + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_abort(ScriptContext* ctx) { + DBGS("Aborting"); + swd_abort(ctx->app); + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_mem_dump(ScriptContext* ctx) { + char filename[MAX_FILE_LENGTH]; + uint32_t address = 0; + uint32_t length = 0; + uint32_t flags = 0; + bool success = true; + + /* get file */ + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_string(ctx, filename, sizeof(filename))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse filename"); + return false; + } + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get length */ + if(!swd_script_get_number(ctx, &length)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse length"); + return false; + } + + /* get flags */ + if(swd_script_get_number(ctx, &flags)) { + DBGS("found extra flags"); + } + + LOG("would dump %08lX, len %08lX into %s", address, length, filename); + + File* dump = storage_file_alloc(ctx->app->storage); + + if(!storage_file_open(dump, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + storage_file_free(dump); + snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Failed to create file"); + swd_script_gui_refresh(ctx); + notification_message_block(ctx->app->notification, &seq_error); + return false; + } + + if(ctx->block_size == 0) { + ctx->block_size = 0x100; + } + if(ctx->block_size > 0x1000) { + ctx->block_size = 0x1000; + } + + uint8_t* buffer = malloc(ctx->block_size); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + for(uint32_t pos = 0; pos < length; pos += ctx->block_size) { + if((pos & 0xFF) == 0) { + int pct = pos * 100 / length; + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Dump %08lX (%d%%)", + pos, + pct); + swd_script_gui_refresh(ctx); + } + + bool read_ok = false; + + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting read"); + break; + } + uint32_t ret = 0; + + if(ctx->block_size > 4) { + ret = swd_read_memory_block( + ctx->app, ctx->selected_ap, address + pos, buffer, ctx->block_size); + } else { + ret = + swd_read_memory(ctx->app, ctx->selected_ap, address + pos, (uint32_t*)buffer); + } + read_ok = (ret == 1); + + if(!read_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed at 0x%08lX", + address + pos); + swd_script_gui_refresh(ctx); + furi_delay_ms(100); + } else { + break; + } + } + if(ctx->abort) { + DBGS("aborting"); + break; + } + + if(!read_ok) { + /* flags == 1: "continue reading even if it fails" */ + /* flags == 2: "its okay if cannot dump fully" */ + if(flags & 1) { + /* set all content to a known value as indication */ + for(size_t fill_pos = 0; fill_pos < ctx->block_size; fill_pos += 4) { + *((uint32_t*)&buffer[fill_pos]) = 0xDEADFACE; + } + } else if(flags & 2) { + success = (pos > 0); + break; + } else { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + break; + } + } + storage_file_write(dump, buffer, ctx->block_size); + } + + furi_mutex_release(ctx->app->swd_mutex); + + storage_file_close(dump); + swd_script_seek_newline(ctx); + free(buffer); + + return success; +} + +static bool swd_scriptfunc_mem_write(ScriptContext* ctx) { + uint32_t address = 0; + uint32_t data = 0; + bool success = true; + + /* get file */ + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + DBG("write %08lX to %08lX", data, address); + + bool access_ok = false; + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + access_ok = swd_write_memory(ctx->app, ctx->selected_ap, address, data) == 1; + furi_mutex_release(ctx->app->swd_mutex); + access_ok |= ctx->errors_ignore; + swd_read_memory(ctx->app, ctx->selected_ap, address, &data); + DBG("read %08lX from %08lX", data, address); + + if(!access_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed write 0x%08lX", + address); + swd_script_gui_refresh(ctx); + } else { + break; + } + } + + if(!access_ok) { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_mem_ldmst(ScriptContext* ctx) { + uint32_t address = 0; + uint32_t data = 0; + uint32_t mask = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get mask */ + if(!swd_script_get_number(ctx, &mask)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse mask"); + return false; + } + + LOG("write %08lX to %08lX, mask %08lX", data, address, mask); + + bool access_ok = false; + uint32_t modified = 0; + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + access_ok = swd_read_memory(ctx->app, ctx->selected_ap, address, &modified) == 1; + modified = (modified & mask) | data; + access_ok &= swd_write_memory(ctx->app, ctx->selected_ap, address, modified) == 1; + + furi_mutex_release(ctx->app->swd_mutex); + access_ok |= ctx->errors_ignore; + + if(!access_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed access 0x%08lX", + address); + swd_script_gui_refresh(ctx); + } else { + break; + } + } + + if(!access_ok) { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_dp_write(ScriptContext* ctx) { + uint32_t dp_bank = 0; + uint32_t dp_off = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get dp_off */ + if(!swd_script_get_number(ctx, &dp_off)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse DP offset"); + return false; + } + + /* get dp_bank */ + if(!swd_script_get_number(ctx, &dp_bank)) { + dp_bank = 0xFF; + } + + swd_script_log( + ctx, FuriLogLevelDefault, "write %08lX to reg %08lX / bank %08lX", data, dp_off, dp_bank); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_write_dpbank(ctx->app, dp_off, dp_bank, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_write_dpbank failed"); + success = false; + } + + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_dp_read(ScriptContext* ctx) { + uint32_t dp_bank = 0; + uint32_t dp_off = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get dp_off */ + if(!swd_script_get_number(ctx, &dp_off)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse DP offset"); + return false; + } + + /* get dp_bank */ + if(!swd_script_get_number(ctx, &dp_bank)) { + dp_bank = 0xFF; + } + + swd_script_log(ctx, FuriLogLevelDefault, "read reg %02lX / bank %02lX", dp_off, dp_bank); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_read_dpbank(ctx->app, dp_off, dp_bank, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_read_dpbank failed"); + success = false; + } else { + swd_script_log(ctx, FuriLogLevelDefault, "result: 0x%08lX", data); + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_ap_write(ScriptContext* ctx) { + uint32_t ap_reg = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get ap_reg */ + if(!swd_script_get_number(ctx, &ap_reg)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP register"); + return false; + } + + swd_script_log( + ctx, FuriLogLevelDefault, "AP%d %08lX -> %02lX", ctx->selected_ap, data, ap_reg); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_write_ap(ctx->app, ctx->selected_ap, ap_reg, data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_write_ap failed"); + success = false; + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_ap_read(ScriptContext* ctx) { + uint32_t ap_reg = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get ap_reg */ + if(!swd_script_get_number(ctx, &ap_reg)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP register"); + return false; + } + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_read_ap(ctx->app, ctx->selected_ap, ap_reg, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_read_ap failed"); + success = false; + } else { + swd_script_log( + ctx, FuriLogLevelDefault, "AP%d %02lX: %08lX", ctx->selected_ap, ap_reg, data); + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static const ScriptFunctionInfo script_funcs[] = { + {"#", &swd_scriptfunc_comment}, + {".label", &swd_scriptfunc_label}, + {"goto", &swd_scriptfunc_goto}, + {"call", &swd_scriptfunc_call}, + {"status", &swd_scriptfunc_status}, + {"errors", &swd_scriptfunc_errors}, + {"message", &swd_scriptfunc_message}, + {"beep", &swd_scriptfunc_beep}, + {"max_tries", &swd_scriptfunc_maxtries}, + {"swd_clock_delay", &swd_scriptfunc_swd_clock_delay}, + {"swd_idle_bits", &swd_scriptfunc_swd_idle_bits}, + {"block_size", &swd_scriptfunc_blocksize}, + {"abort", &swd_scriptfunc_abort}, + {"mem_dump", &swd_scriptfunc_mem_dump}, + {"mem_ldmst", &swd_scriptfunc_mem_ldmst}, + {"mem_write", &swd_scriptfunc_mem_write}, + {"dp_write", &swd_scriptfunc_dp_write}, + {"dp_read", &swd_scriptfunc_dp_read}, + {"ap_scan", &swd_scriptfunc_apscan}, + {"ap_select", &swd_scriptfunc_apselect}, + {"ap_read", &swd_scriptfunc_ap_read}, + {"ap_write", &swd_scriptfunc_ap_write}}; + +/************************** script main code **************************/ + +static bool swd_execute_script_line(ScriptContext* const ctx) { + char buffer[64]; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + uint16_t ret = storage_file_read(ctx->script_file, buffer, 2); + storage_file_seek(ctx->script_file, start_pos, true); + + if(ret < 2) { + return true; + } + } else { + start_pos = ctx->line_pos; + strncpy(buffer, ctx->line_data, 2); + + if(buffer[0] == 0 || buffer[1] == 0) { + return true; + } + } + + if(buffer[0] == '\n' || (buffer[0] == '\r' && buffer[1] == '\n')) { + swd_script_seek_newline(ctx); + return true; + } + + for(size_t entry = 0; entry < COUNT(script_funcs); entry++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + size_t expected = strlen(script_funcs[entry].prefix); + + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + + if(storage_file_read(ctx->script_file, buffer, expected) != expected) { + continue; + } + } else { + ctx->line_pos = start_pos; + + if(strlen(ctx->line_data) < expected) { + continue; + } + strncpy(buffer, ctx->line_data, expected); + ctx->line_pos += expected; + } + + buffer[expected] = '\000'; + if(strncmp(buffer, script_funcs[entry].prefix, expected)) { + continue; + } + bool success = true; + + if(ctx->goto_active) { + DBG("ignore: '%s'", script_funcs[entry].prefix); + + /* only execute label handlers */ + if(buffer[0] == '.') { + success = script_funcs[entry].func(ctx); + } else { + swd_script_seek_newline(ctx); + } + } else { + DBG("command: '%s'", script_funcs[entry].prefix); + + if(!ctx->status_ignore) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "CMD: %s", + script_funcs[entry].prefix); + } + swd_script_gui_refresh(ctx); + + /* function, execute */ + success = script_funcs[entry].func(ctx); + + if(!success && !ctx->errors_ignore) { + swd_script_log( + ctx, FuriLogLevelError, "Command failed: %s", script_funcs[entry].prefix); + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Command failed: %s", + script_funcs[entry].prefix); + return false; + } + } + + return true; + } + swd_script_log(ctx, FuriLogLevelError, "unknown command '%s'", buffer); + + return false; +} + +static bool swd_execute_script(AppFSM* const ctx, const char* filename) { + bool success = true; + + /* fetch current script and set as parent */ + ScriptContext* parent = ctx->script; + + ctx->script = malloc(sizeof(ScriptContext)); + ctx->script->app = ctx; + ctx->script->max_tries = 1; + ctx->script->parent = parent; + strcpy(ctx->script->filename, filename); + + if(!storage_file_exists(ctx->storage, filename)) { + DBG("Does not exist '%s'", filename); + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + return false; + } + + /* first allocate a file object */ + ctx->script->script_file = storage_file_alloc(ctx->storage); + + /* then get our script opened */ + if(!storage_file_open(ctx->script->script_file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(ctx->script->script_file)); + DBG("Failed to open '%s'", filename); + storage_file_free(ctx->script->script_file); + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + return false; + } + + do { + success = true; + ctx->script->restart = false; + + storage_file_seek(ctx->script->script_file, 0, true); + + uint32_t line = 1; + while(line < SCRIPT_MAX_LINES) { + if(ctx->script->abort) { + DBGS("Abort requested"); + break; + } + if(storage_file_eof(ctx->script->script_file)) { + break; + } + DBG("line %lu", line); + if(!swd_execute_script_line(ctx->script)) { + success = false; + break; + } + if(ctx->script->restart) { + break; + } + line++; + } + + if(ctx->script->restart) { + DBGS("Restarting"); + } else { + DBGS("Finished"); + } + + if(line >= SCRIPT_MAX_LINES) { + success = true; + char text_buf[128]; + + snprintf(text_buf, sizeof(text_buf), "aborting after %d lines", SCRIPT_MAX_LINES); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_free(message); + + ctx->script->restart = false; + } + + if(!success) { + char text_buf[128]; + + snprintf(text_buf, sizeof(text_buf), "Line %lu failed:\n%s", line, ctx->state_string); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Back", "Retry", NULL); + if(dialog_message_show(ctx->dialogs, message) == DialogMessageButtonCenter) { + ctx->script->restart = true; + } + dialog_message_free(message); + } + } while(ctx->script->restart); + + storage_file_close(ctx->script->script_file); + storage_file_free(ctx->script->script_file); + + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + + return success; +} + +/************************** UI functions **************************/ + +#define CANVAS_WIDTH 128 +#define CANVAS_HEIGHT 64 + +#define COERCE(d, min, max) \ + do { \ + if(d < (min)) { \ + d = (min); \ + } \ + if(d > (max)) { \ + d = (max); \ + } \ + } while(0) + +#define COERCE_COORDS(x1, y1, x2, y2) \ + do { \ + COERCE(x1, 0, CANVAS_WIDTH); \ + COERCE(x2, 0, CANVAS_WIDTH); \ + COERCE(y1, 0, CANVAS_HEIGHT); \ + COERCE(y1, 0, CANVAS_HEIGHT); \ + } while(0) + +#include "model/model_chip.h" + +static int rotatedVertexCoords[NUM_VERTICES][3]; + +static void draw_model(Canvas* const canvas) { + static float xAngle = 0; + static float yAngle = 0; + static float zAngle = 0; + static float zoom = 0; + static float speed = 0.6f; + + float cosXAngle = cosf(xAngle); + float sinXAngle = sinf(xAngle); + float cosYAngle = cosf(yAngle); + float sinYAngle = sinf(yAngle); + float cosZAngle = cosf(zAngle); + float sinZAngle = sinf(zAngle); + float sinZoom = 1.2f + sinf(zoom) * 0.25f; + + int centerX = CANVAS_WIDTH / 2; + int centerY = CANVAS_HEIGHT / 2 + 5; + + for(int i = 0; i < NUM_VERTICES; i++) { + int x = vertexCoords[i][0] * sinZoom * 16; + int y = vertexCoords[i][1] * sinZoom * 16; + int z = vertexCoords[i][2] * sinZoom * 16; + + int y1 = y * cosXAngle - z * sinXAngle; + int z1 = y * sinXAngle + z * cosXAngle; + + int x2 = x * cosYAngle + z1 * sinYAngle; + int z2 = -x * sinYAngle + z1 * cosYAngle; + + int x3 = x2 * cosZAngle - y1 * sinZAngle; + int y3 = x2 * sinZAngle + y1 * cosZAngle; + + rotatedVertexCoords[i][0] = x3 + centerX; + rotatedVertexCoords[i][1] = y3 + centerY; + rotatedVertexCoords[i][2] = z2; + } + + for(size_t i = 0; i < COUNT(edgeIndices); i++) { + int v1Index = edgeIndices[i][0]; + int v2Index = edgeIndices[i][1]; + int x1 = rotatedVertexCoords[v1Index][0]; + int y1 = rotatedVertexCoords[v1Index][1]; + int x2 = rotatedVertexCoords[v2Index][0]; + int y2 = rotatedVertexCoords[v2Index][1]; + + COERCE_COORDS(x1, y1, x2, y2); + canvas_draw_line(canvas, x1, y1, x2, y2); + } + + xAngle += speed * 0.02 / sinZoom; + yAngle += speed * 0.023 / sinZoom; + zAngle += speed * 0.029 * sinZoom; + zoom += speed * 0.005; +} + +static void render_callback(Canvas* const canvas, void* ctx_in) { + furi_assert(canvas); + furi_assert(ctx_in); + + AppFSM* ctx = ctx_in; + furi_mutex_acquire(ctx->gui_mutex, FuriWaitForever); + + char buffer[64]; + int y = 10; + + canvas_draw_frame(canvas, 0, 0, 128, 64); + canvas_set_font(canvas, FontPrimary); + + if(!ctx->detected_device) { + ctx->mode_page = ModePageScan; + } else if(ctx->mode_page == ModePageScan) { + ctx->mode_page = ModePageFound; + } + + /* if seen less than a quarter second ago */ + switch(ctx->mode_page) { + case ModePageScan: { + draw_model(canvas); + + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Searching"); + y += 14; + + canvas_set_font(canvas, FontSecondary); + + bool info_page = (ctx->loop_count % 500) >= 250; + if(info_page) { + canvas_draw_str(canvas, 2, y, "Connect GND with target GND"); + y += 10; + canvas_draw_str(canvas, 2, y, "and any two GPIOs with pads"); + y += 10; + canvas_draw_str(canvas, 2, y, "you want to check for SWD"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 111, 62, "2/2"); + } else { + const char* filename = ""; + if(strlen(ctx->script_detected) > 0) { + const char* slash = strrchr(ctx->script_detected, '/'); + if(slash) { + filename = &slash[1]; + } else { + filename = ctx->script_detected; + } + } + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Autoexec Script"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, filename); + y += 16; + + canvas_set_font(canvas, FontSecondary); + canvas_draw_icon(canvas, 14, y - 5, &I_ButtonUp_7x4); + canvas_draw_icon(canvas, 78, y - 5, &I_ButtonDown_7x4); + canvas_draw_str(canvas, 23, y, "Clear"); + canvas_draw_str(canvas, 87, y, "Choose"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 111, 62, "1/2"); + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Script"); + break; + } + case ModePageFound: { + if((ctx->detected_timeout + TIMER_HZ / 4) >= TIMER_HZ * TIMEOUT) { + snprintf(buffer, sizeof(buffer), "FOUND!"); + } else { + /* if it was seen more than a quarter second ago, show countdown */ + snprintf( + buffer, sizeof(buffer), "FOUND! (%lus)", (ctx->detected_timeout / TIMER_HZ) + 1); + } + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, buffer); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + snprintf( + buffer, + sizeof(buffer), + "SWC/SWD: %s/%s", + gpio_name(ctx->io_swc), + gpio_name(ctx->io_swd)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "DPIDR 0x%08lX", ctx->dp_regs.dpidr); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "Part %02X Rev %X DAPv%d", + ctx->dpidr_info.partno, + ctx->dpidr_info.revision, + ctx->dpidr_info.version); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + canvas_set_font(canvas, FontSecondary); + snprintf(buffer, sizeof(buffer), "%s", jep106_manufacturer(ctx->dpidr_info.designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Script"); + elements_button_right(canvas, "DP Regs"); + + break; + } + case ModePageDPRegs: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP Registers"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + if(ctx->dp_regs.dpidr_ok) { + snprintf(buffer, sizeof(buffer), "DPIDR %08lX", ctx->dp_regs.dpidr); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.ctrlstat_ok) { + snprintf(buffer, sizeof(buffer), "CTRL %08lX", ctx->dp_regs.ctrlstat); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.targetid_ok) { + snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.eventstat_ok) { + snprintf(buffer, sizeof(buffer), "EVTST %08lX", ctx->dp_regs.eventstat); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Scan"); + elements_button_right(canvas, "DPID"); + + break; + } + + case ModePageDPID: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP ID Register"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + if(ctx->dpidr_info.version != 2) { + snprintf(buffer, sizeof(buffer), "TARGETID not supported"); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + } else { + if(ctx->dp_regs.targetid_ok) { + snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf(buffer, sizeof(buffer), "Part No. %04X", ctx->targetid_info.partno); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf( + buffer, sizeof(buffer), "%s", jep106_manufacturer(ctx->targetid_info.designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + } + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "DP Regs"); + elements_button_right(canvas, "APs"); + break; + } + + case ModePageAPID: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "AP Menu"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + char state = ' '; + if(ctx->ap_pos >= ctx->ap_scanned && ctx->ap_pos <= ctx->ap_scanned + 10) { + state = '*'; + } + + if(!ctx->apidr_info[ctx->ap_pos].ok) { + snprintf(buffer, sizeof(buffer), "[%d]%c", ctx->ap_pos, state); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + if(ctx->ap_pos == 0) { + for(size_t pos = 0; pos < COUNT(ctx->apidr_info); pos++) { + if(ctx->apidr_info[pos].ok) { + ctx->ap_pos = pos; + } + } + } + } else { + const char* class = ""; + + switch(ctx->apidr_info[ctx->ap_pos].class) { + case 0: + class = "und"; + break; + case 1: + class = "COM"; + break; + case 8: + class = "MEM"; + break; + default: + class = "unk"; + break; + } + + const char* types[] = { + "COM-AP", + "AHB3", + "APB2 or APB3", + "Type unknown", + "AXI3 or AXI4", + "AHB5", + "APB4 and APB5", + "AXI5", + "AHB5 enh.", + }; + const char* type = "Type unk"; + + if(ctx->apidr_info[ctx->ap_pos].type < COUNT(types)) { + type = types[ctx->apidr_info[ctx->ap_pos].type]; + } + + snprintf(buffer, sizeof(buffer), "[%d]%c%s, %s", ctx->ap_pos, state, class, type); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf(buffer, sizeof(buffer), "Base 0x%08lX", ctx->apidr_info[ctx->ap_pos].base); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "Rev %d Var %d", + ctx->apidr_info[ctx->ap_pos].revision, + ctx->apidr_info[ctx->ap_pos].variant); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "%s", + jep106_manufacturer(ctx->apidr_info[ctx->ap_pos].designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + elements_button_center(canvas, "Show"); + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "DPID"); + elements_button_right(canvas, "CoreS."); + elements_scrollbar_pos(canvas, 4, 10, 40, ctx->ap_pos / 32, COUNT(ctx->apidr_info) / 32); + break; + } + + /* hex dump view */ + case ModePageHexDump: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Hex dump"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, "Addr:"); + + snprintf(buffer, sizeof(buffer), "%08lX", ctx->hex_addr); + canvas_draw_str_aligned(canvas, 38, y, AlignLeft, AlignBottom, buffer); + uint32_t font_width = canvas_glyph_width(canvas, '0'); + uint32_t x = 37 + (7 - ctx->hex_select) * font_width; + + /* draw selection */ + canvas_draw_line(canvas, x, y + 1, x + font_width, y + 1); + y += 10; + + uint32_t byte_num = 0; + for(int line = 0; line < 4; line++) { + uint32_t x_pos = 5; + + for(int byte_pos = 0; byte_pos < 8; byte_pos++) { + if(ctx->hex_buffer_valid[byte_num / 4]) { + snprintf(buffer, sizeof(buffer), "%02X", ctx->hex_buffer[byte_num]); + } else { + snprintf(buffer, sizeof(buffer), "--"); + } + byte_num++; + canvas_draw_str_aligned(canvas, x_pos, y, AlignLeft, AlignBottom, buffer); + x_pos += font_width * 2 + font_width / 2; + } + y += 10; + } + break; + } + + case ModePageCoresight: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Coresight"); + y += 10; + canvas_set_font(canvas, FontSecondary); + + uint32_t base = ctx->coresight_bases[ctx->coresight_level]; + uint32_t base_next = adi_romtable_get(ctx, base, ctx->coresight_pos[ctx->coresight_level]); + + snprintf(buffer, sizeof(buffer), "Base: %08lX", base); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "Type: %s", adi_romtable_type(ctx, base)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "Full: %s", adi_romtable_full(ctx, base)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + if(adi_is_romtable(ctx, base)) { + snprintf( + buffer, + sizeof(buffer), + "[%lu/%lu] -> %08lX", + ctx->coresight_pos[ctx->coresight_level] + 1, + ctx->coresight_count[ctx->coresight_level], + base_next); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + canvas_set_font(canvas, FontSecondary); + elements_button_center(canvas, "Enter"); + } + y += 10; + + canvas_set_font(canvas, FontSecondary); + + if(ctx->coresight_level) { + elements_button_left(canvas, "Prev"); + } else { + elements_button_left(canvas, "APs"); + } + elements_scrollbar_pos( + canvas, + 4, + 10, + 40, + ctx->coresight_pos[ctx->coresight_level], + ctx->coresight_count[ctx->coresight_level]); + + break; + } + + /* hex dump view */ + case ModePageScript: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Script"); + y += 10; + y += 10; + canvas_draw_str_aligned(canvas, 10, y, AlignLeft, AlignBottom, "Status:"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, ctx->state_string); + y += 10; + break; + } + } + + furi_mutex_release(ctx->gui_mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx_in) { + furi_assert(input_event); + furi_assert(ctx_in); + AppFSM* ctx = ctx_in; + + int entries = furi_message_queue_get_count(ctx->event_queue); + + /* better skip than sorry */ + if(entries < QUEUE_SIZE) { + AppEvent event = {.type = EventKeyPress, .input = *input_event}; + furi_message_queue_put(ctx->event_queue, &event, 0); + } +} + +static void app_init(AppFSM* const app) { + furi_assert(app); + + app->loop_count = 0; + app->current_mask_id = 0; + app->current_mask = gpio_direction_mask[app->current_mask_id]; + app->io_swd = 0xFF; + app->io_swc = 0xFF; + app->hex_addr = 0x40002800; + app->hex_addr = 0xE000EDF0; + app->swd_clock_delay = CLOCK_DELAY; + app->swd_idle_bits = IDLE_BITS; + + strcpy(app->state_string, "none"); + strcpy(app->script_detected, ""); +} + +static void app_deinit(AppFSM* const app) { + furi_assert(app); + + strcpy(app->state_string, "exiting"); +} + +static void swd_main_loop(AppFSM* ctx) { + furi_assert(ctx); + + ctx->loop_count++; + + switch(ctx->mode_page) { + case ModePageScan: + case ModePageFound: { + /* reset after timeout */ + if(ctx->detected_timeout > 0) { + ctx->detected_timeout--; + } else { + DBGS("Reset detected flag"); + ctx->detected_device = false; + ctx->io_swd = 0xFF; + ctx->io_swc = 0xFF; + ctx->io_num_swd = 0xFF; + ctx->io_num_swc = 0xFF; + ctx->ap_scanned = 0; + memset(&ctx->dp_regs, 0x00, sizeof(ctx->dp_regs)); + memset(&ctx->targetid_info, 0x00, sizeof(ctx->targetid_info)); + memset(&ctx->apidr_info, 0x00, sizeof(ctx->apidr_info)); + ctx->script_detected_executed = false; + } + + ctx->detected = false; + ctx->current_mask = gpio_direction_mask[ctx->current_mask_id]; + + /* when SWD was already detected, set it to data pin regardless of the mask */ + if(ctx->detected_device) { + ctx->current_mask &= ~ctx->io_swd; + } + + /* do the scan */ + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + swd_scan(ctx); + furi_mutex_release(ctx->swd_mutex); + + /* now when detected a device, set the timeout */ + if(ctx->detected) { + DBGS("Set detected flag"); + ctx->detected_device = true; + ctx->detected_timeout = TIMER_HZ * TIMEOUT; + + /* update DPIDR fields */ + ctx->dpidr_info.revision = (ctx->dp_regs.dpidr >> 28) & 0x0F; + ctx->dpidr_info.partno = (ctx->dp_regs.dpidr >> 20) & 0xFF; + ctx->dpidr_info.version = (ctx->dp_regs.dpidr >> 12) & 0x0F; + ctx->dpidr_info.designer = (ctx->dp_regs.dpidr >> 1) & 0x3FF; + + if(!has_multiple_bits(ctx->io_swc)) { + DBGS(" - Detected pins"); + DBGS(" - Resetting error"); + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + /* reset error */ + /* first make sure we have the correct bank by invalidating the current select cache */ + ctx->dp_regs.select_ok = false; + uint8_t ack = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + + if(ack != 1 || (ctx->dp_regs.ctrlstat & STAT_ERROR_FLAGS)) { + DBGS(" - send ABORT"); + swd_abort(ctx); + } + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank( + ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", + ctx->dp_regs.ctrlstat, + ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + + if(ctx->dpidr_info.version >= 1) { + DBGS(" - DAPv1, read DLCR"); + ctx->dp_regs.dlcr_ok = + swd_read_dpbank(ctx, REG_DLCR, REG_DLCR_BANK, &ctx->dp_regs.dlcr) == 1; + DBG(" %08lX %s", ctx->dp_regs.dlcr, ctx->dp_regs.dlcr_ok ? "OK" : "FAIL"); + } + + if(ctx->dpidr_info.version >= 2) { + DBGS(" - DAPv2, read TARGETID"); + ctx->dp_regs.targetid_ok = + swd_read_dpbank( + ctx, REG_TARGETID, REG_TARGETID_BANK, &ctx->dp_regs.targetid) == 1; + DBG(" %08lX %s", + ctx->dp_regs.targetid, + ctx->dp_regs.targetid_ok ? "OK" : "FAIL"); + DBGS(" - DAPv2, read EVENTSTAT"); + ctx->dp_regs.eventstat_ok = + swd_read_dpbank( + ctx, REG_EVENTSTAT, REG_EVENTSTAT_BANK, &ctx->dp_regs.eventstat) == 1; + DBG(" %08lX %s", + ctx->dp_regs.eventstat, + ctx->dp_regs.eventstat_ok ? "OK" : "FAIL"); + DBGS(" - DAPv2, read DLPIDR"); + ctx->dp_regs.dlpidr_ok = + swd_read_dpbank(ctx, REG_DLPIDR, REG_DLPIDR_BANK, &ctx->dp_regs.dlpidr) == + 1; + DBG(" %08lX %s", + ctx->dp_regs.dlpidr, + ctx->dp_regs.dlpidr_ok ? "OK" : "FAIL"); + } + + if(ctx->dp_regs.targetid_ok) { + ctx->targetid_info.revision = (ctx->dp_regs.targetid >> 28) & 0x0F; + ctx->targetid_info.partno = (ctx->dp_regs.targetid >> 12) & 0xFFFF; + ctx->targetid_info.designer = (ctx->dp_regs.targetid >> 1) & 0x3FF; + } + + if(!ctx->script_detected_executed && strlen(ctx->script_detected) > 0) { + DBG(" - Run script '%s'", ctx->script_detected); + + ctx->script_detected_executed = true; + + ctx->mode_page = ModePageScript; + swd_execute_script(ctx, ctx->script_detected); + ctx->mode_page = ModePageFound; + } + furi_mutex_release(ctx->swd_mutex); + } + } else { + if(!has_multiple_bits(ctx->io_swc)) { + DBGS(" - Lost device"); + } + } + + ctx->current_mask_id = (ctx->current_mask_id + 1) % COUNT(gpio_direction_mask); + break; + } + + case ModePageDPRegs: + case ModePageDPID: + case ModePageAPID: { + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + /* set debug enable request */ + if(!swd_ensure_powerup(ctx)) { + furi_mutex_release(ctx->swd_mutex); + break; + } + + /* only scan a few APs at once to stay responsive */ + for(int pos = 0; pos < 8; pos++) { + if(ctx->ap_scanned == 0) { + swd_apscan_reset(ctx); + } + + uint8_t ap = ctx->ap_scanned++; + + if(ctx->apidr_info[ap].tested) { + continue; + } + if(swd_apscan_test(ctx, ap)) { + break; + } + } + furi_mutex_release(ctx->swd_mutex); + break; + } + + case ModePageHexDump: { + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + + for(size_t byte_pos = 0; byte_pos < sizeof(ctx->hex_buffer); byte_pos += 4) { + uint32_t* data = (uint32_t*)&ctx->hex_buffer[byte_pos]; + bool ret = swd_read_memory(ctx, ctx->ap_pos, ctx->hex_addr + byte_pos, data) == 1; + + ctx->hex_buffer_valid[byte_pos / 4] = ret; + + if(!ret) { + swd_abort_simple(ctx); + } + } + furi_mutex_release(ctx->swd_mutex); + break; + } + + case ModePageCoresight: + furi_delay_ms(50); + break; + } +} + +static bool swd_message_process(AppFSM* ctx) { + bool processing = true; + AppEvent event; + + /* wait to make sure the OS can do its stuff */ + FuriStatus event_status = furi_message_queue_get(ctx->event_queue, &event, 1000 / TIMER_HZ); + + if(event_status != FuriStatusOk) { + return processing; + } + + if(event.type == EventKeyPress) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + case InputKeyUp: + switch(ctx->mode_page) { + default: + break; + + case ModePageScan: + case ModePageFound: { + strcpy(ctx->script_detected, ""); + break; + } + + case ModePageAPID: + if(ctx->ap_pos > 0) { + ctx->ap_pos--; + } + break; + + case ModePageHexDump: { + ctx->hex_addr += ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select)); + break; + } + + case ModePageCoresight: { + if(ctx->coresight_pos[ctx->coresight_level] > 0) { + ctx->coresight_pos[ctx->coresight_level]--; + } + break; + } + } + break; + + case InputKeyDown: { + switch(ctx->mode_page) { + default: + break; + + case ModePageScan: { + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd")); + FuriString* preselected = furi_string_alloc_printf( + (strlen(ctx->script_detected) > 0) ? ctx->script_detected : + ANY_PATH("swd")); + DialogsFileBrowserOptions options; + + dialog_file_browser_set_basic_options(&options, "swd", &I_swd); + + if(dialog_file_browser_show(ctx->dialogs, result_path, preselected, &options)) { + const char* path = furi_string_get_cstr(result_path); + strcpy(ctx->script_detected, path); + } + + furi_string_free(result_path); + furi_string_free(preselected); + break; + } + + case ModePageAPID: + if(ctx->ap_pos + 1U < COUNT(ctx->apidr_info)) { + ctx->ap_pos++; + } + break; + + case ModePageHexDump: { + ctx->hex_addr -= ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select)); + break; + } + + case ModePageCoresight: { + if(ctx->coresight_pos[ctx->coresight_level] + 1 < + ctx->coresight_count[ctx->coresight_level]) { + ctx->coresight_pos[ctx->coresight_level]++; + } + break; + } + } + break; + } + + case InputKeyRight: + if(ctx->mode_page == ModePageHexDump) { + if(ctx->hex_select > 0) { + ctx->hex_select--; + } + } else if(ctx->mode_page == ModePageAPID && ctx->apidr_info[ctx->ap_pos].ok) { + ctx->mode_page = ModePageCoresight; + uint32_t base = ctx->apidr_info[ctx->ap_pos].base & 0xFFFFF000; + ctx->coresight_level = 0; + ctx->coresight_bases[ctx->coresight_level] = base; + ctx->coresight_pos[ctx->coresight_level] = 0; + ctx->coresight_count[ctx->coresight_level] = + adi_romtable_entry_count(ctx, base); + } else if(ctx->detected) { + if(ctx->mode_page + 1 < ModePageCount) { + ctx->mode_page++; + } + } + break; + + case InputKeyLeft: + if(ctx->mode_page == ModePageHexDump) { + if(ctx->hex_select < 7) { + ctx->hex_select++; + } + } else if(ctx->mode_page == ModePageCoresight) { + if(ctx->coresight_level > 0) { + ctx->coresight_level--; + } else { + ctx->mode_page = ModePageAPID; + } + } else if((ctx->mode_page == ModePageScan) || (ctx->mode_page == ModePageFound)) { + uint32_t mode_page = ctx->mode_page; + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd")); + FuriString* preselected = furi_string_alloc_printf( + (strlen(ctx->script_detected) > 0) ? ctx->script_detected : + ANY_PATH("swd")); + DialogsFileBrowserOptions options; + + dialog_file_browser_set_basic_options(&options, "swd", &I_swd); + + if(dialog_file_browser_show(ctx->dialogs, result_path, preselected, &options)) { + const char* path = furi_string_get_cstr(result_path); + ctx->mode_page = ModePageScript; + swd_execute_script(ctx, path); + ctx->mode_page = mode_page; + } + + furi_string_free(result_path); + furi_string_free(preselected); + break; + } else { + if(ctx->mode_page > 0) { + ctx->mode_page--; + } + } + break; + + case InputKeyOk: + if(ctx->mode_page == ModePageAPID && ctx->apidr_info[ctx->ap_pos].ok) { + ctx->mode_page = ModePageHexDump; + } else if(ctx->mode_page == ModePageCoresight) { + uint32_t base = ctx->coresight_bases[ctx->coresight_level]; + + if(!adi_is_romtable(ctx, base)) { + break; + } + + uint32_t cur_pos = ctx->coresight_pos[ctx->coresight_level]; + uint32_t base_next = adi_romtable_get(ctx, base, cur_pos); + uint32_t new_count = adi_romtable_entry_count(ctx, base_next); + + ctx->coresight_level++; + ctx->coresight_pos[ctx->coresight_level] = 0; + ctx->coresight_count[ctx->coresight_level] = new_count; + ctx->coresight_bases[ctx->coresight_level] = base_next; + } + break; + + case InputKeyBack: + if(ctx->mode_page == ModePageHexDump) { + ctx->mode_page = ModePageAPID; + } else if(ctx->mode_page == ModePageScript) { + ctx->script->abort = true; + } else if(ctx->mode_page > ModePageFound) { + ctx->mode_page = ModePageScan; + } else if(ctx->mode_page == ModePageScan) { + processing = false; + } else if(ctx->mode_page == ModePageFound) { + processing = false; + } + break; + + default: + break; + } + } + } + return processing; +} + +size_t data_received(void* ctx, uint8_t* data, size_t length) { + AppFSM* app = (AppFSM*)ctx; + + strncpy(app->commandline->line_data, (const char*)data, length); + app->commandline->line_pos = 0; + + for(size_t pos = 0; pos < length; pos++) { + uint8_t ch = app->commandline->line_data[pos]; + + if((ch == '\r') || (ch == '\n')) { + app->commandline->line_data[pos++] = '\n'; + app->commandline->line_data[pos] = 0; + LOG("direct command '%s'", app->commandline->line_data); + swd_execute_script_line(app->commandline); + return pos; + } + } + + return 0; +} + +int32_t swd_probe_app_main(void* p) { + UNUSED(p); + + AppFSM* app = malloc(sizeof(AppFSM)); + + DBGS("App init"); + app_init(app); + + DBGS("furi_record_open"); + app->notification = furi_record_open(RECORD_NOTIFICATION); + app->gui = furi_record_open(RECORD_GUI); + app->dialogs = furi_record_open(RECORD_DIALOGS); + app->storage = furi_record_open(RECORD_STORAGE); + + DBGS("furi_mutex_alloc"); + app->swd_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + app->gui_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + app->event_queue = furi_message_queue_alloc(QUEUE_SIZE, sizeof(AppEvent)); + + DBGS("usb_uart_enable"); + UsbUartConfig uart_config; + uart_config.vcp_ch = 1; + uart_config.rx_data = &data_received; + uart_config.rx_data_ctx = app; + app->uart = usb_uart_enable(&uart_config); + + app->commandline = malloc(sizeof(ScriptContext)); + app->commandline->max_tries = 1; + app->commandline->app = app; + + DBGS("view_port_alloc"); + app->view_port = view_port_alloc(); + view_port_draw_callback_set(app->view_port, render_callback, app); + view_port_input_callback_set(app->view_port, input_callback, app); + gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + + DBGS("notification_message_block"); + notification_message(app->notification, &sequence_display_backlight_enforce_on); + + DBGS("swd_execute_script"); + swd_execute_script(app, ANY_PATH("swd_scripts/startup.swd")); + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + + DBGS("processing"); + for(bool processing = true; processing;) { + swd_main_loop(app); + view_port_update(app->view_port); + + processing = swd_message_process(app); + + bool beep = false; + + if(app->detected_device && !app->detected_notified) { + app->detected_notified = true; + beep = true; + } + if(!app->detected_device && app->detected_notified) { + app->detected_notified = false; + } + if(beep) { + notification_message_block(app->notification, &seq_c_minor); + } + } + + view_port_enabled_set(app->view_port, false); + gui_remove_view_port(app->gui, app->view_port); + view_port_free(app->view_port); + + app_deinit(app); + + notification_message(app->notification, &sequence_display_backlight_enforce_auto); + + usb_uart_disable(app->uart); + + furi_message_queue_free(app->event_queue); + furi_mutex_free(app->gui_mutex); + furi_mutex_free(app->swd_mutex); + free(app); + + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + + return 0; +} diff --git a/applications/plugins/swd_probe/swd_probe_app.h b/applications/plugins/swd_probe/swd_probe_app.h new file mode 100644 index 0000000000..152088925c --- /dev/null +++ b/applications/plugins/swd_probe/swd_probe_app.h @@ -0,0 +1,233 @@ +#ifndef __ARHA_FLIPPERAPP_DEMO +#define __ARHA_FLIPPERAPP_DEMO + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb_uart.h" + +#define TAG "SWD" + +/* short debug message */ +#define DBGS(format) furi_log_print_format(FuriLogLevelDebug, TAG, "%s: " format, __FUNCTION__) +/* formatted debug message */ +#define DBG(format, ...) \ + furi_log_print_format(FuriLogLevelDebug, TAG, "%s: " format, __FUNCTION__, __VA_ARGS__) +/* log message*/ +#define LOG(...) furi_log_print_format(FuriLogLevelDefault, TAG, __VA_ARGS__) + +#define COUNT(x) ((size_t)(sizeof(x) / sizeof((x)[0]))) +#define ARRAY_SIZE(x) COUNT(x) + +#define SWD_DELAY_US 0 +#define TIMER_HZ 25 +#define TIMEOUT 3 +#define QUEUE_SIZE 8 +#define IDLE_BITS 8 +#define CLOCK_DELAY 0 + +#define MAX_FILE_LENGTH 128 +#define SCRIPT_MAX_LINES 1000 + +typedef enum { + ModePageScan = 0, + ModePageFound = 1, + ModePageDPRegs = 2, + ModePageDPID = 3, + ModePageAPID = 4, + ModePageCount = 5, + ModePageHexDump = 0x100, + ModePageScript = 0x101, + ModePageCoresight = 0x102, +} ModePages; + +#define CDBGPWRUPREQ (1 << 28) +#define CDBGPWRUPACK (1 << 29) +#define CSYSPWRUPREQ (1 << 30) +#define CSYSPWRUPACK (1 << 31) +#define WDATAERR (1 << 7) +#define STICKYERR (1 << 5) +#define STAT_ERROR_FLAGS (WDATAERR | STICKYERR) + +#define REG_IDCODE 0x00 +#define REG_CTRLSTAT 0x01 +#define REG_CTRLSTAT_BANK 0x00 +#define REG_DLCR 0x01 +#define REG_DLCR_BANK 0x01 +#define REG_TARGETID 0x01 +#define REG_TARGETID_BANK 0x02 +#define REG_DLPIDR 0x01 +#define REG_DLPIDR_BANK 0x03 +#define REG_EVENTSTAT 0x01 +#define REG_EVENTSTAT_BANK 0x04 + +#define REG_SELECT 0x02 + +#define MEMAP_CSW 0x00 +#define MEMAP_TAR 0x04 +#define MEMAP_DRW 0x0C +#define AP_IDR 0xFC +#define AP_BASE 0xF8 + +typedef enum { KeyNone, KeyUp, KeyRight, KeyDown, KeyLeft, KeyOK } KeyCode; + +typedef enum { + EventTimerTick, + EventKeyPress, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} AppEvent; + +typedef struct { + uint32_t ctrlstat; + bool ctrlstat_ok; + uint32_t dlcr; + bool dlcr_ok; + uint32_t dlpidr; + bool dlpidr_ok; + uint32_t dpidr; + bool dpidr_ok; + uint32_t eventstat; + bool eventstat_ok; + uint32_t select; + bool select_ok; + uint32_t targetid; + bool targetid_ok; +} swd_dpreg_t; + +typedef struct { + bool ok; + bool tested; + uint8_t revision; + uint16_t designer; + uint8_t class; + uint8_t variant; + uint8_t type; + uint32_t base; +} swd_apidr_info_t; + +typedef struct { + uint8_t revision; + uint8_t partno; + uint8_t version; + uint16_t designer; +} swd_dpidr_info_t; + +typedef struct { + uint8_t revision; + uint16_t partno; + uint16_t designer; +} swd_targetid_info_t; + +typedef struct sScriptContext ScriptContext; + +typedef struct { + Storage* storage; + Gui* gui; + DialogsApp* dialogs; + NotificationApp* notification; + + FuriTimer* timer; + UsbUart* uart; + ViewPort* view_port; + + FuriMessageQueue* event_queue; + FuriMutex* swd_mutex; + FuriMutex* gui_mutex; + + swd_targetid_info_t targetid_info; + swd_dpidr_info_t dpidr_info; + swd_dpreg_t dp_regs; + swd_apidr_info_t apidr_info[256]; + + ScriptContext* script; + ScriptContext* commandline; + + uint8_t timeout_overdue; + uint32_t loop_count; + uint8_t current_mask_id; + uint32_t current_mask; + uint8_t io_swc; + uint8_t io_swd; + uint8_t io_num_swc; + uint8_t io_num_swd; + int32_t detected_timeout; + uint32_t swd_clock_delay; + uint32_t swd_idle_bits; + bool detected; + bool detected_device; + bool detected_notified; + uint32_t mode_page; + uint8_t ap_pos; + uint8_t ap_scanned; + + uint32_t coresight_pos[16]; + uint32_t coresight_count[16]; + uint8_t coresight_level; + uint32_t coresight_bases[16]; + + uint32_t hex_addr; + uint8_t hex_select; + uint8_t hex_buffer[32]; + uint8_t hex_buffer_valid[8]; + + char state_string[64]; + char script_detected[MAX_FILE_LENGTH]; + bool script_detected_executed; +} AppFSM; + +struct sScriptContext { + AppFSM* app; + ScriptContext* parent; + char filename[MAX_FILE_LENGTH]; + + /* when used with string input */ + char line_data[128]; + uint64_t line_pos; + + /* when used with file input */ + File* script_file; + + uint64_t position; + uint32_t selected_ap; + uint32_t max_tries; + uint32_t block_size; + + bool abort; + bool restart; + bool errors_ignore; + bool status_ignore; + bool goto_active; + char goto_label[64]; +}; + +typedef struct { + const char* prefix; + bool (*func)(ScriptContext* ctx); +} ScriptFunctionInfo; + +uint8_t swd_read_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t* data); + +#endif \ No newline at end of file diff --git a/applications/plugins/swd_probe/usb_uart.c b/applications/plugins/swd_probe/usb_uart.c new file mode 100644 index 0000000000..76841cf11d --- /dev/null +++ b/applications/plugins/swd_probe/usb_uart.c @@ -0,0 +1,223 @@ + +#include + +#include "usb_uart.h" +#include "furi_hal.h" +#include +#include "usb_cdc.h" +#include "cli/cli_vcp.h" +#include +#include "cli/cli.h" + +#define USB_CDC_PKT_LEN CDC_DATA_SZ +#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) + +#define USB_CDC_BIT_DTR (1 << 0) +#define USB_CDC_BIT_RTS (1 << 1) + +typedef enum { + WorkerEvtStop = (1 << 0), + WorkerEvtCdcRx = (1 << 1), + WorkerEvtCfgChange = (1 << 2) + +} WorkerEvtFlags; + +#define WORKER_ALL_EVENTS (WorkerEvtStop | WorkerEvtCfgChange | WorkerEvtCdcRx) + +struct UsbUart { + UsbUartConfig cfg; + UsbUartConfig cfg_new; + + FuriThread* thread; + FuriMutex* usb_mutex; + FuriSemaphore* tx_sem; + UsbUartState st; + FuriApiLock cfg_lock; + + uint8_t rx_buf[USB_CDC_PKT_LEN]; +}; + +static void vcp_on_cdc_tx_complete(void* context); +static void vcp_on_cdc_rx(void* context); +static void vcp_state_callback(void* context, uint8_t state); +static void vcp_on_cdc_control_line(void* context, uint8_t state); +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config); + +static const CdcCallbacks cdc_cb = { + .tx_ep_callback = &vcp_on_cdc_tx_complete, + .rx_ep_callback = &vcp_on_cdc_rx, + .state_callback = &vcp_state_callback, + .ctrl_line_callback = &vcp_on_cdc_control_line, + .config_callback = &vcp_on_line_config}; + +static void usb_uart_vcp_init(UsbUart* usb_uart, uint8_t vcp_ch) { + furi_hal_usb_unlock(); + + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + + if(vcp_ch == 0) { + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); + } else { + furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true); + cli_session_open(cli, &cli_vcp); + } + furi_record_close(RECORD_CLI); + furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart); +} + +static void usb_uart_vcp_deinit(UsbUart* usb_uart, uint8_t vcp_ch) { + UNUSED(usb_uart); + furi_hal_cdc_set_callbacks(vcp_ch, NULL, NULL); + if(vcp_ch != 0) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_record_close(RECORD_CLI); + } +} + +void usb_uart_tx_data(UsbUart* usb_uart, uint8_t* data, size_t length) { + uint32_t pos = 0; + while(pos < length) { + size_t pkt_size = length - pos; + + if(pkt_size > USB_CDC_PKT_LEN) { + pkt_size = USB_CDC_PKT_LEN; + } + + if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) { + furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk); + furi_hal_cdc_send(usb_uart->cfg.vcp_ch, &data[pos], pkt_size); + furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); + usb_uart->st.tx_cnt += pkt_size; + pos += pkt_size; + } + } +} + +static int32_t usb_uart_worker(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + + memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig)); + + usb_uart->tx_sem = furi_semaphore_alloc(1, 1); + usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); + + uint8_t data[2 * USB_CDC_PKT_LEN]; + size_t remain = 0; + + while(1) { + uint32_t events = + furi_thread_flags_wait(WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever); + furi_check(!(events & FuriFlagError)); + + if(events & WorkerEvtStop) { + break; + } + + if(events & WorkerEvtCdcRx) { + furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk); + size_t len = + furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, &data[remain], USB_CDC_PKT_LEN); + furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); + + if(len > 0) { + usb_uart->st.rx_cnt += len; + remain += len; + + size_t handled = usb_uart->cfg.rx_data(usb_uart->cfg.rx_data_ctx, data, remain); + + memcpy(data, &data[handled], remain - handled); + remain -= handled; + } + } + + if(events & WorkerEvtCfgChange) { + if(usb_uart->cfg.vcp_ch != usb_uart->cfg_new.vcp_ch) { + usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); + usb_uart_vcp_init(usb_uart, usb_uart->cfg_new.vcp_ch); + + usb_uart->cfg.vcp_ch = usb_uart->cfg_new.vcp_ch; + } + api_lock_unlock(usb_uart->cfg_lock); + } + } + usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); + + furi_mutex_free(usb_uart->usb_mutex); + furi_semaphore_free(usb_uart->tx_sem); + + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + + return 0; +} + +/* VCP callbacks */ +static void vcp_on_cdc_tx_complete(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + furi_semaphore_release(usb_uart->tx_sem); +} + +static void vcp_on_cdc_rx(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCdcRx); +} + +static void vcp_state_callback(void* context, uint8_t state) { + UNUSED(context); + UNUSED(state); +} + +static void vcp_on_cdc_control_line(void* context, uint8_t state) { + UNUSED(context); + UNUSED(state); +} + +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) { + UNUSED(context); + UNUSED(config); +} + +UsbUart* usb_uart_enable(UsbUartConfig* cfg) { + UsbUart* usb_uart = malloc(sizeof(UsbUart)); + memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); + + usb_uart->thread = furi_thread_alloc_ex("UsbUartWorker", 1024, usb_uart_worker, usb_uart); + furi_thread_start(usb_uart->thread); + return usb_uart; +} + +void usb_uart_disable(UsbUart* usb_uart) { + furi_assert(usb_uart); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtStop); + furi_thread_join(usb_uart->thread); + furi_thread_free(usb_uart->thread); + free(usb_uart); +} + +void usb_uart_set_config(UsbUart* usb_uart, UsbUartConfig* cfg) { + furi_assert(usb_uart); + furi_assert(cfg); + usb_uart->cfg_lock = api_lock_alloc_locked(); + memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange); + api_lock_wait_unlock_and_free(usb_uart->cfg_lock); +} + +void usb_uart_get_config(UsbUart* usb_uart, UsbUartConfig* cfg) { + furi_assert(usb_uart); + furi_assert(cfg); + memcpy(cfg, &(usb_uart->cfg_new), sizeof(UsbUartConfig)); +} + +void usb_uart_get_state(UsbUart* usb_uart, UsbUartState* st) { + furi_assert(usb_uart); + furi_assert(st); + memcpy(st, &(usb_uart->st), sizeof(UsbUartState)); +} diff --git a/applications/plugins/swd_probe/usb_uart.h b/applications/plugins/swd_probe/usb_uart.h new file mode 100644 index 0000000000..a82f36a056 --- /dev/null +++ b/applications/plugins/swd_probe/usb_uart.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +typedef struct UsbUart UsbUart; + +typedef struct { + uint8_t vcp_ch; + size_t (*rx_data)(void* ctx, uint8_t* data, size_t length); + void* rx_data_ctx; +} UsbUartConfig; + +typedef struct { + uint32_t rx_cnt; + uint32_t tx_cnt; +} UsbUartState; + +UsbUart* usb_uart_enable(UsbUartConfig* cfg); + +void usb_uart_disable(UsbUart* usb_uart); + +void usb_uart_set_config(UsbUart* usb_uart, UsbUartConfig* cfg); + +void usb_uart_get_config(UsbUart* usb_uart, UsbUartConfig* cfg); + +void usb_uart_get_state(UsbUart* usb_uart, UsbUartState* st); + +void usb_uart_tx_data(UsbUart* usb_uart, uint8_t* data, size_t length); diff --git a/assets/resources/swd_scripts/100us.swd b/assets/resources/swd_scripts/100us.swd new file mode 100644 index 0000000000..3ad89a0ab1 --- /dev/null +++ b/assets/resources/swd_scripts/100us.swd @@ -0,0 +1 @@ +swd_clock_delay 100 diff --git a/assets/resources/swd_scripts/call_test_1.swd b/assets/resources/swd_scripts/call_test_1.swd new file mode 100644 index 0000000000..03f5575f41 --- /dev/null +++ b/assets/resources/swd_scripts/call_test_1.swd @@ -0,0 +1,6 @@ + +message 0 "gonna call call_test_2" dialog + +call call_test_2 + +message 0 "back now" dialog diff --git a/assets/resources/swd_scripts/call_test_2.swd b/assets/resources/swd_scripts/call_test_2.swd new file mode 100644 index 0000000000..f358b6ece3 --- /dev/null +++ b/assets/resources/swd_scripts/call_test_2.swd @@ -0,0 +1,7 @@ + +# first do a beeeeeep +beep 1 + +message 0 "Seems to work" dialog + +beep 0 diff --git a/assets/resources/swd_scripts/dump_0x00000000_1k.swd b/assets/resources/swd_scripts/dump_0x00000000_1k.swd new file mode 100644 index 0000000000..a8870fe30e --- /dev/null +++ b/assets/resources/swd_scripts/dump_0x00000000_1k.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 4 +mem_dump /ext/swd_scripts/flash.bin 0x00000000 0x100000 2 +beep 1 +message 5 "Reading sucessful" diff --git a/assets/resources/swd_scripts/dump_0x00000000_4b.swd b/assets/resources/swd_scripts/dump_0x00000000_4b.swd new file mode 100644 index 0000000000..a8870fe30e --- /dev/null +++ b/assets/resources/swd_scripts/dump_0x00000000_4b.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 4 +mem_dump /ext/swd_scripts/flash.bin 0x00000000 0x100000 2 +beep 1 +message 5 "Reading sucessful" diff --git a/assets/resources/swd_scripts/dump_STM32.swd b/assets/resources/swd_scripts/dump_STM32.swd new file mode 100644 index 0000000000..e675537c98 --- /dev/null +++ b/assets/resources/swd_scripts/dump_STM32.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 1024 +mem_dump /ext/swd_scripts/flash.bin 0x08000000 0x100000 2 +beep 1 +message 0 "Reading finished" dialog diff --git a/assets/resources/swd_scripts/goto_test.swd b/assets/resources/swd_scripts/goto_test.swd new file mode 100644 index 0000000000..680285653b --- /dev/null +++ b/assets/resources/swd_scripts/goto_test.swd @@ -0,0 +1,7 @@ +beep 1 +goto l2 +.label l1 +beep 0 +.label l2 +beep 1 +goto l1 diff --git a/assets/resources/swd_scripts/halt.swd b/assets/resources/swd_scripts/halt.swd new file mode 100644 index 0000000000..6aad4c194b --- /dev/null +++ b/assets/resources/swd_scripts/halt.swd @@ -0,0 +1,11 @@ + +# make sure errors do not cause a script abort +errors ignore + +message 0 "HAMMER TIME! Trying to halt CPU" +ap_select 0 + +# loop writing the halt bits +.label l1 +mem_write 0xE000EDF0 0xA05F0003 +goto l1 diff --git a/assets/resources/swd_scripts/reset.swd b/assets/resources/swd_scripts/reset.swd new file mode 100644 index 0000000000..1872757fb4 --- /dev/null +++ b/assets/resources/swd_scripts/reset.swd @@ -0,0 +1,8 @@ +errors ignore +status 0 +message 0 "HAMMER TIME! Try to halt the CPU" +.label l1 +ap_select 0 +mem_write 0xE000EDF0 0xA05F0001 +mem_write 0xE000ED0C 0x05FA0004 +goto l1 diff --git a/assets/resources/swd_scripts/test_write.swd b/assets/resources/swd_scripts/test_write.swd new file mode 100644 index 0000000000..df69461fde --- /dev/null +++ b/assets/resources/swd_scripts/test_write.swd @@ -0,0 +1,3 @@ +mem_write 0x20002000 0xdeadbeef +mem_write 0xE000EDF0 0xA05F0001 +mem_write 0xE000EDF0 0xA05F0007 From 72fd448541a5c91250d7cf215eacca7b60ebe174 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 24 Feb 2023 03:04:12 +0300 Subject: [PATCH 37/41] replace paths --- applications/plugins/swd_probe/swd_probe_app.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/plugins/swd_probe/swd_probe_app.c b/applications/plugins/swd_probe/swd_probe_app.c index fcebd8348f..0561cbde73 100644 --- a/applications/plugins/swd_probe/swd_probe_app.c +++ b/applications/plugins/swd_probe/swd_probe_app.c @@ -2589,10 +2589,10 @@ static bool swd_message_process(AppFSM* ctx) { break; case ModePageScan: { - FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd")); + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd_scripts")); FuriString* preselected = furi_string_alloc_printf( (strlen(ctx->script_detected) > 0) ? ctx->script_detected : - ANY_PATH("swd")); + ANY_PATH("swd_scripts")); DialogsFileBrowserOptions options; dialog_file_browser_set_basic_options(&options, "swd", &I_swd); @@ -2662,10 +2662,10 @@ static bool swd_message_process(AppFSM* ctx) { } } else if((ctx->mode_page == ModePageScan) || (ctx->mode_page == ModePageFound)) { uint32_t mode_page = ctx->mode_page; - FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd")); + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd_scripts")); FuriString* preselected = furi_string_alloc_printf( (strlen(ctx->script_detected) > 0) ? ctx->script_detected : - ANY_PATH("swd")); + ANY_PATH("swd_scripts")); DialogsFileBrowserOptions options; dialog_file_browser_set_basic_options(&options, "swd", &I_swd); From c230d09dad6c0d72b52af565d4b0a44bae77ebf2 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 24 Feb 2023 03:04:36 +0300 Subject: [PATCH 38/41] Faster Turn OFF hold time --- applications/services/desktop/views/desktop_view_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index 52a67f9a35..7e68cd4cac 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -17,7 +17,7 @@ struct DesktopMainView { bool dummy_mode; }; -#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 2000 +#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 1300 static void desktop_main_poweroff_timer_callback(TimerHandle_t timer) { DesktopMainView* main_view = pvTimerGetTimerID(timer); From f3e3e828aa6e695986e604ccbd47b896d9e338b2 Mon Sep 17 00:00:00 2001 From: Willy-JL Date: Fri, 24 Feb 2023 00:10:04 +0000 Subject: [PATCH 39/41] Fix keyboard capitalization bug --- applications/services/gui/modules/text_input.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index 60700f12ab..ebe32b7a56 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -138,7 +138,7 @@ static bool char_is_lowercase(char letter) { static char char_to_uppercase(const char letter) { if(letter == '_') { return 0x20; - } else if(islower(letter)) { + } else if(char_is_lowercase(letter)) { return (letter - 0x20); } else { return letter; @@ -237,8 +237,7 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_set_color(canvas, ColorBlack); } - if(model->clear_default_text || - (text_length == 0 && char_is_lowercase(keys[column].text))) { + if((model->clear_default_text || text_length == 0) && char_is_lowercase(keys[column].text)) { canvas_draw_glyph( canvas, keyboard_origin_x + keys[column].x, @@ -309,12 +308,6 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b char selected = get_selected_char(model); size_t text_length = strlen(model->text_buffer); - bool toggle_case = text_length == 0; - if(shift) toggle_case = !toggle_case; - if(toggle_case) { - selected = char_to_uppercase(selected); - } - if(selected == ENTER_KEY) { if(model->validator_callback && (!model->validator_callback( @@ -331,6 +324,9 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b text_length = 0; } if(text_length < (model->text_buffer_size - 1)) { + if(shift || (text_length == 0 && char_is_lowercase(selected))) { + selected = char_to_uppercase(selected); + } model->text_buffer[text_length] = selected; model->text_buffer[text_length + 1] = 0; } From f8eda660d2e5a47bf631e1d33382285c6cf3c7a0 Mon Sep 17 00:00:00 2001 From: Willy-JL Date: Fri, 24 Feb 2023 00:49:41 +0000 Subject: [PATCH 40/41] Keyboard long press first char for lowercase --- applications/services/gui/modules/text_input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index ebe32b7a56..5fd306aa6a 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -237,7 +237,7 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { canvas_set_color(canvas, ColorBlack); } - if((model->clear_default_text || text_length == 0) && char_is_lowercase(keys[column].text)) { + if(model->clear_default_text || text_length == 0) { canvas_draw_glyph( canvas, keyboard_origin_x + keys[column].x, @@ -324,7 +324,7 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b text_length = 0; } if(text_length < (model->text_buffer_size - 1)) { - if(shift || (text_length == 0 && char_is_lowercase(selected))) { + if(shift != (text_length == 0)) { selected = char_to_uppercase(selected); } model->text_buffer[text_length] = selected; From 86da6a7ffe4429a1ff58db540237a3ff0dd88efe Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 24 Feb 2023 04:15:32 +0300 Subject: [PATCH 41/41] Update changelog --- CHANGELOG.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96f3c65d68..d9fd54ba08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,19 @@ ### New changes -* SubGHz: **Nice ON2E (Nice One)** support (by @assasinfil | PR #335) -* SubGHz: Remove 467.75 From freq analyzer since it has too much noise (Frequency is still can be used, just excluded from FA to avoid false detections) -* Archive and FileBrowser: **Fixed more navigation issues** (by @Willy-JL | PR #334) -* Plugins -> SubGHz Bruteforcer: Fix Linear Delta 3 repeats (now its more stable and we will be sure signal is received correctly) -* Plugins: Updated TOTP (Authenticator) [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* OFW: **Fix Cyfral & Metakom emulation (My temp fix removed and proper fix from OFW applied)** -* OFW: BadUSB: disable CDC mode, USB mode switch fix -* OFW: Updater visual fixes +* Desktop: Autolock with PIN Code (by @Willy-JL | PR #338) - **Desktop settings (pin code, favourite app, autolock time) will be resetted!!! Only one time after installing - due to changes in settings structure, after installing of this release desktop settings will not be reset with next release** +* Desktop: Faster back button hold time for power off, was 2 seconds, now 1.3sec +* GUI: Fix keyboard capitalization bug (by @Willy-JL | PR #362) (fixes #361) +* Plugins: Added **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) (moved from extra pack into main FW) +* Plugins: Show RSSI in Weather Station app and in POCSAG Pager app +* Plugins: Improve Tetris fall speed algorithm (by @p3ngu19z | PR #343) +* Plugins: Add missing buttons into HID app, remove old keyboard app, move Bluetooth remote to Misc +* Infrared: Assets update (by @amec0e | PR #340 / #357 / #358) +* Misc: Typo combing (by @Round-Pi | PR #352) +* OFW: Dolphin: drop holiday animation +* OFW: fbt: FBT_QUIET option; docs on environment +* OFW: Delete rwfiletest.bin on exit SDcard benchmark +* OFW: Re-init NFC when starting the worker +* OFW: Up toolchain version to 21 +* OFW: Display Mifare Classic data in NFC app #### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps)