frux-c 2 лет назад
Родитель
Сommit
efc271f400
13 измененных файлов с 630 добавлено и 118 удалено
  1. 23 0
      scenes/uhf_scene_file_select.c
  2. 11 10
      scenes/uhf_scene_save_name.c
  3. 64 0
      scenes/uhf_scene_saved_menu.c
  4. 1 1
      scenes/uhf_scene_start.c
  5. 8 0
      scenes/uhf_scene_verify.c
  6. 8 71
      uhf_app.c
  7. 11 11
      uhf_app_i.h
  8. 17 0
      uhf_data.c
  9. 2 0
      uhf_data.h
  10. 353 0
      uhf_device.c
  11. 103 0
      uhf_device.h
  12. 28 22
      uhf_worker.c
  13. 1 3
      uhf_worker.h

+ 23 - 0
scenes/uhf_scene_file_select.c

@@ -0,0 +1,23 @@
+// #include "../uhf_app_i.h"
+
+// void uhf_scene_file_select_on_enter(void* context) {
+//     UHFApp* uhf_app = context;
+//     // Process file_select return
+//     uhf_device_set_loading_callback(uhf_app->dev, uhf_app_show_loading_popup, uhf_app);
+//     if(uhf_file_select(uhf_app->dev)) {
+//         scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSavedMenu);
+//     } else {
+//         scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
+//     }
+//     uhf_device_set_loading_callback(uhf_app->dev, NULL, uhf_app);
+// }
+
+// bool uhf_scene_file_select_on_event(void* context, SceneManagerEvent event) {
+//     UNUSED(context);
+//     UNUSED(event);
+//     return false;
+// }
+
+// void uhf_scene_file_select_on_exit(void* context) {
+//     UNUSED(context);
+// }

+ 11 - 10
scenes/uhf_scene_save_name.c

@@ -3,9 +3,6 @@
 #include <gui/modules/validators.h>
 #include <gui/modules/validators.h>
 #include <toolbox/path.h>
 #include <toolbox/path.h>
 
 
-#define UHF_DEV_NAME_MAX_LEN 22
-#define UHF_APP_EXTENSION ".uhf"
-
 void uhf_scene_save_name_text_input_callback(void* context) {
 void uhf_scene_save_name_text_input_callback(void* context) {
     UHFApp* uhf_app = context;
     UHFApp* uhf_app = context;
 
 
@@ -30,12 +27,12 @@ void uhf_scene_save_name_on_enter(void* context) {
     FuriString* folder_path;
     FuriString* folder_path;
     folder_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
     folder_path = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
 
 
-    // if(furi_string_end_with(uhf_app->dev->load_path, UHF_APP_EXTENSION)) {
-    //     path_extract_dirname(furi_string_get_cstr(uhf_app->dev->load_path), folder_path);
-    // }
+    if(furi_string_end_with(uhf_app->uhf_device->load_path, UHF_APP_EXTENSION)) {
+        path_extract_dirname(furi_string_get_cstr(uhf_app->uhf_device->load_path), folder_path);
+    }
 
 
-    ValidatorIsFile* validator_is_file =
-        validator_is_file_alloc_init(furi_string_get_cstr(folder_path), UHF_APP_EXTENSION, "test");
+    ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
+        furi_string_get_cstr(folder_path), UHF_APP_EXTENSION, uhf_app->uhf_device->dev_name);
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
 
 
     view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewTextInput);
     view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewTextInput);
