From 6982b4533bd9ddead8d6b3d0bcf776a1bfbcbc57 Mon Sep 17 00:00:00 2001 From: Eric Betts Date: Sat, 8 Jul 2023 14:51:49 -0700 Subject: [PATCH] Add view showing gpio traffic --- application.fam | 1 + icons/ArrowUpEmpty_14x15.png | Bin 0 -> 3616 bytes icons/ArrowUpFilled_14x15.png | Bin 0 -> 3628 bytes scenes/seader_scene_config.h | 1 + scenes/seader_scene_sam_present.c | 26 +++-- scenes/seader_scene_uart.c | 101 ++++++++++++++++++++ seader.c | 9 ++ seader_bridge.h | 2 +- seader_custom_event.h | 5 + seader_i.h | 5 + seader_worker.c | 2 + uart.c | 1 - views/seader_uart_view.c | 152 ++++++++++++++++++++++++++++++ views/seader_uart_view.h | 24 +++++ 14 files changed, 321 insertions(+), 8 deletions(-) create mode 100644 icons/ArrowUpEmpty_14x15.png create mode 100644 icons/ArrowUpFilled_14x15.png create mode 100644 scenes/seader_scene_uart.c create mode 100644 seader_custom_event.h create mode 100644 views/seader_uart_view.c create mode 100644 views/seader_uart_view.h diff --git a/application.fam b/application.fam index 0d6b414..c302a05 100644 --- a/application.fam +++ b/application.fam @@ -19,6 +19,7 @@ App( "seader_worker.c", "seader_credential.c", "seader_icons.c", + "views/*.c", ], fap_icon="icons/logo.png", fap_category="NFC", diff --git a/icons/ArrowUpEmpty_14x15.png b/icons/ArrowUpEmpty_14x15.png new file mode 100644 index 0000000000000000000000000000000000000000..261c6d89e3c9a75d61803c83569b989345cca06e GIT binary patch literal 3616 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 literal 0 HcmV?d00001 diff --git a/icons/ArrowUpFilled_14x15.png b/icons/ArrowUpFilled_14x15.png new file mode 100644 index 0000000000000000000000000000000000000000..fa35eb2f827bbf3b125673521e94c40ace83f035 GIT binary patch literal 3628 zcmaJ@c{r49+rMpP$&!5uW5m;f8CzvCwjra)G`3MGV+;nfGzK%0l$4S!Th@d~4QwO&8b<}ZdQDH@4002a7kd|of zD#m@q1^Kw&k!GdqqOhtUfYI*jZX;XC~6A?sAtfGAn90XAjHU{6^HtXs6SMzN_{Z zKEDvcnVDJrxLPrhIkDEpXcrIPDXEz-p6d%3p(Bl9J*si`$hxM=a9$bYAU{ZAoL%cJ zP!9mJd<=RR?Xl?^&m%Ix3sAarc1t!4ZAO%%G+h8t0x$@coDkuOM+1#Ij*Zelqdf4~ z;hCo}kOTn!j8F?O@IVxp{%K<(0Q3|k_R9f1xx0!4ffybjZIAVCUb9z#yVE7K7H>^0 zki#?s>+si<@Pxa*(6i7KOHN+Yn^R3$7fK8k1(;XuYmUFz{+#V!6ZV~lH(CtS83dSx&1>IO6iEOi zybbgiO8}5qy&Pw@p9g47%^v}Pim&pg?&A`dib9|=2OhsnLZ>@`dasp=)|Dp=}S`-xoz(9 z*|qW&SB3b^8wI7XYOtuC9(HbJ?xSbi`TX>cn%A2b;yeF9wHNX_RhvhYoCL#qGK zrb-*doHkpD?`s6<-B`O(VXd2V>FEi+54?e9FYl`=-gui6&_Od0cMDI+_3Kb9Re^`U z$Sv$R_BD_OT(}X73-8bs^Sb#7d-~=zEBEUdMa>3T+!)5tInEHLj5!!2qg0cP`@CL(u>HQgFLF07^zuV*7-}+YUexTn{-MLGHo@d;)zXPMg^aS zGeM~dW%1(i_P17>-i($>!|J1kZH01oqw|v_j~e1l$N2Bv(X&X)d2ph&DEoupgDBXY zlQzVhAQZ&mT9K4NV7f+YhAe`eubtQRE}h^_Sn`2P(#nNCN2pk(zDw=&`?`H{Vlv`q z@D9V4v zAoq>a&FN4*2sIEq5U=2`dk8n%5|8`pcbmZKn7uM|e<$0gJfY4fufrzqFP7%_Yu+P< zbU70*CV7_!)8Grf-_IE9LD1{Vugk9=t=ij~ZfHK0T#1MeKI*M=7~v z?8ty+uwUFS&M2-6${-F%4@<}G?cBTIK0~H1xxImN%zw@kdl` z+rE~)dU%Ds9`~zyi19;q?zn(E&ugABp2|y#m!9$Y@u~8s@!#8SC=es?Y8zySiHyY# zAyHRVY9hHt?uXJcPQTwaczMUv_pq-;FX>~J4U01y;W9Qt~LpJEqWZC1d@$FXhH3+t}H` z#;%60@u7zzZ%d{=H64opS)d^D_G5)4J7uXKS27~)t*UZka!))dV;wcVHJ;_1ym;vI z;R}crpR4vq0^jNj*`xO}5)^K|RG+tVw(S1GZ2xrbleSS(W>RJzT9lAdy8k1zY)_fJ z*Z%#9qN9v)VzW}>wdSQ!_2q#1J{kW=+m5_abO}mK))sPqKmC;aDLM;Ti9Gp1f52Q>eV$l(u_wFI~Uv@D_E=p=*lS+P`e2J66CVM(@d{etlIbYl-mwc8^?2B4mUXaweRkaWd*`<=T5+a)X=MNYN7dC&g^1__ zF)BzHWh^6{+?z3z9{ikga-UeO`Pl2f1`0yYkD$KZZF|%Irgb3gV%dV=6q2#O6ILC_ z)XpR3!0%RazTV8sQa+<>T~)Rj#?c+Y1vVJQxn$>L?SaoNk6un3DfBGN&N^-i|B%+t zSh8J9^K(1lR_Tps&o-5#eYY(;yVNxQWg^aPwu15#yyVfRQFg2tUIMocqpS}hADtpk z;g{GmF2*IapLSD+J2>wzuK3n;1$_MVQOE5LqmuJ>TB(er`FR&hqkQ34(Bh0-u<&== zez%Y~`lGd~-t}+WSH!yfFaqX%ZYUG>n}s3`ZvFV7F{^ z=tK$^4FJZbbP5*dho^x&@ZJOx9L#xD4F(ZB;b0d-JE$E6f%hRGL#TL%kmHWH5I>xe zC)m^kWK4%~35a+a7DOldlLBCLIQVZ~7+2m>L%^WFO=x~_@PC5B*r7lOG8GRxsH3Zm zgF>O8gGM@@SPv}D!$S+C2i4PsKn)55d^9S(bLoBT4)C_NHi>6n-rk_o52zvfTI#9Gy<6f z+G50dkOOIOFgMiyRKTz3=I*8gBIqN zhKK{Y2lb79V=c+JKq8(*`;GPdFZR$Mv0LLnq;Nf3;;Donyyp=rnF#tjYZ&3ru^9f5 z?;ot^pJO@jM=XRJ3}maf|Et%(RonsE68{}t?&ja&$CJ1dPvwrb(7l^v?r*UTW$S3Q zxw**|ooe5QahJn3mgbK1-Yc;k!T?l|w{mlHGUlX@ePRyxMtL+x!l_{DmM2M3#dlob pSvNf~;vDtN$}5p)%c7HlP++$_;B=kyp@2&R*jOF6EU|FE{67WAU$+1N literal 0 HcmV?d00001 diff --git a/scenes/seader_scene_config.h b/scenes/seader_scene_config.h index 2d8dcb5..5231b95 100644 --- a/scenes/seader_scene_config.h +++ b/scenes/seader_scene_config.h @@ -14,3 +14,4 @@ ADD_SCENE(seader, delete, Delete) ADD_SCENE(seader, delete_success, DeleteSuccess) ADD_SCENE(seader, credential_info, CredentialInfo) ADD_SCENE(seader, sam_info, SamInfo) +ADD_SCENE(seader, uart, Uart) diff --git a/scenes/seader_scene_sam_present.c b/scenes/seader_scene_sam_present.c index 1e1d041..61b0ef0 100644 --- a/scenes/seader_scene_sam_present.c +++ b/scenes/seader_scene_sam_present.c @@ -66,14 +66,28 @@ bool seader_scene_sam_present_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexReadPicopass) { - scene_manager_set_scene_state( - seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadPicopass); - scene_manager_next_scene(seader->scene_manager, SeaderSceneReadPicopass); + if(seader->is_debug_enabled) { + seader->credential->type = SeaderCredentialTypePicopass; + scene_manager_set_scene_state( + seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadPicopass); + scene_manager_next_scene(seader->scene_manager, SeaderSceneUart); + } else { + scene_manager_set_scene_state( + seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexReadPicopass); + scene_manager_next_scene(seader->scene_manager, SeaderSceneReadPicopass); + } consumed = true; } else if(event.event == SubmenuIndexRead14a) { - scene_manager_set_scene_state( - seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a); - scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a); + if(seader->is_debug_enabled) { + seader->credential->type = SeaderCredentialType14A; + scene_manager_set_scene_state( + seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a); + scene_manager_next_scene(seader->scene_manager, SeaderSceneUart); + } else { + scene_manager_set_scene_state( + seader->scene_manager, SeaderSceneSamPresent, SubmenuIndexRead14a); + scene_manager_next_scene(seader->scene_manager, SeaderSceneRead14a); + } consumed = true; } else if(event.event == SubmenuIndexSamInfo) { scene_manager_set_scene_state( diff --git a/scenes/seader_scene_uart.c b/scenes/seader_scene_uart.c new file mode 100644 index 0000000..ccd7be8 --- /dev/null +++ b/scenes/seader_scene_uart.c @@ -0,0 +1,101 @@ +#include "../seader_i.h" +#include "../seader_bridge.h" +#define TAG "SeaderSceneUart" + +typedef struct { + SeaderUartConfig cfg; + SeaderUartState state; +} SceneUartBridge; + +static SceneUartBridge* scene_uart; + +void seader_uart_worker_callback(SeaderWorkerEvent event, void* context) { + UNUSED(event); + Seader* seader = context; + view_dispatcher_send_custom_event(seader->view_dispatcher, SeaderCustomEventWorkerExit); +} + +void seader_scene_uart_callback(SeaderCustomEvent event, void* context) { + furi_assert(context); + Seader* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void seader_scene_uart_on_enter(void* context) { + Seader* app = context; + uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, SeaderViewUart); + if(prev_state == 0) { + scene_uart = malloc(sizeof(SceneUartBridge)); + scene_uart->cfg.uart_ch = 0; + scene_uart->cfg.flow_pins = 0; + scene_uart->cfg.baudrate_mode = 0; + scene_uart->cfg.baudrate = 0; + } + + seader_uart_get_config(app->uart, &scene_uart->cfg); + seader_uart_get_state(app->uart, &scene_uart->state); + + seader_uart_view_set_callback(app->seader_uart_view, seader_scene_uart_callback, app); + scene_manager_set_scene_state(app->scene_manager, SeaderSceneUart, 0); + view_dispatcher_switch_to_view(app->view_dispatcher, SeaderViewUart); + notification_message(app->notifications, &sequence_display_backlight_enforce_on); + + Seader* seader = app; + + if(seader->credential->type == SeaderCredentialTypePicopass) { + seader_worker_start( + seader->worker, + SeaderWorkerStateReadPicopass, + seader->uart, + seader->credential, + seader_uart_worker_callback, + seader); + } else if(seader->credential->type == SeaderCredentialType14A) { + seader_worker_start( + seader->worker, + SeaderWorkerStateRead14a, + seader->uart, + seader->credential, + seader_uart_worker_callback, + seader); + } +} + +bool seader_scene_uart_on_event(void* context, SceneManagerEvent event) { + Seader* app = context; + Seader* seader = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SeaderCustomEventWorkerExit) { + scene_manager_next_scene(seader->scene_manager, SeaderSceneReadCardSuccess); + consumed = true; + } else if(event.type == SceneManagerEventTypeTick) { + scene_manager_set_scene_state(app->scene_manager, SeaderSceneUart, 1); + consumed = true; + } + } else if(event.type == SceneManagerEventTypeTick) { + uint32_t tx_cnt_last = scene_uart->state.tx_cnt; + uint32_t rx_cnt_last = scene_uart->state.rx_cnt; + seader_uart_get_state(app->uart, &scene_uart->state); + if(seader->credential->type == SeaderCredentialTypePicopass) { + scene_uart->state.protocol = FrameProtocol_iclass; + } else if(seader->credential->type == SeaderCredentialType14A) { + scene_uart->state.protocol = FrameProtocol_nfc; + } + seader_uart_view_update_state(app->seader_uart_view, &scene_uart->cfg, &scene_uart->state); + if(tx_cnt_last != scene_uart->state.tx_cnt) { + notification_message(app->notifications, &sequence_blink_blue_10); + } + if(rx_cnt_last != scene_uart->state.rx_cnt) { + notification_message(app->notifications, &sequence_blink_green_10); + } + } + return consumed; +} + +void seader_scene_uart_on_exit(void* context) { + Seader* app = context; + seader_worker_stop(app->worker); + notification_message(app->notifications, &sequence_display_backlight_enforce_auto); +} diff --git a/seader.c b/seader.c index ba74eab..9d566d7 100644 --- a/seader.c +++ b/seader.c @@ -78,6 +78,12 @@ Seader* seader_alloc() { view_dispatcher_add_view( seader->view_dispatcher, SeaderViewWidget, widget_get_view(seader->widget)); + seader->seader_uart_view = seader_uart_view_alloc(); + view_dispatcher_add_view( + seader->view_dispatcher, + SeaderViewUart, + seader_uart_view_get_view(seader->seader_uart_view)); + return seader; } @@ -114,6 +120,9 @@ void seader_free(Seader* seader) { view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewWidget); widget_free(seader->widget); + view_dispatcher_remove_view(seader->view_dispatcher, SeaderViewUart); + seader_uart_view_free(seader->seader_uart_view); + // Worker seader_worker_stop(seader->worker); seader_worker_free(seader->worker); diff --git a/seader_bridge.h b/seader_bridge.h index 26f1920..7beabb6 100644 --- a/seader_bridge.h +++ b/seader_bridge.h @@ -21,7 +21,7 @@ typedef struct { typedef struct { uint32_t rx_cnt; uint32_t tx_cnt; - uint32_t baudrate_cur; + uint8_t protocol; } SeaderUartState; struct SeaderUartBridge { diff --git a/seader_custom_event.h b/seader_custom_event.h new file mode 100644 index 0000000..5749764 --- /dev/null +++ b/seader_custom_event.h @@ -0,0 +1,5 @@ +#pragma once + +typedef enum { + SeaderStartEventNone = 0, +} SeaderCustomEvent; diff --git a/seader_i.h b/seader_i.h index 1f67344..e152fdc 100644 --- a/seader_i.h +++ b/seader_i.h @@ -33,6 +33,7 @@ #include #include "scenes/seader_scene.h" +#include "views/seader_uart_view.h" #include "seader_bridge.h" #include "seader.h" @@ -93,6 +94,9 @@ struct Seader { Loading* loading; TextInput* text_input; Widget* widget; + + //Custom views + SeaderUartView* seader_uart_view; }; typedef enum { @@ -101,6 +105,7 @@ typedef enum { SeaderViewLoading, SeaderViewTextInput, SeaderViewWidget, + SeaderViewUart, } SeaderView; void seader_text_store_set(Seader* seader, const char* text, ...); diff --git a/seader_worker.c b/seader_worker.c index 3d6f317..33dbd38 100644 --- a/seader_worker.c +++ b/seader_worker.c @@ -871,6 +871,7 @@ int32_t seader_worker_task(void* context) { FURI_LOG_D(TAG, "Read Picopass"); requestPacs = true; seader_credential_clear(seader_worker->credential); + seader_worker->credential->type = SeaderCredentialTypePicopass; seader_worker_enable_field(); if(picopass_card_read(seader_worker) != ERR_NONE) { // Turn off if cancelled / no card found @@ -880,6 +881,7 @@ int32_t seader_worker_task(void* context) { FURI_LOG_D(TAG, "Read 14a"); requestPacs = true; seader_credential_clear(seader_worker->credential); + seader_worker->credential->type = SeaderCredentialType14A; nfc_scene_field_on_enter(); if(!detect_nfc(seader_worker)) { // Turn off if cancelled / no card found diff --git a/uart.c b/uart.c index b048e9f..7afd90a 100644 --- a/uart.c +++ b/uart.c @@ -33,7 +33,6 @@ void seader_uart_serial_deinit(SeaderUartBridge* seader_uart, uint8_t uart_ch) { void seader_uart_set_baudrate(SeaderUartBridge* seader_uart, uint32_t baudrate) { if(baudrate != 0) { furi_hal_uart_set_br(seader_uart->cfg.uart_ch, baudrate); - seader_uart->st.baudrate_cur = baudrate; } else { FURI_LOG_I(TAG, "No baudrate specified"); } diff --git a/views/seader_uart_view.c b/views/seader_uart_view.c new file mode 100644 index 0000000..1d1908a --- /dev/null +++ b/views/seader_uart_view.c @@ -0,0 +1,152 @@ +#include "../seader_bridge.h" +#include "../seader_i.h" +#include +#include + +struct SeaderUartView { + View* view; + SeaderUartViewCallback callback; + void* context; +}; + +typedef struct { + uint32_t tx_cnt; + uint32_t rx_cnt; + bool tx_active; + bool rx_active; + uint8_t protocol; +} SeaderUartViewModel; + +static void seader_uart_view_draw_callback(Canvas* canvas, void* _model) { + SeaderUartViewModel* model = _model; + char temp_str[18]; + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 64, 0, AlignCenter, AlignTop, "PICC <=> SAM"); + canvas_draw_str(canvas, 3, 25, "TX:"); + canvas_draw_str(canvas, 3, 42, "RX:"); + + if(model->protocol == FrameProtocol_iclass) { + canvas_draw_str_aligned(canvas, 64, 62, AlignCenter, AlignBottom, "Detecting picopass"); + } else if(model->protocol == FrameProtocol_nfc) { + canvas_draw_str_aligned(canvas, 64, 62, AlignCenter, AlignBottom, "Detecting 14a"); + } + + if(model->tx_cnt < 100000000) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "B."); + canvas_set_font(canvas, FontKeyboard); + snprintf(temp_str, 18, "%lu", model->tx_cnt); + canvas_draw_str_aligned(canvas, 116, 24, AlignRight, AlignBottom, temp_str); + } else { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 24, AlignRight, AlignBottom, "KiB."); + canvas_set_font(canvas, FontKeyboard); + snprintf(temp_str, 18, "%lu", model->tx_cnt / 1024); + canvas_draw_str_aligned(canvas, 111, 24, AlignRight, AlignBottom, temp_str); + } + + if(model->rx_cnt < 100000000) { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "B."); + canvas_set_font(canvas, FontKeyboard); + snprintf(temp_str, 18, "%lu", model->rx_cnt); + canvas_draw_str_aligned(canvas, 116, 41, AlignRight, AlignBottom, temp_str); + } else { + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 127, 41, AlignRight, AlignBottom, "KiB."); + canvas_set_font(canvas, FontKeyboard); + snprintf(temp_str, 18, "%lu", model->rx_cnt / 1024); + canvas_draw_str_aligned(canvas, 111, 41, AlignRight, AlignBottom, temp_str); + } + + if(model->tx_active) { + canvas_draw_icon(canvas, 48, 14, &I_ArrowUpFilled_14x15); + } else { + canvas_draw_icon(canvas, 48, 14, &I_ArrowUpEmpty_14x15); + } + + if(model->rx_active) { + canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpFilled_14x15, IconRotation180); + } else { + canvas_draw_icon_ex(canvas, 48, 34, &I_ArrowUpEmpty_14x15, IconRotation180); + } +} + +static bool seader_uart_view_input_callback(InputEvent* event, void* context) { + furi_assert(context); + SeaderUartView* seader_uart_view = context; + bool consumed = false; + + if(event->type == InputTypeShort) { + if(event->key == InputKeyLeft) { + consumed = true; + furi_assert(seader_uart_view->callback); + // seader_uart_view->callback(SeaderUartViewEventConfig, seader_uart_view->context); + } + } + + return consumed; +} + +SeaderUartView* seader_uart_view_alloc() { + SeaderUartView* seader_uart_view = malloc(sizeof(SeaderUartView)); + + seader_uart_view->view = view_alloc(); + view_allocate_model(seader_uart_view->view, ViewModelTypeLocking, sizeof(SeaderUartViewModel)); + view_set_context(seader_uart_view->view, seader_uart_view); + view_set_draw_callback(seader_uart_view->view, seader_uart_view_draw_callback); + view_set_input_callback(seader_uart_view->view, seader_uart_view_input_callback); + + return seader_uart_view; +} + +void seader_uart_view_free(SeaderUartView* seader_uart_view) { + furi_assert(seader_uart_view); + view_free(seader_uart_view->view); + free(seader_uart_view); +} + +View* seader_uart_view_get_view(SeaderUartView* seader_uart_view) { + furi_assert(seader_uart_view); + return seader_uart_view->view; +} + +void seader_uart_view_set_callback( + SeaderUartView* seader_uart_view, + SeaderUartViewCallback callback, + void* context) { + furi_assert(seader_uart_view); + furi_assert(callback); + + with_view_model( + seader_uart_view->view, + SeaderUartViewModel * model, + { + UNUSED(model); + seader_uart_view->callback = callback; + seader_uart_view->context = context; + }, + false); +} + +void seader_uart_view_update_state( + SeaderUartView* instance, + SeaderUartConfig* cfg, + SeaderUartState* st) { + furi_assert(instance); + furi_assert(cfg); + furi_assert(st); + + with_view_model( + instance->view, + SeaderUartViewModel * model, + { + model->tx_active = (model->tx_cnt != st->tx_cnt); + model->rx_active = (model->rx_cnt != st->rx_cnt); + model->tx_cnt = st->tx_cnt; + model->rx_cnt = st->rx_cnt; + model->protocol = st->protocol; + }, + true); +} diff --git a/views/seader_uart_view.h b/views/seader_uart_view.h new file mode 100644 index 0000000..f6f87ad --- /dev/null +++ b/views/seader_uart_view.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "../seader_custom_event.h" +#include "../seader_bridge.h" + +typedef struct SeaderUartView SeaderUartView; +typedef void (*SeaderUartViewCallback)(SeaderCustomEvent event, void* context); + +SeaderUartView* seader_uart_view_alloc(); + +void seader_uart_view_free(SeaderUartView* seader_uart_view); + +View* seader_uart_view_get_view(SeaderUartView* seader_uart_view); + +void seader_uart_view_set_callback( + SeaderUartView* seader_uart_view, + SeaderUartViewCallback callback, + void* context); + +void seader_uart_view_update_state( + SeaderUartView* instance, + SeaderUartConfig* cfg, + SeaderUartState* st);