Kaynağa Gözat

MagSpoof read PoC

Mattar B 2 yıl önce
ebeveyn
işleme
be79a9e8c5

+ 3 - 3
application.fam

@@ -1,6 +1,6 @@
 App(
     appid="mag",
-    name="MagSpoof WIP",
+    name="MagSpoof",
     apptype=FlipperAppType.EXTERNAL,
     entry_point="mag_app",
     cdefines=["APP_MAG"],
@@ -11,10 +11,10 @@ App(
         "dialogs",
     ],
     provides=[],
-    stack_size=5 * 1024,
+    stack_size=6 * 1024,
     order=64,  # keep it at the bottom of the list while still WIP
     fap_icon="icons/mag_10px.png",
-    fap_category="Tools",
+    fap_category="GPIO",
     fap_icon_assets="icons",
     fap_version=(0, 5),  # major, minor
     fap_description="WIP MagSpoof port using the RFID subsystem",

+ 8 - 5
helpers/mag_helpers.c

@@ -2,8 +2,9 @@
 
 #define TAG "MagHelpers"
 
-#define GPIO_PIN_A &gpio_ext_pa6
-#define GPIO_PIN_B &gpio_ext_pa7
+// Haviv Board - pins gpio_ext_pa7 & gpio_ext_pa6 was swapped.
+#define GPIO_PIN_A &gpio_ext_pa7
+#define GPIO_PIN_B &gpio_ext_pa6
 #define GPIO_PIN_ENABLE &gpio_ext_pa4
 #define RFID_PIN_OUT &gpio_rfid_carrier_out
 
@@ -126,10 +127,12 @@ void tx_init_rfid() {
     // initialize RFID system for TX
 
     // OTG needed for RFID? Or just legacy from GPIO?
-    furi_hal_power_enable_otg();
+    // furi_hal_power_enable_otg();
+    furi_hal_ibutton_pin_configure();
+
+    // furi_hal_ibutton_start_drive();
+    furi_hal_ibutton_pin_write(false);
 
-    furi_hal_ibutton_start_drive();
-    furi_hal_ibutton_pin_low();
 
     // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
 

+ 7 - 0
helpers/mag_types.h

@@ -36,3 +36,10 @@ typedef enum {
     MagTxCC1101_434,
     MagTxCC1101_868,
 } MagTxState;
+
+
+typedef enum {
+    UART_TerminalEventRefreshConsoleOutput = 0,
+    UART_TerminalEventStartConsole,
+    UART_TerminalEventStartKeyboard,
+} UART_TerminalCustomEvent;

+ 71 - 0
mag_device.c

@@ -230,6 +230,77 @@ bool mag_device_delete(MagDevice* mag_dev, bool use_load_path) {
     return deleted;
 }
 
+bool mag_device_parse_card_string(MagDevice* mag_dev, FuriString* f_card_str) {
+    furi_assert(mag_dev);
+    FURI_LOG_D(TAG, "mag_device_parse_card_string");
+
+    const char* card_str = furi_string_get_cstr(f_card_str);
+
+    FURI_LOG_D(TAG, "Parsing card string: %s", card_str);
+
+    // Track 1
+    const char* track1_start = strchr(card_str, '%');
+    if(!track1_start) {
+        FURI_LOG_D(TAG, "Could not find track 1 start");
+        return false;
+    }
+    track1_start++;
+    const char* track1_end = strchr(track1_start, '?');
+    if(!track1_end) {
+        FURI_LOG_D(TAG, "Could not find track 1 end");
+        return false;
+    }
+    size_t track1_len = track1_end - track1_start;
+    
+    FURI_LOG_D(TAG, "Track 1: %.*s", track1_len, track1_start);
+
+    mag_dev->dev_data.track[0].len = track1_len;
+    furi_string_printf(mag_dev->dev_data.track[0].str, "%%%.*s?", track1_len, track1_start);
+
+    // Track 2
+    const char* track2_start = strchr(track1_end, ';');
+    if (!track2_start) {
+        FURI_LOG_D(TAG, "Could not find track 2 start");
+        return true;
+    }
+
+    track2_start++;
+    const char* track2_end = strchr(track2_start, '?');
+    if(!track2_end) {
+        FURI_LOG_D(TAG, "Could not find track 2 end");
+        return true;
+    }
+    size_t track2_len = track2_end - track2_start;
+
+    FURI_LOG_D(TAG, "Track 2: %.*s", track2_len, track2_start);
+
+    mag_dev->dev_data.track[1].len = track2_len;
+    furi_string_printf(mag_dev->dev_data.track[1].str, "%%%.*s?", track2_len, track2_start);
+
+    // Track 3
+    const char* track3_start = strchr(track2_end, ';');
+    if (!track3_start) {
+        FURI_LOG_D(TAG, "Could not find track 3 start");
+        return true;
+    }
+
+    track3_start++;
+    const char* track3_end = strchr(track3_start, '?');
+    if(!track3_end) {
+        FURI_LOG_D(TAG, "Could not find track 3 end");
+        return true;
+    }
+    size_t track3_len = track3_end - track3_start;
+
+    FURI_LOG_D(TAG, "Track 3: %.*s", track3_len, track3_start);
+
+    mag_dev->dev_data.track[2].len = track3_len;
+    furi_string_printf(mag_dev->dev_data.track[2].str, "%%%.*s?", track3_len, track3_start);
+    
+    return true;
+}
+
+
 void mag_device_set_loading_callback(
     MagDevice* mag_dev,
     MagLoadingCallback callback,

+ 3 - 0
mag_device.h

@@ -17,6 +17,7 @@ typedef void (*MagLoadingCallback)(void* context, bool state);
 
 typedef struct {
     FuriString* str;
+    size_t len;
 } MagTrack;
 
 typedef struct {
@@ -49,6 +50,8 @@ void mag_device_clear(MagDevice* mag_dev);
 
 bool mag_device_delete(MagDevice* mag_dev, bool use_load_path);
 
+bool mag_device_parse_card_string(MagDevice* mag_dev, FuriString* card_str);
+
 void mag_device_set_loading_callback(
     MagDevice* mag_dev,
     MagLoadingCallback callback,

+ 13 - 0
mag_i.h

@@ -33,6 +33,7 @@
 #include <toolbox/value_index.h>
 
 #include "scenes/mag_scene.h"
+#include "scenes/mag_scene_read.h"
 
 #define MAG_TEXT_STORE_SIZE 150
 
@@ -50,6 +51,7 @@ typedef struct {
     uint32_t us_interpacket;
 } MagSetting;
 
+
 typedef struct {
     ViewDispatcher* view_dispatcher;
     Gui* gui;
@@ -76,6 +78,17 @@ typedef struct {
 
     // Custom views
     Mag_TextInput* mag_text_input;
+
+    // UART
+    FuriThread* uart_rx_thread;
+    FuriStreamBuffer* uart_rx_stream;
+    uint8_t uart_rx_buf[UART_RX_BUF_SIZE + 1];
+    void (*handle_rx_data_cb)(uint8_t* buf, size_t len, void* context);
+    
+    char uart_text_input_store[UART_TERMINAL_TEXT_INPUT_STORE_SIZE + 1];
+    FuriString* uart_text_box_store;
+    size_t uart_text_box_store_strlen;
+    // UART_TextInput* text_input;
 } Mag;
 
 void mag_text_store_set(Mag* mag, const char* text, ...);

+ 1 - 0
scenes/mag_scene_config.h

@@ -12,3 +12,4 @@ ADD_SCENE(mag, delete_success, DeleteSuccess)
 ADD_SCENE(mag, delete_confirm, DeleteConfirm)
 ADD_SCENE(mag, exit_confirm, ExitConfirm)
 ADD_SCENE(mag, under_construction, UnderConstruction)
+ADD_SCENE(mag, read, Read)

+ 178 - 0
scenes/mag_scene_read.c

@@ -0,0 +1,178 @@
+// Creator: Hummus@FlipperGang
+
+#include "../mag_i.h"
+#include "../helpers/mag_helpers.h"
+
+#include "mag_scene_read.h"
+
+#define TAG "MagSceneRead"
+
+void uart_callback(UartIrqEvent event, uint8_t data, void *context) {
+    Mag* mag = context;
+    if(event == UartIrqEventRXNE) {
+        furi_stream_buffer_send(mag->uart_rx_stream, &data, 1, 0);
+        furi_thread_flags_set(furi_thread_get_id(mag->uart_rx_thread), WorkerEvtRxDone);
+    }
+}
+
+static int32_t uart_worker(void* context) {
+    Mag* mag = context;
+    mag->uart_rx_stream = furi_stream_buffer_alloc(UART_RX_BUF_SIZE, 1);
+    mag->uart_text_box_store_strlen = 0;
+
+    while (1) {
+        uint32_t events = furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
+        // furi_check((events & FuriFlagError) == 0);
+        
+        if(events & WorkerEvtStop) break;
+        if(events & WorkerEvtRxDone) {
+            FURI_LOG_D(TAG, "WorkerEvtRxDone");
+            // notification_message(mag->notifications, &sequence_success);
+            size_t len = furi_stream_buffer_receive(mag->uart_rx_stream, mag->uart_rx_buf, UART_RX_BUF_SIZE, 200);
+            FURI_LOG_D(TAG, "UART RX len: %d", len);
+            
+            if (len > 0) {
+                // If text box store gets too big, then truncate it
+                mag->uart_text_box_store_strlen += len;
+
+                if(mag->uart_text_box_store_strlen >= UART_TERMINAL_TEXT_BOX_STORE_SIZE - 1) {
+                    furi_string_right(mag->uart_text_box_store, mag->uart_text_box_store_strlen / 2);
+                    mag->uart_text_box_store_strlen = furi_string_size(mag->uart_text_box_store) + len;
+                }
+
+                // Add '\0' to the end of the string, and then add the new data
+                mag->uart_rx_buf[len] = '\0';
+                furi_string_cat_printf(mag->uart_text_box_store, "%s", mag->uart_rx_buf);
+
+                FURI_LOG_D(TAG, "UART RX buf: %*.s", len, mag->uart_rx_buf);
+                FURI_LOG_D(TAG, "UART RX store: %s", furi_string_get_cstr(mag->uart_text_box_store));
+
+            }
+
+            FURI_LOG_D(TAG, "UARTEventRxData");
+            
+            view_dispatcher_send_custom_event(
+                mag->view_dispatcher, UARTEventRxData);
+            
+        }
+    }
+    
+    furi_stream_buffer_free(mag->uart_rx_stream);
+
+    return 0;
+}
+
+void update_widgets(Mag* mag) {
+    // Clear widget from all elements
+    widget_reset(mag->widget);
+
+    // Titlebar
+    widget_add_icon_element(mag->widget, 38, -1, &I_mag_file_10px);
+    widget_add_string_element(mag->widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "READ");
+    widget_add_icon_element(mag->widget, 81, -1, &I_mag_file_10px);
+
+    // Text box
+    widget_add_text_scroll_element(mag->widget, 0, 10, 128, 40, furi_string_get_cstr(mag->uart_text_box_store));
+
+    // Buttons
+    widget_add_button_element(mag->widget, GuiButtonTypeLeft, "Clear", mag_widget_callback, mag);
+    widget_add_button_element(mag->widget, GuiButtonTypeRight, "Parse", mag_widget_callback, mag);
+}
+
+void mag_scene_read_on_enter(void* context) {
+    Mag* mag = context;
+    FuriString* message = furi_string_alloc();
+    furi_string_printf(message, "Flipper Elite, swipe a card!\n");
+    mag->uart_text_box_store = message;
+
+    view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
+    
+    update_widgets(mag);
+    
+    
+    // Initialize UART
+    // furi_hal_console_disable();
+    furi_hal_uart_deinit(FuriHalUartIdUSART1);
+    furi_hal_uart_init(FuriHalUartIdUSART1, 9600);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_callback, mag);
+    FURI_LOG_D(TAG, "UART initialized");
+
+    mag->uart_rx_thread = furi_thread_alloc();
+    furi_thread_set_name(mag->uart_rx_thread, "UartRx");
+    furi_thread_set_stack_size(mag->uart_rx_thread, 1024);
+    furi_thread_set_context(mag->uart_rx_thread, mag);
+    furi_thread_set_callback(mag->uart_rx_thread, uart_worker);
+
+    furi_thread_start(mag->uart_rx_thread);
+    FURI_LOG_D(TAG, "UART worker started");
+}
+
+bool mag_scene_read_on_event(void* context, SceneManagerEvent event) {
+    Mag* mag = context;
+    
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        FURI_LOG_D(TAG, "Custom event: %ld", event.event);
+
+        switch(event.event) {
+        case GuiButtonTypeLeft: // Clear
+            consumed = true;
+            // Clear text box store
+            furi_string_reset(mag->uart_text_box_store);
+            mag->uart_text_box_store_strlen = 0;
+            break;
+
+        case GuiButtonTypeRight: // Parse
+            consumed = true;
+            FURI_LOG_D(TAG, "Trying to parse");
+            MagDevice* mag_dev = mag->mag_dev;
+
+            bool res = mag_device_parse_card_string(mag_dev, mag->uart_text_box_store);
+            furi_string_reset(mag->uart_text_box_store);
+            if(res) {
+                notification_message(mag->notifications, &sequence_success);
+                
+                furi_string_printf(mag->uart_text_box_store, "Track 1: %.*s\nTrack 2: %.*s\nTrack 3: %.*s",
+                    mag_dev->dev_data.track[0].len, furi_string_get_cstr(mag_dev->dev_data.track[0].str),
+                    mag_dev->dev_data.track[1].len, furi_string_get_cstr(mag_dev->dev_data.track[1].str),
+                    mag_dev->dev_data.track[2].len, furi_string_get_cstr(mag_dev->dev_data.track[2].str));
+
+                // Switch to saved menu scene
+                scene_manager_next_scene(mag->scene_manager, MagSceneSavedMenu);
+
+            } else {
+                furi_string_printf(mag->uart_text_box_store, "Failed to parse! Try again\n");
+                notification_message(mag->notifications, &sequence_error);
+            }
+
+            break;
+        }
+
+        update_widgets(mag);
+    }
+
+    return consumed;
+}
+
+void mag_scene_read_on_exit(void* context) {
+    Mag* mag = context;
+    // notification_message(mag->notifications, &sequence_blink_stop);
+    widget_reset(mag->widget);
+    // view_dispatcher_remove_view(mag->view_dispatcher, MagViewWidget);
+    
+    // Stop UART worker
+    FURI_LOG_D(TAG, "Stopping UART worker");
+    furi_thread_flags_set(furi_thread_get_id(mag->uart_rx_thread), WorkerEvtStop);
+    furi_thread_join(mag->uart_rx_thread);
+    furi_thread_free(mag->uart_rx_thread);
+    FURI_LOG_D(TAG, "UART worker stopped");
+
+    furi_string_free(mag->uart_text_box_store);
+
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
+    furi_hal_uart_deinit(FuriHalUartIdUSART1);
+    // furi_hal_console_enable();
+    
+    notification_message(mag->notifications, &sequence_blink_stop);
+}

+ 21 - 0
scenes/mag_scene_read.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include <gui/modules/text_box.h>
+
+#define UART_RX_BUF_SIZE (320)
+#define UART_TERMINAL_TEXT_BOX_STORE_SIZE (4096)
+#define UART_TERMINAL_TEXT_INPUT_STORE_SIZE (512)
+#define UART_CH (FuriHalUartIdUSART1)
+#define UART_BAUDRATE (9600)
+
+typedef enum {
+    WorkerEvtStop = (1 << 0),
+    WorkerEvtRxDone = (1 << 1),
+} WorkerEvtFlags;
+
+typedef enum {
+    UARTEventRxData = 100,
+} UARTEvents;
+
+
+#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxDone)

+ 2 - 0
scenes/mag_scene_saved_menu.c

@@ -17,6 +17,8 @@ void mag_scene_saved_menu_on_enter(void* context) {
     Mag* mag = context;
     Submenu* submenu = mag->submenu;
 
+    notification_message(mag->notifications, &sequence_blink_cyan_10);
+
     // messy code to quickly check which tracks are available for emulation/display
     // there's likely a better spot to do this, but the MagDevice functions don't have access to the full mag struct...
     bool is_empty_t1 = furi_string_empty(mag->mag_dev->dev_data.track[0].str);

+ 7 - 0
scenes/mag_scene_start.c

@@ -2,6 +2,7 @@
 
 typedef enum {
     SubmenuIndexSaved,
+    SubmenuIndexRead,
     //SubmenuIndexAddManually,
     SubmenuIndexAbout,
 } SubmenuIndex;
@@ -17,6 +18,7 @@ void mag_scene_start_on_enter(void* context) {
     Submenu* submenu = mag->submenu;
 
     submenu_add_item(submenu, "Saved", SubmenuIndexSaved, mag_scene_start_submenu_callback, mag);
+    submenu_add_item(submenu, "Read", SubmenuIndexRead, mag_scene_start_submenu_callback, mag);
     //submenu_add_item(
     //    submenu, "Add Manually", SubmenuIndexAddManually, mag_scene_start_submenu_callback, mag);
     submenu_add_item(submenu, "About", SubmenuIndexAbout, mag_scene_start_submenu_callback, mag);
@@ -41,6 +43,11 @@ bool mag_scene_start_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(mag->scene_manager, MagSceneFileSelect);
             consumed = true;
             break;
+
+        case SubmenuIndexRead:
+            scene_manager_next_scene(mag->scene_manager, MagSceneRead);
+            consumed = true;
+            break;
         //case SubmenuIndexAddManually:
         //    scene_manager_next_scene(mag->scene_manager, MagSceneInputValue);
         //    consumed = true;