@@ -45,11 +42,15 @@ void uhf_scene_save_name_on_enter(void* context) {
 
 
 bool uhf_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 bool uhf_scene_save_name_on_event(void* context, SceneManagerEvent event) {
     UHFApp* uhf_app = context;
     UHFApp* uhf_app = context;
-    UHFResponseData* uhf_data_save = uhf_app->worker->response_data;
     bool consumed = false;
     bool consumed = false;
+
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == UHFCustomEventTextInputDone) {
         if(event.event == UHFCustomEventTextInputDone) {
-            if(uhf_save_read_data(uhf_data_save, uhf_app->storage, uhf_app->text_store)) {
+            strlcpy(
+                uhf_app->uhf_device->dev_name,
+                uhf_app->text_store,
+                strlen(uhf_app->text_store) + 1);
+            if(uhf_device_save(uhf_app->uhf_device, uhf_app->text_store)) {
                 scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveSuccess);
                 scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveSuccess);
                 consumed = true;
                 consumed = true;
             } else {
             } else {

+ 64 - 0
scenes/uhf_scene_saved_menu.c

@@ -0,0 +1,64 @@
+// #include "../uhf_app_i.h"
+
+// #include "../uhf_app_i.h"
+
+// enum SubmenuIndex {
+//     SubmenuIndexSave,
+//     SubmenuIndexChangeKey,
+// };
+
+// void uhf_scene_card_menu_submenu_callback(void* ctx, uint32_t index) {
+//     UHFApp* uhf_app = ctx;
+//     view_dispatcher_send_custom_event(uhf_app->view_dispatcher, index);
+// }
+
+// void uhf_scene_card_menu_on_enter(void* ctx) {
+//     UHFApp* uhf_app = ctx;
+
+//     Submenu* submenu = uhf_app->submenu;
+
+//     submenu_add_item(
+//         submenu, "Save", SubmenuIndexSave, uhf_scene_card_menu_submenu_callback, uhf_app);
+//     submenu_add_item(
+//         submenu,
+//         "Change Key",
+//         SubmenuIndexChangeKey,
+//         uhf_scene_card_menu_submenu_callback,
+//         uhf_app);
+
+//     submenu_set_selected_item(
+//         submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneCardMenu));
+
+//     view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
+// }
+
+// bool uhf_scene_card_menu_on_event(void* ctx, SceneManagerEvent event) {
+//     UHFApp* uhf_app = ctx;
+//     bool consumed = false;
+
+//     if(event.type == SceneManagerEventTypeCustom) {
+//         if(event.event == SubmenuIndexSave) {
+//             scene_manager_set_scene_state(
+//                 uhf_app->scene_manager, UHFSceneCardMenu, SubmenuIndexSave);
+//             scene_manager_next_scene(uhf_app->scene_manager, UHFSceneSaveName);
+//             consumed = true;
+//         }
+//         // else if(event.event == SubmenuIndexChangeKey) {
+//         //     scene_manager_set_scene_state(
+//         //         picopass->scene_manager, UHFSceneCardMenu, SubmenuIndexChangeKey);
+//         //     scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu);
+//         //     consumed = true;
+//         // }
+//     } else if(event.type == SceneManagerEventTypeBack) {
+//         consumed = scene_manager_search_and_switch_to_previous_scene(
+//             uhf_app->scene_manager, UHFSceneStart);
+//     }
+
+//     return consumed;
+// }
+
+// void uhf_scene_card_menu_on_exit(void* ctx) {
+//     UHFApp* uhf_app = ctx;
+
+//     submenu_reset(uhf_app->submenu);
+// }

+ 1 - 1
scenes/uhf_scene_start.c

@@ -32,7 +32,7 @@ bool uhf_scene_start_on_event(void* ctx, SceneManagerEvent event) {
             scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTag);
             scene_manager_next_scene(uhf_app->scene_manager, UHFSceneReadTag);
             consumed = true;
             consumed = true;
         }
         }
-        //else if(event.event == SubmenuIndexSaved) {
+        // else if(event.event == SubmenuIndexSaved) {
         // Explicitly save state so that the correct item is
         // Explicitly save state so that the correct item is
         // reselected if the user cancels loading a file.
         // reselected if the user cancels loading a file.
         // scene_manager_set_scene_state(
         // scene_manager_set_scene_state(

+ 8 - 0
scenes/uhf_scene_verify.c

@@ -116,6 +116,14 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                     AlignCenter,
                     AlignCenter,
                     FontPrimary,
                     FontPrimary,
                     "No UHF Module found");
                     "No UHF Module found");
