MX 2 سال پیش
والد
کامیت
349a47db26

+ 1 - 0
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",

+ 2 - 0
ccid.c

@@ -135,6 +135,8 @@ size_t processCCID(SeaderWorker* seader_worker, uint8_t* cmd, size_t cmd_len) {
             switch(cmd[1]) {
             case CARD_OUT:
                 FURI_LOG_D(TAG, "Card removed");
+                powered = false;
+                hasSAM = false;
                 retries = 3;
                 break;
             case CARD_IN_1:

BIN
icons/ArrowUpEmpty_14x15.png


BIN
icons/ArrowUpFilled_14x15.png


+ 1 - 1
scenes/seader_scene_card_menu.c

@@ -34,7 +34,7 @@ void seader_scene_card_menu_on_enter(void* context) {
         seader_scene_card_menu_submenu_callback,
         seader);
     if(seader->is_debug_enabled) {
-        if(credential->sio[0] != 0) {
+        if(credential->sio[0] == 0x30) {
             submenu_add_item(
                 submenu,
                 "Save SR",

+ 1 - 0
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)

+ 13 - 2
scenes/seader_scene_credential_info.c

@@ -21,6 +21,7 @@ void seader_scene_credential_info_on_enter(void* context) {
     FuriString* type_str = furi_string_alloc();
     FuriString* bitlength_str = furi_string_alloc();
     FuriString* credential_str = furi_string_alloc();
+    FuriString* sio_str = furi_string_alloc();
 
     dolphin_deed(DolphinDeedNfcReadSuccess);
 
@@ -29,11 +30,14 @@ void seader_scene_credential_info_on_enter(void* context) {
 
     furi_string_set(credential_str, "");
     furi_string_set(bitlength_str, "");
+    furi_string_set(sio_str, "");
     if(credential->bit_length > 0) {
         furi_string_cat_printf(bitlength_str, "%d bit", credential->bit_length);
         furi_string_cat_printf(credential_str, "0x%llX", credential->credential);
 
-        if(credential->type == SeaderCredentialType14A) {
+        if(credential->type == SeaderCredentialTypeNone) {
+            furi_string_set(type_str, "None");
+        } else if(credential->type == SeaderCredentialType14A) {
             furi_string_set(type_str, "14443A");
         } else if(credential->type == SeaderCredentialTypePicopass) {
             furi_string_set(type_str, "Picopass");
@@ -68,9 +72,16 @@ void seader_scene_credential_info_on_enter(void* context) {
         FontSecondary,
         furi_string_get_cstr(credential_str));
 
+    if(credential->sio[0] == 0x30) {
+        furi_string_set(sio_str, "+SIO");
+        widget_add_string_element(
+            widget, 64, 48, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(sio_str));
+    }
+
     furi_string_free(bitlength_str);
-    furi_string_free(credential_str);
     furi_string_free(type_str);
+    furi_string_free(credential_str);
+    furi_string_free(sio_str);
 
     view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewWidget);
 }

+ 11 - 1
scenes/seader_scene_read_card_success.c

@@ -21,6 +21,7 @@ void seader_scene_read_card_success_on_enter(void* context) {
     FuriString* type_str = furi_string_alloc();
     FuriString* bitlength_str = furi_string_alloc();
     FuriString* credential_str = furi_string_alloc();
+    FuriString* sio_str = furi_string_alloc();
 
     dolphin_deed(DolphinDeedNfcReadSuccess);
 
@@ -29,11 +30,14 @@ void seader_scene_read_card_success_on_enter(void* context) {
 
     furi_string_set(credential_str, "");
     furi_string_set(bitlength_str, "");
+    furi_string_set(sio_str, "");
     if(credential->bit_length > 0) {
         furi_string_cat_printf(bitlength_str, "%d bit", credential->bit_length);
         furi_string_cat_printf(credential_str, "0x%llX", credential->credential);
 
-        if(credential->type == SeaderCredentialType14A) {
+        if(credential->type == SeaderCredentialTypeNone) {
+            furi_string_set(type_str, "None");
+        } else if(credential->type == SeaderCredentialType14A) {
             furi_string_set(type_str, "14443A");
         } else if(credential->type == SeaderCredentialTypePicopass) {
             furi_string_set(type_str, "Picopass");
@@ -68,10 +72,16 @@ void seader_scene_read_card_success_on_enter(void* context) {
         AlignCenter,
         FontSecondary,
         furi_string_get_cstr(credential_str));
+    if(credential->sio[0] == 0x30) {
+        furi_string_set(sio_str, "+SIO");
+        widget_add_string_element(
+            widget, 64, 48, AlignCenter, AlignCenter, FontSecondary, furi_string_get_cstr(sio_str));
+    }
 
     furi_string_free(credential_str);
     furi_string_free(bitlength_str);
     furi_string_free(type_str);
+    furi_string_free(sio_str);
 
     view_dispatcher_switch_to_view(seader->view_dispatcher, SeaderViewWidget);
 }

+ 3 - 0
scenes/seader_scene_sam_missing.c

@@ -40,6 +40,9 @@ bool seader_scene_sam_missing_on_event(void* context, SceneManagerEvent event) {
         } else if(event.event == SubmenuIndexSaved) {
             scene_manager_next_scene(seader->scene_manager, SeaderSceneFileSelect);
             consumed = true;
+        } else if(event.event == SeaderWorkerEventSamPresent) {
+            scene_manager_next_scene(seader->scene_manager, SeaderSceneSamPresent);
+            consumed = true;
         }
     } else if(event.type == SceneManagerEventTypeBack) {
         scene_manager_stop(seader->scene_manager);

+ 20 - 6
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(

+ 101 - 0
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);
+}

+ 9 - 0
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);

+ 1 - 1
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 {

+ 4 - 0
seader_credential.c

@@ -54,6 +54,7 @@ static bool seader_credential_load(SeaderCredential* cred, FuriString* path, boo
     FuriString* temp_str;
     temp_str = furi_string_alloc();
     bool deprecated_version = false;
+    cred->type = SeaderCredentialTypeNone;
 
     if(cred->loading_cb) {
         cred->loading_cb(cred->loading_cb_ctx, true);
@@ -367,9 +368,12 @@ bool seader_file_select(SeaderCredential* cred) {
 
 void seader_credential_clear(SeaderCredential* cred) {
     furi_assert(cred);
+    memset(cred->name, 0, sizeof(cred->name));
     cred->credential = 0;
     cred->bit_length = 0;
     cred->type = SeaderCredentialTypeNone;
+    memset(cred->sio, 0, sizeof(cred->sio));
+    memset(cred->diversifier, 0, sizeof(cred->diversifier));
     furi_string_reset(cred->load_path);
 }
 

+ 5 - 0
seader_custom_event.h

@@ -0,0 +1,5 @@
+#pragma once
+
+typedef enum {
+    SeaderStartEventNone = 0,
+} SeaderCustomEvent;

+ 5 - 0
seader_i.h

@@ -33,6 +33,7 @@
 #include <FrameProtocol.h>
 
 #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, ...);

+ 9 - 4
seader_worker.c

@@ -378,10 +378,13 @@ bool unpack_pacs(
             FURI_LOG_D(TAG, "Received pac: %s", pacDebug);
 
             memset(display, 0, sizeof(display));
-            for(uint8_t i = 0; i < sizeof(seader_credential->sio); i++) {
-                snprintf(display + (i * 2), sizeof(display), "%02x", seader_credential->sio[i]);
+            if(seader_credential->sio[0] == 0x30) {
+                for(uint8_t i = 0; i < sizeof(seader_credential->sio); i++) {
+                    snprintf(
+                        display + (i * 2), sizeof(display), "%02x", seader_credential->sio[i]);
+                }
+                FURI_LOG_D(TAG, "SIO %s", display);
             }
-            FURI_LOG_D(TAG, "SIO %s", display);
         }
 
         if(pac->size <= sizeof(seader_credential->credential)) {
@@ -565,7 +568,7 @@ bool iso15693Transmit(SeaderWorker* seader_worker, uint8_t* buffer, size_t len)
             snprintf(display + (i * 2), sizeof(display), "%02x", rxBuffer[i]);
         }
         // FURI_LOG_D(TAG, "Result %d %s", recvLen, display);
-        if(memcmp(buffer, readBlock6, len) == 0) {
+        if(memcmp(buffer, readBlock6, len) == 0 && rxBuffer[0] == 0x30) {
             memcpy(credential->sio, rxBuffer, 32);
         } else if(memcmp(buffer, readBlock9, len) == 0) {
             memcpy(credential->sio + 32, rxBuffer + 8, 24);
@@ -871,6 +874,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 +884,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

+ 0 - 1
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");
     }

+ 152 - 0
views/seader_uart_view.c

@@ -0,0 +1,152 @@
+#include "../seader_bridge.h"
+#include "../seader_i.h"
+#include <furi_hal.h>
+#include <gui/elements.h>
+
+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);
+}

+ 24 - 0
views/seader_uart_view.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include <gui/view.h>
+#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);