+                widget_add_string_multiline_element(
+                    uhf_app->widget,
+                    64,
+                    30,
+                    AlignCenter,
+                    AlignCenter,
+                    FontSecondary,
+                    "Please connect your module.\nPlease refer to the frux-c/uhf_rfid for help.");
                 widget_add_button_element(
                 widget_add_button_element(
                     uhf_app->widget,
                     uhf_app->widget,
                     GuiButtonTypeLeft,
                     GuiButtonTypeLeft,

+ 8 - 71
uhf_app.c

@@ -1,10 +1,5 @@
 #include "uhf_app_i.h"
 #include "uhf_app_i.h"
 
 
-static const char* uhf_file_header = "Flipper UHF device";
-static const uint32_t uhf_file_version = 1;
-static const uint8_t bank_data_start = 20;
-static const uint8_t bank_data_length = 16;
-
 // empty callback
 // empty callback
 void empty_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
 void empty_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
     UNUSED(event);
     UNUSED(event);
@@ -35,66 +30,6 @@ char* convertToHexString(const uint8_t* array, size_t length) {
     return hexArray;
     return hexArray;
 }
 }
 
 
-bool uhf_save_read_data(UHFResponseData* uhf_response_data, Storage* storage, const char* filename) {
-    if(!storage_dir_exists(storage, UHF_APPS_DATA_FOLDER)) {
-        storage_simply_mkdir(storage, UHF_APPS_DATA_FOLDER);
-    }
-    if(!storage_dir_exists(storage, UHF_APPS_STORAGE_FOLDER)) {
-        storage_simply_mkdir(storage, UHF_APPS_STORAGE_FOLDER);
-    }
-
-    FlipperFormat* file = flipper_format_file_alloc(storage);
-    FuriString* temp_str = furi_string_alloc();
-    // set file name
-    furi_string_cat_printf(
-        temp_str, "%s/%s%s", UHF_APPS_STORAGE_FOLDER, filename, UHF_FILE_EXTENSION);
-    // open file
-    if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) return false;
-    // write header
-    if(!flipper_format_write_header_cstr(file, uhf_file_header, uhf_file_version)) return false;
-    // write rfu data to file
-    UHFData* rfu_data = uhf_response_data_get_uhf_data(uhf_response_data, 1);
-    if(rfu_data->length) {
-        if(!flipper_format_write_hex(
-               file, "RFU", rfu_data->data + bank_data_start, bank_data_length))
-            return false;
-    } else {
-        if(!flipper_format_write_hex(file, "RFU", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
-    }
-
-    // write epc data to file
-    UHFData* epc_data = uhf_response_data_get_uhf_data(uhf_response_data, 2);
-    if(epc_data->length) {
-        if(!flipper_format_write_hex(
-               file, "EPC", epc_data->data + bank_data_start, bank_data_length))
-            return false;
-    } else {
-        if(!flipper_format_write_hex(file, "EPC", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
-    }
-
-    // write tid data to file
-    UHFData* tid_data = uhf_response_data_get_uhf_data(uhf_response_data, 3);
-    if(tid_data->length) {
-        if(!flipper_format_write_hex(
-               file, "TID", tid_data->data + bank_data_start, bank_data_length))
-            return false;
-    } else {
-        if(!flipper_format_write_hex(file, "TID", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
-    }
-    // write user data to file
-    UHFData* user_data = uhf_response_data_get_uhf_data(uhf_response_data, 4);
-    if(user_data->length) {
-        if(!flipper_format_write_hex(
-               file, "USER", user_data->data + bank_data_start, bank_data_length))
-            return false;
-    } else {
-        if(!flipper_format_write_hex(file, "USER", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
-    }
-    furi_string_free(temp_str);
-    flipper_format_free(file);
-    return true;
-}
-
 bool uhf_custom_event_callback(void* ctx, uint32_t event) {
 bool uhf_custom_event_callback(void* ctx, uint32_t event) {
     furi_assert(ctx);
     furi_assert(ctx);
     UHFApp* uhf_app = ctx;
     UHFApp* uhf_app = ctx;
@@ -115,7 +50,6 @@ void uhf_tick_event_callback(void* ctx) {
 
 
 UHFApp* uhf_alloc() {
 UHFApp* uhf_alloc() {
     UHFApp* uhf_app = (UHFApp*)malloc(sizeof(UHFApp));
     UHFApp* uhf_app = (UHFApp*)malloc(sizeof(UHFApp));
-    uhf_app->worker = (UHFWorker*)uhf_worker_alloc();
     uhf_app->view_dispatcher = view_dispatcher_alloc();
     uhf_app->view_dispatcher = view_dispatcher_alloc();
     uhf_app->scene_manager = scene_manager_alloc(&uhf_scene_handlers, uhf_app);
     uhf_app->scene_manager = scene_manager_alloc(&uhf_scene_handlers, uhf_app);
     view_dispatcher_enable_queue(uhf_app->view_dispatcher);
     view_dispatcher_enable_queue(uhf_app->view_dispatcher);
@@ -131,8 +65,12 @@ UHFApp* uhf_alloc() {
     view_dispatcher_attach_to_gui(
     view_dispatcher_attach_to_gui(
         uhf_app->view_dispatcher, uhf_app->gui, ViewDispatcherTypeFullscreen);
         uhf_app->view_dispatcher, uhf_app->gui, ViewDispatcherTypeFullscreen);
 
 
-    // Storage
-    uhf_app->storage = furi_record_open(RECORD_STORAGE);
+    //worker
+    uhf_app->worker = uhf_worker_alloc();
+
+    // device
+    uhf_app->uhf_device = uhf_device_alloc();
+    uhf_app->uhf_device->dev_data = uhf_app->worker->response_data;
 
 
     // Open Notification record
     // Open Notification record
     uhf_app->notifications = furi_record_open(RECORD_NOTIFICATION);
     uhf_app->notifications = furi_record_open(RECORD_NOTIFICATION);
@@ -202,9 +140,8 @@ void uhf_free(UHFApp* uhf_app) {
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_GUI);
     uhf_app->gui = NULL;
     uhf_app->gui = NULL;
 
 
-    // Storage
-    furi_record_close(RECORD_STORAGE);
-    uhf_app->storage = NULL;
+    // UHFDevice
+    uhf_device_free(uhf_app->uhf_device);
 
 
     // Notifications
     // Notifications
     furi_record_close(RECORD_NOTIFICATION);
     furi_record_close(RECORD_NOTIFICATION);

+ 11 - 11
uhf_app_i.h

@@ -15,24 +15,24 @@
 
 
 #include <input/input.h>
 #include <input/input.h>
 
 
+#include "uhf_app.h"
+#include "uhf_worker.h"
+#include "uhf_device.h"
 #include "scenes/uhf_scene.h"
 #include "scenes/uhf_scene.h"
 
 
 #include <storage/storage.h>
 #include <storage/storage.h>
-// #include <lib/toolbox/path.h>
+#include <lib/toolbox/path.h>
 #include <toolbox/path.h>
 #include <toolbox/path.h>
 #include <flipper_format/flipper_format.h>
 #include <flipper_format/flipper_format.h>
 
 
-#include "uhf_app.h"
-#include "uhf_worker.h"
 #include <uhf_rfid_icons.h>
 #include <uhf_rfid_icons.h>
 
 
-#define UHF_BANK_DOES_NOT_EXIST (uint8_t[]){0xFF}
 #define UHF_TEXT_STORE_SIZE 128
 #define UHF_TEXT_STORE_SIZE 128
-#define UHF_APPS_DATA_FOLDER EXT_PATH("apps_data")
-#define UHF_APPS_STORAGE_FOLDER \
-    UHF_APPS_DATA_FOLDER "/"    \
-                         "uhf_rfid"
-#define UHF_FILE_EXTENSION ".uhf"
+// #define UHF_APPS_DATA_FOLDER EXT_PATH("apps_data")
+// #define UHF_APPS_STORAGE_FOLDER 
+//     UHF_APPS_DATA_FOLDER "/"    
+//                          "uhf_rfid"
+// #define UHF_FILE_EXTENSION ".uhf"
 
 
 enum UHFCustomEvent {
 enum UHFCustomEvent {
     // Reserve first 100 events for button types and indexes, starting from 0
     // Reserve first 100 events for button types and indexes, starting from 0
@@ -56,8 +56,8 @@ struct UHFApp {
     Gui* gui;
     Gui* gui;
     NotificationApp* notifications;
     NotificationApp* notifications;
     SceneManager* scene_manager;
     SceneManager* scene_manager;
-    Storage* storage;
-
+    // Storage* storage;
+    UHFDevice* uhf_device;
     char text_store[UHF_TEXT_STORE_SIZE + 1];
     char text_store[UHF_TEXT_STORE_SIZE + 1];
     FuriString* text_box_store;
     FuriString* text_box_store;
 
 

+ 17 - 0
uhf_data.c

@@ -34,6 +34,23 @@ void uhf_data_reset(UHFData* uhf_data) {
     uhf_data->next = NULL;
     uhf_data->next = NULL;
 }
 }
 
 
+uint8_t uhf_data_calculate_checksum(UHFData* uhf_data) {
+    // CheckSum8 Modulo 256
+    // Sum of Bytes % 256
+    uint8_t sum_val = 0x00;
+    size_t length = uhf_data->length - 2;
+    for(size_t i = 1; i < length; i++) {
+        sum_val += uhf_data->data[i];
+    }
+    return sum_val % 256;
+}
+
+bool uhf_data_verfiy_checksum(UHFData* uhf_data) {
+    uint8_t data_checksum = uhf_data->data[uhf_data->length - 2];
+    uint8_t actual_checksum = uhf_data_calculate_checksum(uhf_data);
+    return data_checksum == actual_checksum;
+}
+
 void uhf_data_free(UHFData* uhf_data) {
 void uhf_data_free(UHFData* uhf_data) {
     if(uhf_data == NULL) return;
     if(uhf_data == NULL) return;
     while(uhf_data != NULL) {
     while(uhf_data != NULL) {

+ 2 - 0
uhf_data.h

@@ -23,6 +23,8 @@ typedef struct UHFResponseData {
 UHFData* uhf_data_alloc();
 UHFData* uhf_data_alloc();
 int uhf_data_append(UHFData* uhf_data, uint8_t data);
 int uhf_data_append(UHFData* uhf_data, uint8_t data);
 void uhf_data_reset(UHFData* uhf_data);
 void uhf_data_reset(UHFData* uhf_data);
+uint8_t uhf_data_calculate_checksum(UHFData* uhf_data);
+bool uhf_data_verfiy_checksum(UHFData* uhf_data);
 void uhf_data_free(UHFData* uhf_data);
 void uhf_data_free(UHFData* uhf_data);
 
 
 UHFResponseData* uhf_response_data_alloc();
 UHFResponseData* uhf_response_data_alloc();

+ 353 - 0
uhf_device.c

@@ -0,0 +1,353 @@
+#include "uhf_device.h"
+
+#include <toolbox/path.h>
+#include <flipper_format/flipper_format.h>
+#include <uhf_rfid_icons.h>
+
+#define TAG "UHFDevice"
+
+static const char* uhf_file_header = "Flipper UHF RFID device";
+static const uint32_t uhf_file_version = 1;
+static const uint8_t bank_data_start = 20;
+static const uint8_t bank_data_length = 16;
+
+UHFDevice* uhf_device_alloc() {
+    UHFDevice* uhf_device = malloc(sizeof(UHFDevice));
+    uhf_device->storage = furi_record_open(RECORD_STORAGE);
+    uhf_device->dialogs = furi_record_open(RECORD_DIALOGS);
+    uhf_device->load_path = furi_string_alloc();
+    return uhf_device;
+}
+
+void picopass_device_set_name(UHFDevice* dev, const char* name) {
+    furi_assert(dev);
+
+    strlcpy(dev->dev_name, name, UHF_DEV_NAME_MAX_LEN);
+}
+
+static bool uhf_device_save_file(
+    UHFDevice* dev,
+    const char* dev_name,
+    const char* folder,
+    const char* extension,
+    bool use_load_path) {
+    furi_assert(dev);
+
+    UHFResponseData* uhf_response_data = dev->dev_data;
+    bool saved = false;
+    FlipperFormat* file = flipper_format_file_alloc(dev->storage);
+    FuriString* temp_str;
+    temp_str = furi_string_alloc();
+
+    do {
+        if(use_load_path && !furi_string_empty(dev->load_path)) {
+            // Get directory name
+            path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
+            // Make path to file to save
+            furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
+        } else {
+            // First remove uhf device file if it was saved
+            furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
+        }
+        // Open file
+        if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
+
+        // Write header
+        if(!flipper_format_write_header_cstr(file, uhf_file_header, uhf_file_version)) break;
+        // write rfu data to file
+        UHFData* rfu_data = uhf_response_data_get_uhf_data(uhf_response_data, 1);
+        if(rfu_data->length) {
+            if(!flipper_format_write_hex(
+                   file, "RFU", rfu_data->data + bank_data_start, bank_data_length))
+                return false;
+        } else {
+            if(!flipper_format_write_hex(file, "RFU", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
+        }
+
+        // write epc data to file
+        UHFData* epc_data = uhf_response_data_get_uhf_data(uhf_response_data, 2);
+        if(epc_data->length) {
+            if(!flipper_format_write_hex(
+                   file, "EPC", epc_data->data + bank_data_start, bank_data_length))
+                return false;
+        } else {
+            if(!flipper_format_write_hex(file, "EPC", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
+        }
+
+        // write tid data to file
+        UHFData* tid_data = uhf_response_data_get_uhf_data(uhf_response_data, 3);
+        if(tid_data->length) {
+            if(!flipper_format_write_hex(
+                   file, "TID", tid_data->data + bank_data_start, bank_data_length))
+                return false;
+        } else {
+            if(!flipper_format_write_hex(file, "TID", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
+        }
+        // write user data to file
+        UHFData* user_data = uhf_response_data_get_uhf_data(uhf_response_data, 4);
+        if(user_data->length) {
+            if(!flipper_format_write_hex(
+                   file, "USER", user_data->data + bank_data_start, bank_data_length))
+                return false;
+        } else {
+            if(!flipper_format_write_hex(file, "USER", UHF_BANK_DOES_NOT_EXIST, 1)) return false;
+        }
+        saved = true;
+    } while(0);
+
+    if(!saved) {
+        dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile");
+    }
+    furi_string_free(temp_str);
+    flipper_format_free(file);
+    return saved;
+}
+
+bool uhf_device_save(UHFDevice* dev, const char* dev_name) {
+    return uhf_device_save_file(
+        dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, UHF_APP_EXTENSION, true);
+
+    return false;
+}
+// uncomment
+
+// static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dialog) {
+//     bool parsed = false;
+//     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
+//     FuriString* temp_str;
+//     temp_str = furi_string_alloc();
+//     bool deprecated_version = false;
+
+//     if(dev->loading_cb) {
+//         dev->loading_cb(dev->loading_cb_ctx, true);
+//     }
+
+//     do {
+//         if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
+
+//         // Read and verify file header
+//         uint32_t version = 0;
+//         if(!flipper_format_read_header(file, temp_str, &version)) break;
+//         if(furi_string_cmp_str(temp_str, uhf_file_header) || (version != uhf_file_version)) {
+//             deprecated_version = true;
+//             break;
+//         }
+
+//         // // Parse header blocks
+//         // bool block_read = true;
+//         // for(size_t i = 0; i < 6; i++) {
+//         //     furi_string_printf(temp_str, "Block %d", i);
+//         //     if(!flipper_format_read_hex(
+//         //            file, furi_string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
+//         //         block_read = false;
+//         //         break;
+//         //     }
+//         // }
+
+//         // size_t app_limit = AA1[PICOPASS_CONFIG_BLOCK_INDEX].data[0];
+//         // // Fix for unpersonalized cards that have app_limit set to 0xFF
+//         // if(app_limit > PICOPASS_MAX_APP_LIMIT) app_limit = PICOPASS_MAX_APP_LIMIT;
+//         // for(size_t i = 6; i < app_limit; i++) {
+//         //     furi_string_printf(temp_str, "Block %d", i);
+//         //     if(!flipper_format_read_hex(
+//         //            file, furi_string_get_cstr(temp_str), AA1[i].data, PICOPASS_BLOCK_LEN)) {
+//         //         block_read = false;
+//         //         break;
+//         //     }
+//         // }
+//         // if(!block_read) break;
+
+//         // if(picopass_device_parse_credential(AA1, pacs) != ERR_NONE) break;
+//         // if(picopass_device_parse_wiegand(pacs->credential, &pacs->record) != ERR_NONE) break;
+
+//         parsed = true;
+//     } while(false);
+
+//     if(dev->loading_cb) {
+//         dev->loading_cb(dev->loading_cb_ctx, false);
+//     }
+
+//     if((!parsed) && (show_dialog)) {
+//         if(deprecated_version) {
+//             dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
+//         } else {
+//             dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
+//         }
+//     }
+
+//     furi_string_free(temp_str);
+//     flipper_format_free(file);
+
+//     return parsed;
+// }
+
+// void picopass_device_clear(UHFDevice* dev) {
+//     furi_assert(dev);
+
+//     picopass_device_data_clear(&dev->dev_data);
+//     memset(&dev->dev_data, 0, sizeof(dev->dev_data));
+//     dev->format = PicopassDeviceSaveFormatHF;
+//     furi_string_reset(dev->load_path);
+// }
+
+void uhf_device_free(UHFDevice* uhf_dev) {
+    furi_assert(uhf_dev);
+    // picopass_device_clear(uhf_dev);
+    furi_record_close(RECORD_STORAGE);
+    furi_record_close(RECORD_DIALOGS);
+    furi_string_free(uhf_dev->load_path);
+    uhf_response_data_free(uhf_dev->dev_data);
+    free(uhf_dev);
+}
+
+// bool uhf_file_select(UHFDevice* dev) {
+//     furi_assert(dev);
+
+//     FuriString* uhf_app_folder;
+//     uhf_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
+
+//     DialogsFileBrowserOptions browser_options;
+//     dialog_file_browser_set_basic_options(&browser_options, UHF_APP_EXTENSION, &I_Nfc_10px);
+//     browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
+
+//     bool res =
+//         dialog_file_browser_show(dev->dialogs, dev->load_path, uhf_app_folder, &browser_options);
+
+//     furi_string_free(uhf_app_folder);
+//     if(res) {
+//         FuriString* filename;
+//         filename = furi_string_alloc();
+//         path_extract_filename(dev->load_path, filename, true);
+//         strncpy(dev->dev_name, furi_string_get_cstr(filename), UHF_DEV_NAME_MAX_LEN);
+//         res = uhf_device_load_data(dev, dev->load_path, true);
+//         if(res) {
+//             uhf_device_set_name(dev, dev->dev_name);
+//         }
+//         furi_string_free(filename);
+//     }
+
+//     return res;
+// }
+
+// void uhf_device_data_clear(UHFDevice* dev_data) {
+//     for(size_t i = 0; i < PICOPASS_MAX_APP_LIMIT; i++) {
+//         memset(dev_data->AA1[i].data, 0, sizeof(dev_data->AA1[i].data));
+//     }
+//     dev_data->pacs.legacy = false;
+//     dev_data->pacs.se_enabled = false;
+//     dev_data->pacs.elite_kdf = false;
+//     dev_data->pacs.pin_length = 0;
+// }
+
+bool uhf_device_delete(UHFDevice* dev, bool use_load_path) {
+    furi_assert(dev);
+
+    bool deleted = false;
+    FuriString* file_path;
+    file_path = furi_string_alloc();
+
+    do {
+        // Delete original file
+        if(use_load_path && !furi_string_empty(dev->load_path)) {
+            furi_string_set(file_path, dev->load_path);
+        } else {
+            furi_string_printf(file_path, APP_DATA_PATH("%s%s"), dev->dev_name, UHF_APP_EXTENSION);
+        }
+        if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
+        deleted = true;
+    } while(0);
+
+    if(!deleted) {
+        dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
+    }
+
+    furi_string_free(file_path);
+    return deleted;
+}
+
+void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context) {
+    furi_assert(dev);
+
+    dev->loading_cb = callback;
+    dev->loading_cb_ctx = context;
+}
+
+// ReturnCode picopass_device_decrypt(uint8_t* enc_data, uint8_t* dec_data) {
+//     uint8_t key[32] = {0};
+//     memcpy(key, picopass_iclass_decryptionkey, sizeof(picopass_iclass_decryptionkey));
+//     mbedtls_des3_context ctx;
+//     mbedtls_des3_init(&ctx);
+//     mbedtls_des3_set2key_dec(&ctx, key);
+//     mbedtls_des3_crypt_ecb(&ctx, enc_data, dec_data);
+//     mbedtls_des3_free(&ctx);
+//     return ERR_NONE;
+// }
+
+// ReturnCode picopass_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs) {
+//     ReturnCode err;
+
+//     pacs->biometrics = AA1[6].data[4];
+//     pacs->pin_length = AA1[6].data[6] & 0x0F;
+//     pacs->encryption = AA1[6].data[7];
+
+//     if(pacs->encryption == PicopassDeviceEncryption3DES) {
+//         FURI_LOG_D(TAG, "3DES Encrypted");
+//         err = picopass_device_decrypt(AA1[7].data, pacs->credential);
+//         if(err != ERR_NONE) {
+//             FURI_LOG_E(TAG, "decrypt error %d", err);
+//             return err;
+//         }
+
+//         err = picopass_device_decrypt(AA1[8].data, pacs->pin0);
+//         if(err != ERR_NONE) {
+//             FURI_LOG_E(TAG, "decrypt error %d", err);
+//             return err;
+//         }
+
+//         err = picopass_device_decrypt(AA1[9].data, pacs->pin1);
+//         if(err != ERR_NONE) {
+//             FURI_LOG_E(TAG, "decrypt error %d", err);
+//             return err;
+//         }
+//     } else if(pacs->encryption == PicopassDeviceEncryptionNone) {
+//         FURI_LOG_D(TAG, "No Encryption");
+//         memcpy(pacs->credential, AA1[7].data, PICOPASS_BLOCK_LEN);
+//         memcpy(pacs->pin0, AA1[8].data, PICOPASS_BLOCK_LEN);
+//         memcpy(pacs->pin1, AA1[9].data, PICOPASS_BLOCK_LEN);
+//     } else if(pacs->encryption == PicopassDeviceEncryptionDES) {
+//         FURI_LOG_D(TAG, "DES Encrypted");
+//     } else {
+//         FURI_LOG_D(TAG, "Unknown encryption");
+//     }
+
+//     pacs->sio = (AA1[10].data[0] == 0x30); // rough check
+
+//     return ERR_NONE;
+// }
+
+// ReturnCode picopass_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record) {
+//     uint32_t* halves = (uint32_t*)data;
+//     if(halves[0] == 0) {
+//         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[1]));
+//         record->bitLength = 31 - leading0s;
+//     } else {
+//         uint8_t leading0s = __builtin_clz(REVERSE_BYTES_U32(halves[0]));
+//         record->bitLength = 63 - leading0s;
+//     }
+//     FURI_LOG_D(TAG, "bitLength: %d", record->bitLength);
+
+//     if(record->bitLength == 26) {
+//         uint8_t* v4 = data + 4;
+//         uint32_t bot = v4[3] | (v4[2] << 8) | (v4[1] << 16) | (v4[0] << 24);
+
+//         record->CardNumber = (bot >> 1) & 0xFFFF;
+//         record->FacilityCode = (bot >> 17) & 0xFF;
+//         FURI_LOG_D(TAG, "FC: %u CN: %u", record->FacilityCode, record->CardNumber);
+//         record->valid = true;
+//     } else {
+//         record->CardNumber = 0;
+//         record->FacilityCode = 0;
+//         record->valid = false;
+//     }
+//     return ERR_NONE;
+// }

+ 103 - 0
uhf_device.h

@@ -0,0 +1,103 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <storage/storage.h>
+#include <dialogs/dialogs.h>
+#include <mbedtls/des.h>
+#include "uhf_data.h"
+
+// #include "rfal_picopass.h"
+
+#define UHF_DEV_NAME_MAX_LEN 22
+#define PICOPASS_READER_DATA_MAX_SIZE 64
+#define PICOPASS_BLOCK_LEN 8
+#define PICOPASS_MAX_APP_LIMIT 32
+#define UHF_BANK_DOES_NOT_EXIST (uint8_t[]){0xFF}
+
+
+#define UHF_APP_EXTENSION ".uhf"
+// #define PICOPASS_APP_SHADOW_EXTENSION ".pas"
+
+typedef void (*UHFLoadingCallback)(void* context, bool state);
+
+// typedef struct {
+//     IclassEliteDict* dict;
+//     IclassEliteDictType type;
+//     uint8_t current_sector;
+// } IclassEliteDictAttackData;
+
+// typedef enum {
+//     PicopassDeviceEncryptionUnknown = 0,
+//     PicopassDeviceEncryptionNone = 0x14,
+//     PicopassDeviceEncryptionDES = 0x15,
+//     PicopassDeviceEncryption3DES = 0x17,
+// } PicopassEncryption;
+
+// typedef enum {
+//     PicopassDeviceSaveFormatHF,
+//     PicopassDeviceSaveFormatLF,
+// } PicopassDeviceSaveFormat;
+
+// typedef struct {
+//     bool valid;
+//     uint8_t bitLength;
+//     uint8_t FacilityCode;
+//     uint16_t CardNumber;
+// } PicopassWiegandRecord;
+
+// typedef struct {
+//     bool legacy;
+//     bool se_enabled;
+//     bool sio;
+//     bool biometrics;
+//     uint8_t key[8];
+//     bool elite_kdf;
+//     uint8_t pin_length;
+//     PicopassEncryption encryption;
+//     uint8_t credential[8];
+//     uint8_t pin0[8];
+//     uint8_t pin1[8];
+//     PicopassWiegandRecord record;
+// } PicopassPacs;
+
+// typedef struct {
+//     uint8_t data[PICOPASS_BLOCK_LEN];
+// } PicopassBlock;
+
+// typedef struct {
+//     PicopassBlock AA1[PICOPASS_MAX_APP_LIMIT];
+//     PicopassPacs pacs;
+//     IclassEliteDictAttackData iclass_elite_dict_attack_data;
+// } PicopassDeviceData;
+
+typedef struct {
+    Storage* storage;
+    DialogsApp* dialogs;
+    UHFResponseData* dev_data;
+    char dev_name[UHF_DEV_NAME_MAX_LEN + 1];
+    FuriString* load_path;
+    UHFLoadingCallback loading_cb;
+    void* loading_cb_ctx;
+} UHFDevice;
+
+UHFDevice* uhf_device_alloc();
+
+void uhf_device_free(UHFDevice* uhf_dev);
+
+void uhf_device_set_name(UHFDevice* dev, const char* name);
+
+bool uhf_device_save(UHFDevice* dev, const char* dev_name);
+
+bool uhf_file_select(UHFDevice* dev);
+
+// void uhf_device_data_clear(PicopassDeviceData* dev_data);
+
+void uhf_device_clear(UHFDevice* dev);
+
+bool uhf_device_delete(UHFDevice* dev, bool use_load_path);
+
+void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context);
+
+// ReturnCode uhf_device_parse_credential(PicopassBlock* AA1, PicopassPacs* pacs);
+// ReturnCode uhf_device_parse_wiegand(uint8_t* data, PicopassWiegandRecord* record);

+ 28 - 22
uhf_worker.c

@@ -2,22 +2,22 @@
 #include "uhf_cmd.h"
 #include "uhf_cmd.h"
 
 
 #define CB_DELAY 50
 #define CB_DELAY 50
-// inner functions
-uint8_t calculate_checksum(UHFData* uhf_data) {
-    // CheckSum8 Modulo 256
-    // Sum of Bytes % 256
-    uint8_t sum_val = 0x00;
-    size_t length = uhf_data->length - 2;
-    for(size_t i = 1; i < length; i++) {
-        sum_val += uhf_data->data[i];
-    }
-    return sum_val % 256;
-}
-bool validate_checksum(UHFData* uhf_data) {
-    uint8_t data_checksum = uhf_data->data[uhf_data->length - 2];
-    uint8_t actual_checksum = calculate_checksum(uhf_data);
-    return data_checksum == actual_checksum;
-}
+// // inner functions
+// uint8_t calculate_checksum(UHFData* uhf_data) {
+//     // CheckSum8 Modulo 256
+//     // Sum of Bytes % 256
+//     uint8_t sum_val = 0x00;
+//     size_t length = uhf_data->length - 2;
+//     for(size_t i = 1; i < length; i++) {
+//         sum_val += uhf_data->data[i];
+//     }
+//     return sum_val % 256;
+// }
+// bool validate_checksum(UHFData* uhf_data) {
+//     uint8_t data_checksum = uhf_data->data[uhf_data->length - 2];
+//     uint8_t actual_checksum = calculate_checksum(uhf_data);
+//     return data_checksum == actual_checksum;
+// }
 // uart callback functions
 // uart callback functions
 void module_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
 void module_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
     UNUSED(event);
     UNUSED(event);
@@ -48,10 +48,16 @@ UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) {
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, manufacturer);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, manufacturer);
     furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_MANUFACTURERS.cmd, CMD_MANUFACTURERS.length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_MANUFACTURERS.cmd, CMD_MANUFACTURERS.length);
     furi_delay_ms(CB_DELAY);
     furi_delay_ms(CB_DELAY);
-    // FURI_LOG_E("log", "done sending tx");
+    // verify that we received all data
     if(!hardware_version->end || !software_version->end || !manufacturer->end) {
     if(!hardware_version->end || !software_version->end || !manufacturer->end) {
         return UHFWorkerEventFail;
         return UHFWorkerEventFail;
     }
     }
+    // verify all data was received correctly
+    if(!uhf_data_verfiy_checksum(hardware_version) ||
+       !uhf_data_verfiy_checksum(software_version) || 
+       !uhf_data_verfiy_checksum(manufacturer))
+        return UHFWorkerEventFail;
+
     return UHFWorkerEventSuccess;
     return UHFWorkerEventSuccess;
 }
 }
 
 
@@ -91,7 +97,7 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
         select_cmd->data[12 + i] = raw_read_data->data[8 + i];
         select_cmd->data[12 + i] = raw_read_data->data[8 + i];
     }
     }
     // checksum
     // checksum
-    select_cmd->data[select_cmd->length - 2] = calculate_checksum(select_cmd);
+    select_cmd->data[select_cmd->length - 2] = uhf_data_calculate_checksum(select_cmd);
     UHFData* select_response = uhf_response_data_add_new_uhf_data(uhf_response_data);
     UHFData* select_response = uhf_response_data_add_new_uhf_data(uhf_response_data);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, select_response);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, select_response);
     furi_hal_uart_tx(FuriHalUartIdUSART1, select_cmd->data, select_cmd->length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, select_cmd->data, select_cmd->length);
@@ -111,7 +117,7 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
     UHFData* rfu_bank = select_response;
     UHFData* rfu_bank = select_response;
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, rfu_bank);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, rfu_bank);
     read_bank_cmd->data[9] = 0x00;
     read_bank_cmd->data[9] = 0x00;
-    read_bank_cmd->data[read_bank_cmd->length - 2] = calculate_checksum(read_bank_cmd);
+    read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
     uhf_data_reset(rfu_bank);
     uhf_data_reset(rfu_bank);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_delay_ms(CB_DELAY);
     furi_delay_ms(CB_DELAY);
@@ -123,7 +129,7 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
     UHFData* epc_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     UHFData* epc_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, epc_bank);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, epc_bank);
     read_bank_cmd->data[9] = 0x01;
     read_bank_cmd->data[9] = 0x01;
-    read_bank_cmd->data[read_bank_cmd->length - 2] = calculate_checksum(read_bank_cmd);
+    read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
     uhf_data_reset(epc_bank);
     uhf_data_reset(epc_bank);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_delay_ms(CB_DELAY);
     furi_delay_ms(CB_DELAY);
@@ -135,7 +141,7 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
     UHFData* tid_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     UHFData* tid_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, tid_bank);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, tid_bank);
     read_bank_cmd->data[9] = 0x02;
     read_bank_cmd->data[9] = 0x02;
-    read_bank_cmd->data[read_bank_cmd->length - 2] = calculate_checksum(read_bank_cmd);
+    read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
     uhf_data_reset(tid_bank);
     uhf_data_reset(tid_bank);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_delay_ms(CB_DELAY);
     furi_delay_ms(CB_DELAY);
@@ -147,7 +153,7 @@ UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
     UHFData* user_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     UHFData* user_bank = uhf_response_data_add_new_uhf_data(uhf_response_data);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, user_bank);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, user_bank);
     read_bank_cmd->data[9] = 0x03;
     read_bank_cmd->data[9] = 0x03;
-    read_bank_cmd->data[read_bank_cmd->length - 2] = calculate_checksum(read_bank_cmd);
+    read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
     uhf_data_reset(user_bank);
     uhf_data_reset(user_bank);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
     furi_delay_ms(CB_DELAY);
     furi_delay_ms(CB_DELAY);

+ 1 - 3
uhf_worker.h

@@ -45,6 +45,4 @@ void uhf_worker_start(
     UHFWorkerCallback callback,
     UHFWorkerCallback callback,
     void* ctx);
     void* ctx);
 void uhf_worker_stop(UHFWorker* uhf_worker);
 void uhf_worker_stop(UHFWorker* uhf_worker);
-void uhf_worker_free(UHFWorker* uhf_worker);
-uint8_t calculate_checksum(UHFData* uhf_data);
-bool validate_checksum(UHFData* uhf_data);
+void uhf_worker_free(UHFWorker* uhf_worker);