Bläddra i källkod

Merge pull request #7 from frux-c/gen2_struct

Proper Structured Code for converting to framework
Abel Chaka 2 år sedan
förälder
incheckning
95962eb04b

+ 21 - 83
README.md

@@ -1,21 +1,33 @@
 # [UHF]RFID App for FlipperZero
 
-![FlipperZero](assets/img/uhf_demo_app.jpg)
+![FlipperZero](assets/img/uhf_demo_app2.jpg)
 
 ## Overview
 
 This repository contains a UHF RFID application developed for FlipperZero, a versatile multi-tool device. The app leverages the YRM100 module to enable UHF RFID functionality.
 
+## What's Changed
+
+- A complete refractor from the concept code to covert to a framework. So that it's easy to refractor for different possible module's. See [module.h](uhf_module.h) for more info.
+- Reading bank now can automatically detect bank size, for cases that PC(protocol control) bits aren't properly written to tag.
+- Can now view tag from saved.
+- Can now write tags from saved.
+
 ## Features
 
 - [x] Read Single UHF RFID tag.
 - [x] View saved UHF RFID tag.
-- [ ] Write Single UHF RFID tag. __(in progress)__
-- [ ] Change Module setting parameters.
-- [ ] Easy-to-use interface on FlipperZero's display.
-    - Extras
-        - [ ] Read multiple tags at once
-        - [ ] View multiple on a list view
+- [x] Write Single UHF RFID tag.
+- [ ] Change Module setting parameters. __(In Progress)__
+    - [ ] Set/Reset Access Password
+    - [ ] Set Kill Password
+    - [ ] Kill Tag
+    - [ ] TBD
+- [ ] Edit/Create new data to write.
+- Extras
+    - [ ] Read multiple tags at once
+    - [ ] View multiple on a list view
+
 
 ## Requirements
 
@@ -49,82 +61,6 @@ To run this application on FlipperZero, you will need:
 
 As this app is still in the development stage, I welcome contributions to this project. If you find any issues or want to enhance the application, feel free to create a pull request.
 
-<!-- ## License
-
-This project is licensed under the [MIT License](link_to_license_file). -->
-
-## Future Plans
-- Code cleanup
-- Build a framework around the chip communication commands
-- Build a proper tag class
-```c
-// Ideal concept
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-typedef struct {
-    int uart_fd; // UART file descriptor or other identifier
-} YRM100_RFID;
-
-void sendCommand(YRM100_RFID *rfid, const uint8_t *command, size_t length) {
-    // Implementation to send the command through UART
-    // Write the command to the UART interface using rfid->uart_fd
-}
-
-// Configuration functions:
-
-void setCommunicationBaudRate(YRM100_RFID *rfid) {
-    uint8_t command[] = {0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E};
-    sendCommand(rfid, command, sizeof(command));
-}
-
-void setWorkingArea(YRM100_RFID *rfid, uint8_t area) {
-    uint8_t command[] = {0xBB, 0x00, 0x07, 0x00, 0x01, area, 0x09, 0x7E}; 
-    sendCommand(rfid, command, sizeof(command));
-}
-
-// other method etc ... 
-```
-
-```c
-// Ideal concept
-#include <stdint.h>
-#include <stdlib.h>
-
-typedef struct {
-    uint8_t *killPassword;
-    uint8_t *accessPassword;
-    size_t size;
-} ReservedMemory;
-
-typedef struct {
-    uint8_t *header;
-    uint8_t *filter;
-    uint8_t *partition;
-    uint8_t *companyPrefix;
-    uint8_t *itemReference;
-    size_t size;
-} EPCMemory;
-
-typedef struct {
-    uint8_t *tid;
-    size_t size;
-} TIDMemory;
-
-typedef struct {
-    uint8_t *userMemory;
-    size_t size;
-} UserMemory;
-
-typedef struct {
-    ReservedMemory reserved;
-    EPCMemory epc;
-    TIDMemory tid;
-    UserMemory user;
-} ISO18000_6C_Tag;
-```
-
 ## Disclaimer
 
 - This application is provided as-is and may contain bugs or issues.
@@ -134,6 +70,8 @@ typedef struct {
 ## Extra Resources
 
 - [MagicRF M100&QM100_Firmware_manual_en.pdf](assets/res/MagicRF_M100&QM100_Firmware_manual_en.pdf)
+- [TDS_1_9_Standard.pdf](assets/res/TDS_1_9_Standard.pdf)
+- [M5Stack Docs](https://docs.m5stack.com/en/unit/uhf_rfid)
 
 ## Contact
 

BIN
assets/img/uhf_demo_app2.jpg


+ 3 - 3
scenes/uhf_scene_config.h

@@ -2,7 +2,7 @@ ADD_SCENE(uhf, verify, Verify)
 ADD_SCENE(uhf, start, Start)
 ADD_SCENE(uhf, read_tag, ReadTag)
 ADD_SCENE(uhf, read_tag_success, ReadTagSuccess)
-ADD_SCENE(uhf, card_menu, CardMenu)
+ADD_SCENE(uhf, tag_menu, TagMenu)
 ADD_SCENE(uhf, save_name, SaveName)
 ADD_SCENE(uhf, save_success, SaveSuccess)
 ADD_SCENE(uhf, saved_menu, SavedMenu)
@@ -10,8 +10,8 @@ ADD_SCENE(uhf, file_select, FileSelect)
 ADD_SCENE(uhf, device_info, DeviceInfo)
 ADD_SCENE(uhf, delete, Delete)
 ADD_SCENE(uhf, delete_success, DeleteSuccess)
-// ADD_SCENE(uhf, write_card, WriteCard)
-// ADD_SCENE(uhf, write_card_success, WriteCardSuccess)
+ADD_SCENE(uhf, write_tag, WriteTag)
+ADD_SCENE(uhf, write_tag_success, WriteTagSuccess)
 // ADD_SCENE(uhf, read_factory_success, ReadFactorySuccess)
 // ADD_SCENE(uhf, write_key, WriteKey)
 // ADD_SCENE(uhf, key_menu, KeyMenu)

+ 8 - 8
scenes/uhf_scene_device_info.c

@@ -40,7 +40,7 @@ void uhf_scene_device_info_widget_callback(GuiButtonType result, InputType type,
 }
 
 void change_view_on_event(UHFApp* uhf_app) {
-    UHFTag* uhf_tag = uhf_app->uhf_device->uhf_tag;
+    UHFTag* uhf_tag = uhf_app->uhf_device->uhf_tag_wrapper->uhf_tag;
     FuriString* furi_temp_str;
     furi_temp_str = furi_string_alloc();
     char* temp_str;
@@ -52,16 +52,16 @@ void change_view_on_event(UHFApp* uhf_app) {
 
     switch(current_info) {
     case EPC_INFO:
-        temp_str = convertToHexString(uhf_tag->epc, uhf_tag->epc_length);
-        length = uhf_tag->epc_length;
+        temp_str = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
+        length = uhf_tag->epc->size;
         break;
     case TID_INFO:
-        temp_str = convertToHexString(uhf_tag->tid, uhf_tag->tid_length);
-        length = uhf_tag->tid_length;
+        temp_str = convertToHexString(uhf_tag->tid->data, uhf_tag->tid->size);
+        length = uhf_tag->tid->size;
         break;
     case USER_INFO:
-        temp_str = convertToHexString(uhf_tag->user, uhf_tag->user_length);
-        length = uhf_tag->user_length;
+        temp_str = convertToHexString(uhf_tag->user->data, uhf_tag->user->size);
+        length = uhf_tag->user->size;
         break;
     default:
         temp_str = NULL;
@@ -81,7 +81,7 @@ void change_view_on_event(UHFApp* uhf_app) {
         furi_string_get_cstr(furi_temp_str));
 
     widget_add_string_multiline_element(
-        uhf_app->widget, 3, 24, AlignLeft, AlignTop, FontBatteryPercent, temp_str);
+        uhf_app->widget, 3, 24, AlignLeft, AlignTop, FontKeyboard, temp_str);
 
     widget_add_button_element(
         uhf_app->widget,

+ 0 - 1
scenes/uhf_scene_read_tag.c

@@ -44,6 +44,5 @@ void uhf_scene_read_tag_on_exit(void* ctx) {
     uhf_worker_stop(uhf_app->worker);
     // Clear view
     popup_reset(uhf_app->popup);
-
     uhf_blink_stop(uhf_app);
 }

+ 28 - 11
scenes/uhf_scene_read_tag_success.c

@@ -17,7 +17,8 @@ void uhf_scene_read_card_success_widget_callback(GuiButtonType result, InputType
 
 void uhf_scene_read_tag_success_on_enter(void* ctx) {
     UHFApp* uhf_app = ctx;
-    UHFTag* uhf_tag = uhf_app->worker->uhf_tag;
+    UHFTag* uhf_tag = uhf_app->worker->uhf_tag_wrapper->uhf_tag;
+    FuriString* temp_str = furi_string_alloc();
 
     dolphin_deed(DolphinDeedNfcReadSuccess);
 
@@ -35,13 +36,30 @@ void uhf_scene_read_tag_success_on_enter(void* ctx) {
     widget_add_string_element(
         uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
 
-    char* pc = convertToHexString(uhf_tag->pc, 2);
-    widget_add_string_element(uhf_app->widget, 26, 19, AlignLeft, AlignCenter, FontKeyboard, pc);
-    char* crc = convertToHexString(uhf_tag->crc, 2);
-    widget_add_string_element(uhf_app->widget, 96, 19, AlignLeft, AlignCenter, FontKeyboard, crc);
-    char* epc = convertToHexString(uhf_tag->epc + 2, uhf_tag->epc_length - 2);
-    widget_add_string_multiline_element(
-        uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
+    furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->pc);
+    widget_add_string_element(
+        uhf_app->widget,
+        26,
+        19,
+        AlignLeft,
+        AlignCenter,
+        FontKeyboard,
+        furi_string_get_cstr(temp_str));
+    furi_string_reset(temp_str);
+    furi_string_cat_printf(temp_str, "%04X", uhf_tag->epc->crc);
+    widget_add_string_element(
+        uhf_app->widget,
+        96,
+        19,
+        AlignLeft,
+        AlignCenter,
+        FontKeyboard,
+        furi_string_get_cstr(temp_str));
+    char* epc = convertToHexString(uhf_tag->epc->data, uhf_tag->epc->size);
+    if(epc != NULL) {
+        widget_add_string_multiline_element(
+            uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
+    }
     widget_add_button_element(
         uhf_app->widget,
         GuiButtonTypeRight,
@@ -55,9 +73,8 @@ void uhf_scene_read_tag_success_on_enter(void* ctx) {
         uhf_scene_read_card_success_widget_callback,
         uhf_app);
     view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
-    free(pc);
-    free(crc);
     free(epc);
+    furi_string_free(temp_str);
 }
 
 bool uhf_scene_read_tag_success_on_event(void* ctx, SceneManagerEvent event) {
@@ -72,7 +89,7 @@ bool uhf_scene_read_tag_success_on_event(void* ctx, SceneManagerEvent event) {
             consumed = scene_manager_search_and_switch_to_previous_scene(
                 uhf_app->scene_manager, UHFSceneStart);
         } else if(event.event == GuiButtonTypeRight) {
-            scene_manager_next_scene(uhf_app->scene_manager, UHFSceneCardMenu);
+            scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
             consumed = true;
         } else if(event.event == GuiButtonTypeCenter) {
             // consumed = scene_manager_search_and_switch_to_another_scene(

+ 2 - 2
scenes/uhf_scene_save_success.c

@@ -27,9 +27,9 @@ bool uhf_scene_save_success_on_event(void* context, SceneManagerEvent event) {
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == UHFCustomEventViewExit) {
-            if(scene_manager_has_previous_scene(uhf_app->scene_manager, UHFSceneCardMenu)) {
+            if(scene_manager_has_previous_scene(uhf_app->scene_manager, UHFSceneTagMenu)) {
                 consumed = scene_manager_search_and_switch_to_previous_scene(
-                    uhf_app->scene_manager, UHFSceneCardMenu);
+                    uhf_app->scene_manager, UHFSceneTagMenu);
             } else {
                 consumed = scene_manager_search_and_switch_to_previous_scene(
                     uhf_app->scene_manager, UHFSceneStart);

+ 3 - 4
scenes/uhf_scene_saved_menu.c

@@ -43,11 +43,10 @@ bool uhf_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
         } else if(event.event == SubmenuIndexInfo) {
             scene_manager_next_scene(uhf_app->scene_manager, UHFSceneDeviceInfo);
             consumed = true;
+        } else if(event.event == SubmenuIndexWrite) {
+            scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTag);
+            consumed = true;
         }
-        // } else if(event.event == SubmenuIndexWrite) {
-        //     scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteCard);
-        //     consumed = true;
-        // }
     }
 
     return consumed;

+ 9 - 13
scenes/uhf_scene_card_menu.c → scenes/uhf_scene_tag_menu.c

@@ -5,45 +5,41 @@ enum SubmenuIndex {
     SubmenuIndexChangeKey,
 };
 
-void uhf_scene_card_menu_submenu_callback(void* ctx, uint32_t index) {
+void uhf_scene_tag_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) {
+void uhf_scene_tag_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, "Save", SubmenuIndexSave, uhf_scene_tag_menu_submenu_callback, uhf_app);
     submenu_add_item(
-        submenu,
-        "Change Key",
-        SubmenuIndexChangeKey,
-        uhf_scene_card_menu_submenu_callback,
-        uhf_app);
+        submenu, "Change Key", SubmenuIndexChangeKey, uhf_scene_tag_menu_submenu_callback, uhf_app);
 
     submenu_set_selected_item(
-        submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneCardMenu));
+        submenu, scene_manager_get_scene_state(uhf_app->scene_manager, UHFSceneTagMenu));
 
     view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewMenu);
 }
 
-bool uhf_scene_card_menu_on_event(void* ctx, SceneManagerEvent event) {
+bool uhf_scene_tag_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);
+                uhf_app->scene_manager, UHFSceneTagMenu, 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);
+        //         picopass->scene_manager, UHFSceneTagMenu, SubmenuIndexChangeKey);
         //     scene_manager_next_scene(picopass->scene_manager, PicopassSceneKeyMenu);
         //     consumed = true;
         // }
@@ -55,7 +51,7 @@ bool uhf_scene_card_menu_on_event(void* ctx, SceneManagerEvent event) {
     return consumed;
 }
 
-void uhf_scene_card_menu_on_exit(void* ctx) {
+void uhf_scene_tag_menu_on_exit(void* ctx) {
     UHFApp* uhf_app = ctx;
 
     submenu_reset(uhf_app->submenu);

+ 9 - 17
scenes/uhf_scene_verify.c

@@ -42,6 +42,10 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                 widget_reset(uhf_app->widget);
                 furi_string_reset(temp_str);
                 uhf_worker_stop(uhf_app->worker);
+                // furi_hal_gpio_write(&gpio_ext, false);
+                // furi_delay_ms(50);
+                // furi_hal_gpio_write(&gpio_ext_pa7, true);
+                // furi_delay_ms(50);
                 uhf_worker_start(
                     uhf_app->worker,
                     UHFWorkerStateVerify,
@@ -52,18 +56,12 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
             if(verify_success) {
                 widget_reset(uhf_app->widget);
                 furi_string_reset(temp_str);
-                UHFResponseData* uhf_response_data = uhf_app->worker->response_data;
-                UHFData* hardware_version = uhf_response_data_get_uhf_data(uhf_response_data, 0);
-                UHFData* software_version = uhf_response_data_get_uhf_data(uhf_response_data, 1);
-                UHFData* manufacturer = uhf_response_data_get_uhf_data(uhf_response_data, 2);
-                uint offset = 6;
+                M100Module* module = uhf_app->worker->module;
                 widget_add_string_element(
                     uhf_app->widget, 64, 5, AlignCenter, AlignCenter, FontPrimary, "Module Info");
                 // hardware info
                 furi_string_cat_str(temp_str, "HW Version: ");
-                for(int i = 0; i < (int)hardware_version->data[4]; i++) {
-                    furi_string_cat_printf(temp_str, "%c", hardware_version->data[offset + i]);
-                }
+                furi_string_cat_str(temp_str, module->info->hw_version);
                 widget_add_string_element(
                     uhf_app->widget,
                     1,
@@ -75,9 +73,7 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                 furi_string_reset(temp_str);
                 // software info
                 furi_string_cat_str(temp_str, "SW Version: ");
-                for(int i = 0; i < (int)software_version->data[4]; i++) {
-                    furi_string_cat_printf(temp_str, "%c", software_version->data[offset + i]);
-                }
+                furi_string_cat_str(temp_str, module->info->sw_version);
                 widget_add_string_element(
                     uhf_app->widget,
                     1,
@@ -89,9 +85,7 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                 furi_string_reset(temp_str);
                 // manufacturer info
                 furi_string_cat_str(temp_str, "Manufacturer: ");
-                for(int i = 0; i < (int)manufacturer->data[4]; i++) {
-                    furi_string_cat_printf(temp_str, "%c", manufacturer->data[offset + i]);
-                }
+                furi_string_cat_str(temp_str, module->info->manufacturer);
                 widget_add_string_element(
                     uhf_app->widget,
                     1,
@@ -123,7 +117,7 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                     AlignCenter,
                     AlignCenter,
                     FontSecondary,
-                    "Please connect your module.\nPlease refer to the frux-c/uhf_rfid for help.");
+                    "Please refer to the git@frux-c/uhf_rfid for help.");
                 widget_add_button_element(
                     uhf_app->widget,
                     GuiButtonTypeLeft,
@@ -148,8 +142,6 @@ void uhf_scene_verify_on_exit(void* ctx) {
     furi_string_free(temp_str);
     // Stop worker
     uhf_worker_stop(uhf_app->worker);
-    // Clear view
-    // popup_reset(uhf_app->popup);
     // clear widget
     widget_reset(uhf_app->widget);
 }

+ 49 - 0
scenes/uhf_scene_write_tag.c

@@ -0,0 +1,49 @@
+#include "../uhf_app_i.h"
+#include <dolphin/dolphin.h>
+
+void uhf_write_tag_worker_callback(UHFWorkerEvent event, void* ctx) {
+    UHFApp* uhf_app = ctx;
+    if(event == UHFWorkerEventSuccess) {
+        view_dispatcher_send_custom_event(uhf_app->view_dispatcher, UHFCustomEventWorkerExit);
+    }
+    // } else if(event == UHFWorkerEventAborted) {
+    //     scene_manager_search_and_switch_to_previous_scene(uhf_app->scene_manager, UHFSceneStart);
+    // }
+}
+
+void uhf_scene_write_tag_on_enter(void* ctx) {
+    UHFApp* uhf_app = ctx;
+    dolphin_deed(DolphinDeedNfcRead);
+
+    // Setup view
+    Popup* popup = uhf_app->popup;
+    popup_set_header(popup, "Writing\n[UHF] RFID\nTag", 68, 30, AlignLeft, AlignTop);
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
+
+    // Start worker
+    view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewPopup);
+    uhf_worker_start(
+        uhf_app->worker, UHFWorkerStateWriteSingle, uhf_write_tag_worker_callback, uhf_app);
+
+    uhf_blink_start(uhf_app);
+}
+
+bool uhf_scene_write_tag_on_event(void* ctx, SceneManagerEvent event) {
+    UHFApp* uhf_app = ctx;
+    bool consumed = false;
+    if(event.event == UHFCustomEventWorkerExit) {
+        scene_manager_next_scene(uhf_app->scene_manager, UHFSceneWriteTagSuccess);
+        consumed = true;
+    }
+    return consumed;
+}
+
+void uhf_scene_write_tag_on_exit(void* ctx) {
+    UHFApp* uhf_app = ctx;
+    // Stop worker
+    uhf_worker_stop(uhf_app->worker);
+    // Clear view
+    popup_reset(uhf_app->popup);
+
+    uhf_blink_stop(uhf_app);
+}

+ 94 - 0
scenes/uhf_scene_write_tag_success.c

@@ -0,0 +1,94 @@
+#include "../uhf_app_i.h"
+#include <dolphin/dolphin.h>
+
+void uhf_write_tag_success_worker_callback(UHFWorkerEvent event, void* ctx) {
+    UNUSED(event);
+    UNUSED(ctx);
+}
+
+void uhf_scene_write_tag_success_widget_callback(GuiButtonType result, InputType type, void* ctx) {
+    furi_assert(ctx);
+    UHFApp* uhf_app = ctx;
+
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(uhf_app->view_dispatcher, result);
+    }
+}
+
+void uhf_scene_write_tag_success_on_enter(void* ctx) {
+    UHFApp* uhf_app = ctx;
+
+    dolphin_deed(DolphinDeedNfcReadSuccess);
+
+    // Send notification
+    notification_message(uhf_app->notifications, &sequence_success);
+
+    widget_add_string_element(
+        uhf_app->widget, 32, 5, AlignLeft, AlignCenter, FontPrimary, "Write Success");
+
+    // widget_add_string_element(uhf_app->widget, 3, 18, AlignLeft, AlignCenter, FontPrimary, "PC :");
+
+    // widget_add_string_element(
+    //     uhf_app->widget, 66, 18, AlignLeft, AlignCenter, FontPrimary, "CRC :");
+
+    // widget_add_string_element(
+    //     uhf_app->widget, 3, 32, AlignLeft, AlignCenter, FontPrimary, "EPC :");
+
+    // char* pc = convertToHexString(uhf_tag->pc, 2);
+    // widget_add_string_element(uhf_app->widget, 26, 19, AlignLeft, AlignCenter, FontKeyboard, pc);
+    // char* crc = convertToHexString(uhf_tag->crc, 2);
+    // widget_add_string_element(uhf_app->widget, 96, 19, AlignLeft, AlignCenter, FontKeyboard, crc);
+    // char* epc = convertToHexString(uhf_tag->epc + 2, uhf_tag->epc_length - 2);
+    // widget_add_string_multiline_element(
+    //     uhf_app->widget, 34, 29, AlignLeft, AlignTop, FontKeyboard, epc);
+
+    widget_add_button_element(
+        uhf_app->widget,
+        GuiButtonTypeRight,
+        "More",
+        uhf_scene_write_tag_success_widget_callback,
+        uhf_app);
+    widget_add_button_element(
+        uhf_app->widget,
+        GuiButtonTypeLeft,
+        "Exit",
+        uhf_scene_write_tag_success_widget_callback,
+        uhf_app);
+    view_dispatcher_switch_to_view(uhf_app->view_dispatcher, UHFViewWidget);
+    // free(pc);
+    // free(crc);
+    // free(epc);
+}
+
+bool uhf_scene_write_tag_success_on_event(void* ctx, SceneManagerEvent event) {
+    UHFApp* uhf_app = ctx;
+    bool consumed = false;
+    if(event.event == SceneManagerEventTypeBack) {
+        uhf_app->worker->state = UHFWorkerStateStop;
+    }
+    if(event.type == SceneManagerEventTypeCustom) {
+        // if 'exit' is pressed go back to home screen
+        if(event.event == GuiButtonTypeLeft) {
+            consumed = scene_manager_search_and_switch_to_previous_scene(
+                uhf_app->scene_manager, UHFSceneStart);
+        } else if(event.event == GuiButtonTypeRight) {
+            scene_manager_next_scene(uhf_app->scene_manager, UHFSceneTagMenu);
+            consumed = true;
+        } else if(event.event == GuiButtonTypeCenter) {
+            // consumed = scene_manager_search_and_switch_to_another_scene(
+            //     picopass->scene_manager, PicopassSceneStart);
+        }
+    }
+    return consumed;
+}
+
+void uhf_scene_write_tag_success_on_exit(void* ctx) {
+    UHFApp* uhf_app = ctx;
+
+    // // Stop worker
+    uhf_worker_stop(uhf_app->worker);
+    // Clear view
+    popup_reset(uhf_app->popup);
+    // clear widget
+    widget_reset(uhf_app->widget);
+}

+ 14 - 15
uhf_app.c

@@ -1,6 +1,6 @@
 #include "uhf_app_i.h"
 
-char* convertToHexString(const uint8_t* array, size_t length) {
+char* convertToHexString(uint8_t* array, size_t length) {
     if(array == NULL || length == 0) {
         return " ";
     }
@@ -60,10 +60,11 @@ UHFApp* uhf_alloc() {
     // device
     uhf_app->uhf_device = uhf_device_alloc();
 
-    UHFTag* uhf_tag = uhf_tag_alloc();
-    // point tag object to worker
-    uhf_app->worker->uhf_tag = uhf_tag;
-    uhf_app->uhf_device->uhf_tag = uhf_tag;
+    UHFTagWrapper* uhf_tag_wrapper = uhf_tag_wrapper_alloc();
+
+    // // point tag object to worker
+    uhf_app->worker->uhf_tag_wrapper = uhf_tag_wrapper;
+    uhf_app->uhf_device->uhf_tag_wrapper = uhf_tag_wrapper;
 
     // Open Notification record
     uhf_app->notifications = furi_record_open(RECORD_NOTIFICATION);
@@ -119,12 +120,15 @@ void uhf_free(UHFApp* uhf_app) {
     view_dispatcher_remove_view(uhf_app->view_dispatcher, UHFViewWidget);
     widget_free(uhf_app->widget);
 
+    // Tag
+    uhf_tag_wrapper_free(uhf_app->worker->uhf_tag_wrapper);
+
     // Worker
     uhf_worker_stop(uhf_app->worker);
     uhf_worker_free(uhf_app->worker);
 
-    // Tag
-    uhf_tag_free(uhf_app->worker->uhf_tag);
+    // Device
+    uhf_device_free(uhf_app->uhf_device);
 
     // View Dispatcher
     view_dispatcher_free(uhf_app->view_dispatcher);
@@ -136,9 +140,6 @@ void uhf_free(UHFApp* uhf_app) {
     furi_record_close(RECORD_GUI);
     uhf_app->gui = NULL;
 
-    // UHFDevice
-    uhf_device_free(uhf_app->uhf_device);
-
     // Notifications
     furi_record_close(RECORD_NOTIFICATION);
     uhf_app->notifications = NULL;
@@ -184,19 +185,17 @@ int32_t uhf_app_main(void* ctx) {
     UNUSED(ctx);
     UHFApp* uhf_app = uhf_alloc();
 
-    furi_hal_uart_resume(FuriHalUartIdUSART1);
-
     // enable 5v pin
     furi_hal_power_enable_otg();
+    // init pin a2
+    // furi_hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
 
     scene_manager_next_scene(uhf_app->scene_manager, UHFSceneVerify);
     view_dispatcher_run(uhf_app->view_dispatcher);
 
     // disable 5v pin
     furi_hal_power_disable_otg();
-
-    furi_hal_uart_suspend(FuriHalUartIdUSART1);
-
+    // furi_hal_gpio_disable_int_callback()
     // exit app
     uhf_free(uhf_app);
     return 0;

+ 2 - 2
uhf_app_i.h

@@ -99,6 +99,6 @@ void uhf_show_loading_popup(void* context, bool show);
  */
 bool uhf_is_memset(const uint8_t* data, const uint8_t pattern, size_t size);
 
-char* convertToHexString(const uint8_t* array, size_t length);
+char* convertToHexString(uint8_t* array, size_t length);
 
-bool uhf_save_read_data(UHFResponseData* uhf_response_data, Storage* storage, const char* filename);
+// bool uhf_save_read_data(UHFResponseData* uhf_response_data, Storage* storage, const char* filename);

+ 66 - 0
uhf_buffer.c

@@ -0,0 +1,66 @@
+#include "uhf_buffer.h"
+#include <stdlib.h>
+#include <string.h>
+
+Buffer* buffer_alloc(size_t initial_capacity) {
+    Buffer* buf = (Buffer*)malloc(sizeof(Buffer));
+    buf->data = (uint8_t*)malloc(sizeof(uint8_t) * initial_capacity);
+    if(!buf->data) {
+        free(buf);
+        return NULL;
+    }
+    buf->size = 0;
+    buf->capacity = initial_capacity;
+    return buf;
+}
+
+bool buffer_append_single(Buffer* buf, uint8_t data) {
+    if(buf->closed) return false;
+    if(buf->size + 1 > buf->capacity) {
+        size_t new_capacity = buf->capacity * 2;
+        uint8_t* new_data = (uint8_t*)realloc(buf->data, sizeof(uint8_t) * new_capacity);
+        if(!new_data) return false;
+        buf->data = new_data;
+        buf->capacity = new_capacity;
+    }
+    buf->data[buf->size++] = data;
+    return true;
+}
+
+bool buffer_append(Buffer* buf, uint8_t* data, size_t data_size) {
+    if(buf->closed) return false;
+    if(buf->size + data_size > buf->capacity) {
+        size_t new_capacity = buf->capacity * 2;
+        uint8_t* new_data = (uint8_t*)realloc(buf->data, new_capacity);
+        if(!new_data) return false;
+
+        buf->data = new_data;
+        buf->capacity = new_capacity;
+    }
+
+    memcpy((void*)&buf->data[buf->size], data, data_size);
+    buf->size += data_size;
+    return true;
+}
+
+uint8_t* buffer_get_data(Buffer* buf) {
+    return buf->data;
+}
+
+size_t buffer_get_size(Buffer* buf) {
+    return buf->size;
+}
+
+void buffer_close(Buffer* buf) {
+    buf->closed = true;
+}
+
+void buffer_reset(Buffer* buf) {
+    buf->size = 0;
+    buf->closed = false;
+}
+
+void buffer_free(Buffer* buf) {
+    free(buf->data);
+    free(buf);
+}

+ 22 - 0
uhf_buffer.h

@@ -0,0 +1,22 @@
+#pragma once
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#define MAX_BUFFER_SIZE 128
+
+typedef struct Buffer {
+    uint8_t* data;
+    size_t size;
+    size_t capacity;
+    bool closed;
+} Buffer;
+
+Buffer* buffer_alloc(size_t inital_capacity);
+bool buffer_append_single(Buffer* buf, uint8_t value);
+bool buffer_append(Buffer* buf, uint8_t* data, size_t size);
+uint8_t* buffer_get_data(Buffer* buf);
+size_t buffer_get_size(Buffer* buf);
+void buffer_close(Buffer* buf);
+void buffer_reset(Buffer* buf);
+void buffer_free(Buffer* buf);

+ 69 - 69
uhf_cmd.h

@@ -1,114 +1,114 @@
-#ifndef UHF_CMD_H
-#define UHF_CMD_H
+// #ifndef UHF_CMD_H
+// #define UHF_CMD_H
 
-#include <stdint.h>
-#include <stdlib.h>
+// #include <stdint.h>
+// #include <stdlib.h>
 
-typedef struct UHF_RFID_CMD {
-    uint8_t* cmd;
-    size_t length;
-}UHF_RFID_CMD;
+// typedef struct UHF_RFID_CMD {
+//     uint8_t* cmd;
+//     size_t length;
+// }UHF_RFID_CMD;
 
-typedef enum{
-    COMMAND_FRAME = 0x00,
-    RESPONSE_FRAME,
-    NOTIFICATION_FRAME
-}UHFFrameType;
+// typedef enum{
+//     COMMAND_FRAME = 0x00,
+//     RESPONSE_FRAME,
+//     NOTIFICATION_FRAME
+// }UHFFrameType;
 
-typedef enum{
-    RFU_BANK,
-    EPC_BANK,
-    TID_BANK,
-    USER_BANK
-}UHFBank;
+// typedef enum{
+//     RFU_BANK,
+//     EPC_BANK,
+//     TID_BANK,
+//     USER_BANK
+// }UHFBank;
 
-typedef enum{
-    CHINA_900MHZ = 1,
-    CHINA_800MHZ = 4,
-    US = 2,
-    EU = 3,
-    KOREA = 6
-}UHFWorkArea;
+// typedef enum{
+//     CHINA_900MHZ = 1,
+//     CHINA_800MHZ = 4,
+//     US = 2,
+//     EU = 3,
+//     KOREA = 6
+// }UHFWorkArea;
 
-#define DEFAULT_BAUD_RATE 115200
-#define FRAME_START 0xBB
-#define FRAME_END 0x7E
-#define ERROR 0x15
+// #define DEFAULT_BAUD_RATE 115200
+// #define FRAME_START 0xBB
+// #define FRAME_END 0x7E
+// #define ERROR 0x15
 
-UHF_RFID_CMD CMD_HARDWARE_VERSION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_HARDWARE_VERSION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_SOFTWARE_VERSION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SOFTWARE_VERSION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_MANUFACTURERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x02, 0x06, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_MANUFACTURERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x03, 0x00, 0x01, 0x02, 0x06, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_SINGLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_SINGLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_MULTIPLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x27, 0x10, 0x83, 0x7E}, .length = 10};
+// UHF_RFID_CMD CMD_MULTIPLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x27, 0x10, 0x83, 0x7E}, .length = 10};
 
-UHF_RFID_CMD CMD_STOP_MULTIPLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x28, 0x00, 0x00, 0x28, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_STOP_MULTIPLE_POLLING = {.cmd = (uint8_t[]){0xBB, 0x00, 0x28, 0x00, 0x00, 0x28, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_SELECT_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0C, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x20, 0x60, 0x00, 0x30, 0x75, 0x1F, 0xEB, 0x70, 0x5C, 0x59, 0x04, 0xE3, 0xD5, 0x0D, 0x70, 0xAD, 0x7E }, .length = 26};
+// UHF_RFID_CMD CMD_SET_SELECT_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0C, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x20, 0x60, 0x00, 0x30, 0x75, 0x1F, 0xEB, 0x70, 0x5C, 0x59, 0x04, 0xE3, 0xD5, 0x0D, 0x70, 0xAD, 0x7E }, .length = 26};
 
-UHF_RFID_CMD CMD_GET_SELECT_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0B, 0x00, 0x00, 0x0B, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_GET_SELECT_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0B, 0x00, 0x00, 0x0B, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_SELECT_MODE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x12, 0x00, 0x01, 0x01, 0x14, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SET_SELECT_MODE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x12, 0x00, 0x01, 0x01, 0x14, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_READ_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x39, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x4D, 0x7E}, .length = 16};
+// UHF_RFID_CMD CMD_READ_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x39, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x4D, 0x7E}, .length = 16};
 
-UHF_RFID_CMD CMD_WRITE_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x49, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x71, 0x7E}, .length = 24};
+// UHF_RFID_CMD CMD_WRITE_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x71, 0x7E}, .length = 24};
 
-UHF_RFID_CMD CMD_LOCK_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x82, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x80, 0x09, 0x7E}, .length = 13};
+// UHF_RFID_CMD CMD_LOCK_LABEL_DATA_STORAGE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x82, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x80, 0x09, 0x7E}, .length = 13};
 
-UHF_RFID_CMD CMD_INACTIVATE_KILL_TAG = {.cmd = (uint8_t[]){0xBB, 0x00, 0x65, 0x00, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x67, 0x7E}, .length = 11};
+// UHF_RFID_CMD CMD_INACTIVATE_KILL_TAG = {.cmd = (uint8_t[]){0xBB, 0x00, 0x65, 0x00, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x67, 0x7E}, .length = 11};
 
-UHF_RFID_CMD CMD_SET_COMMUNICATION_BAUD_RATE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E}, .length = 9};
+// UHF_RFID_CMD CMD_SET_COMMUNICATION_BAUD_RATE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E}, .length = 9};
 
-UHF_RFID_CMD CMD_GET_QUERY_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0D, 0x00, 0x00, 0x0D, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_GET_QUERY_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0D, 0x00, 0x00, 0x0D, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_QUERY_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x20, 0x40, 0x7E}, .length = 9};
+// UHF_RFID_CMD CMD_SET_QUERY_PARAMETER = {.cmd = (uint8_t[]){0xBB, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x20, 0x40, 0x7E}, .length = 9};
 
-UHF_RFID_CMD CMD_SETUP_WORK_AREA = {.cmd = (uint8_t[]){0xBB, 0x00, 0x07, 0x00, 0x01, 0x01, 0x09, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SETUP_WORK_AREA = {.cmd = (uint8_t[]){0xBB, 0x00, 0x07, 0x00, 0x01, 0x01, 0x09, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_ACQUIRE_WORK_LOCATIONS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x08, 0x00, 0x00, 0x08, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_ACQUIRE_WORK_LOCATIONS = {.cmd = (uint8_t[]){0xBB, 0x00, 0x08, 0x00, 0x00, 0x08, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SETUP_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAB, 0x00, 0x01, 0x01, 0xAC, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SETUP_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAB, 0x00, 0x01, 0x01, 0xAC, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_GET_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_GET_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_AUTO_FREQUENCY_HOPPING = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAD, 0x00, 0x01, 0xFF, 0xAD, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SET_AUTO_FREQUENCY_HOPPING = {.cmd = (uint8_t[]){0xBB, 0x00, 0xAD, 0x00, 0x01, 0xFF, 0xAD, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_INSERT_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xA9, 0x00, 0x06, 0x05, 0x01, 0x02,0x03, 0x04, 0x05, 0xC3, 0x7E}, .length = 13};
+// UHF_RFID_CMD CMD_INSERT_WORKING_CHANNEL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xA9, 0x00, 0x06, 0x05, 0x01, 0x02,0x03, 0x04, 0x05, 0xC3, 0x7E}, .length = 13};
 
-UHF_RFID_CMD CMD_ACQUIRE_TRANSMITTING_POWER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB7, 0x00, 0x00, 0xB7, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_ACQUIRE_TRANSMITTING_POWER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB7, 0x00, 0x00, 0xB7, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_TRANSMITTING_POWER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB6, 0x00, 0x02, 0x07, 0xD0, 0x8F, 0x7E}, .length = 9};
+// UHF_RFID_CMD CMD_SET_TRANSMITTING_POWER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB6, 0x00, 0x02, 0x07, 0xD0, 0x8F, 0x7E}, .length = 9};
 
-UHF_RFID_CMD CMD_SET_CONTINUOUS_CARRIER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB0, 0x00, 0x01, 0xFF, 0xB0, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_SET_CONTINUOUS_CARRIER = {.cmd = (uint8_t[]){0xBB, 0x00, 0xB0, 0x00, 0x01, 0xFF, 0xB0, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_GET_DEMODULATOR_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF1, 0x00, 0x00, 0xF1, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_GET_DEMODULATOR_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF1, 0x00, 0x00, 0xF1, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_SET_DEMODULATOR_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF0, 0x00, 0x04, 0x03, 0x06, 0x01, 0xB0, 0xAE, 0x7E}, .length = 11};
+// UHF_RFID_CMD CMD_SET_DEMODULATOR_PARAMETERS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF0, 0x00, 0x04, 0x03, 0x06, 0x01, 0xB0, 0xAE, 0x7E}, .length = 11};
 
-UHF_RFID_CMD CMD_TEST_RF_INPUT_BLOCK_SIGNAL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF2, 0x00, 0x00, 0xF2, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_TEST_RF_INPUT_BLOCK_SIGNAL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF2, 0x00, 0x00, 0xF2, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_TEST_RSSI_SIGNAL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF3, 0x00, 0x00, 0xF3, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_TEST_RSSI_SIGNAL = {.cmd = (uint8_t[]){0xBB, 0x00, 0xF3, 0x00, 0x00, 0xF3, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_MODULE_HIBERNATION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x17, 0x00, 0x00, 0x17, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_MODULE_HIBERNATION = {.cmd = (uint8_t[]){0xBB, 0x00, 0x17, 0x00, 0x00, 0x17, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_IDLE_HIBERNATION_TIME = {.cmd = (uint8_t[]){0xBB, 0x00, 0x1D, 0x00, 0x01, 0x02, 0x20, 0x7E}, .length = 8};
+// UHF_RFID_CMD CMD_IDLE_HIBERNATION_TIME = {.cmd = (uint8_t[]){0xBB, 0x00, 0x1D, 0x00, 0x01, 0x02, 0x20, 0x7E}, .length = 8};
 
-UHF_RFID_CMD CMD_IDLE_MODE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x04, 0x00, 0x03, 0x01, 0x01, 0x03, 0x0C, 0x7E}, .length = 10};
+// UHF_RFID_CMD CMD_IDLE_MODE = {.cmd = (uint8_t[]){0xBB, 0x00, 0x04, 0x00, 0x03, 0x01, 0x01, 0x03, 0x0C, 0x7E}, .length = 10};
 
-UHF_RFID_CMD CMD_NXP_READPROTECT = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE1, 0x00, 0x05, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xE4, 0x7E}, .length = 12};
+// UHF_RFID_CMD CMD_NXP_READPROTECT = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE1, 0x00, 0x05, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xE4, 0x7E}, .length = 12};
 
-UHF_RFID_CMD CMD_NXP_CHANGE_EAS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE3, 0x00, 0x05, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xE7, 0x7E}, .length = 12};
+// UHF_RFID_CMD CMD_NXP_CHANGE_EAS = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE3, 0x00, 0x05, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xE7, 0x7E}, .length = 12};
 
-UHF_RFID_CMD CMD_NXP_EAS_ALARM = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE4, 0x00, 0x00, 0xE4, 0x7E}, .length = 7};
+// UHF_RFID_CMD CMD_NXP_EAS_ALARM = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE4, 0x00, 0x00, 0xE4, 0x7E}, .length = 7};
 
-UHF_RFID_CMD CMD_NXP_CONFIG_WORD = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE0, 0x00, 0x06, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE4, 0x7E}, .length = 13};
+// UHF_RFID_CMD CMD_NXP_CONFIG_WORD = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE0, 0x00, 0x06, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE4, 0x7E}, .length = 13};
 
-UHF_RFID_CMD CMD_IMPINJ_MONZA4_QT = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE5, 0x00, 0x08, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x01, 0x40, 0x00, 0x2D, 0x7E}, .length = 15};
+// UHF_RFID_CMD CMD_IMPINJ_MONZA4_QT = {.cmd = (uint8_t[]){0xBB, 0x00, 0xE5, 0x00, 0x08, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x01, 0x40, 0x00, 0x2D, 0x7E}, .length = 15};
 
-UHF_RFID_CMD CMD_BLOCK_PERMALOCK = {.cmd = (uint8_t[]){0xBB, 0x00, 0xD3, 0x00, 0x0B, 0x00, 0x00, 0xFF,0xFF, 0x01, 0x03, 0x00, 0x00, 0x01, 0x07, 0x00, 0xE8, 0x7E}, .length = 18};
+// UHF_RFID_CMD CMD_BLOCK_PERMALOCK = {.cmd = (uint8_t[]){0xBB, 0x00, 0xD3, 0x00, 0x0B, 0x00, 0x00, 0xFF,0xFF, 0x01, 0x03, 0x00, 0x00, 0x01, 0x07, 0x00, 0xE8, 0x7E}, .length = 18};
 
-#endif /* UHF_CMD_H */
+// #endif /* UHF_CMD_H */

+ 0 - 148
uhf_data.c

@@ -1,148 +0,0 @@
-#include "uhf_data.h"
-
-UHFData* uhf_data_alloc() {
-    UHFData* uhf_data = (UHFData*)malloc(sizeof(UHFData));
-    uhf_data->word_length = 0;
-    uhf_data->length = 0;
-    uhf_data->start = false;
-    uhf_data->end = false;
-    uhf_data->next = NULL;
-    return uhf_data;
-}
-
-int uhf_data_append(UHFData* uhf_data, uint8_t data) {
-    if(data == 0xBB) {
-        uhf_data->start = true;
-    }
-    if(!uhf_data->start) return 0;
-    if(uhf_data->end) return 0;
-    if(uhf_data->length >= MAX_DATA_SIZE) return 0;
-    if(data == 0x7E) {
-        uhf_data->end = true;
-    }
-    uhf_data->data[uhf_data->length++] = data;
-    return 1;
-}
-
-void uhf_data_reset(UHFData* uhf_data) {
-    for(size_t i = 0; i < uhf_data->length; i++) {
-        uhf_data->data[i] = 0x00;
-    }
-    uhf_data->start = false;
-    uhf_data->end = false;
-    uhf_data->length = 0;
-    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) {
-    if(uhf_data == NULL) return;
-    while(uhf_data != NULL) {
-        UHFData* next = uhf_data->next;
-        free(uhf_data);
-        uhf_data = next;
-    }
-}
-
-UHFResponseData* uhf_response_data_alloc() {
-    UHFResponseData* uhf_response_data = (UHFResponseData*)malloc(sizeof(UHFResponseData));
-    uhf_response_data->head = uhf_data_alloc();
-    uhf_response_data->tail = uhf_response_data->head;
-    uhf_response_data->size = 1;
-    return uhf_response_data;
-}
-
-UHFData* uhf_response_data_add_new_uhf_data(UHFResponseData* uhf_response_data) {
-    UHFData* temp = uhf_response_data->head;
-    while(temp->next != NULL) {
-        temp = temp->next;
-    }
-    temp->next = uhf_data_alloc();
-    uhf_response_data->size++;
-    uhf_response_data->tail = temp->next;
-    return temp->next;
-}
-
-UHFData* uhf_response_data_get_uhf_data(UHFResponseData* uhf_response_data, uint index) {
-    if(uhf_response_data == NULL || uhf_response_data->size <= index) return NULL;
-    UHFData* uhf_data = uhf_response_data->head;
-    if(index == 0) return uhf_data;
-    while(uhf_data != NULL && index >= 1) {
-        uhf_data = uhf_data->next;
-        index--;
-    }
-    return uhf_data;
-}
-
-void uhf_response_data_reset(UHFResponseData* uhf_response_data) {
-    uhf_data_reset(uhf_response_data->head);
-    if(uhf_response_data->size == 1) {
-        return;
-    }
-    uhf_data_free(uhf_response_data->head->next);
-    uhf_response_data->size = 1;
-}
-
-void uhf_response_data_free(UHFResponseData* uhf_response_data) {
-    uhf_data_free(uhf_response_data->head);
-    free(uhf_response_data);
-}
-
-UHFTag* uhf_tag_alloc() {
-    UHFTag* uhf_tag = (UHFTag*)malloc(sizeof(UHFTag));
-    return uhf_tag;
-}
-
-void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data, size_t length) {
-    memcpy(uhf_tag->crc, data, 2);
-    data += 2;
-    memcpy(uhf_tag->pc, data, 2);
-    memcpy(uhf_tag->epc, data, length);
-    uhf_tag->epc_length = length;
-}
-
-void uhf_tag_reset(UHFTag* uhf_tag) {
-    for(int i = 0; i < 2; i++) {
-        uhf_tag->crc[i] = 0;
-        uhf_tag->pc[i] = 0;
-        uhf_tag->xpc[i] = 0;
-    }
-    for(int i = 0; i < MAX_BANK_SIZE; i++) {
-        uhf_tag->epc[i] = 0;
-        uhf_tag->tid[i] = 0;
-        uhf_tag->user[i] = 0;
-    }
-    uhf_tag->epc_length = 0;
-    uhf_tag->tid_length = 0;
-    uhf_tag->user_length = 0;
-}
-
-void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data, size_t length) {
-    memcpy(uhf_tag->tid, data, length);
-    uhf_tag->tid_length = length;
-}
-
-void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data, size_t length) {
-    memcpy(uhf_tag->user, data, length);
-    uhf_tag->user_length = length;
-}
-
-void uhf_tag_free(UHFTag* uhf_tag) {
-    free(uhf_tag);
-}

+ 0 - 64
uhf_data.h

@@ -1,64 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-
-#define MAX_DATA_SIZE 128
-#define MAX_BANK_SIZE 64
-typedef unsigned int uint;
-
-typedef struct UHFData {
-    uint8_t data[MAX_DATA_SIZE];
-    size_t word_length;
-    size_t length;
-    bool start;
-    bool end;
-    struct UHFData* next;
-} UHFData;
-
-typedef struct UHFResponseData {
-    UHFData* head;
-    UHFData* tail;
-    size_t size;
-} UHFResponseData;
-
-typedef struct UHFTag {
-    // RESERVED BANK (RFU) (00)
-    uint8_t kill_pwd[2]; // 0x00-0x10
-    uint8_t access_pwd[2]; // 0x10-0x20
-    // EPC Bank
-    uint8_t crc[2]; // 0x00-0x10
-    uint8_t pc[2]; // 0x10-0x20
-    uint8_t epc[MAX_BANK_SIZE]; // 0x20-0x210
-    size_t epc_length;
-    uint8_t xpc[2]; // 0x210-0x21F
-    size_t xpc_length;
-    // TID Bank
-    uint8_t tid[MAX_BANK_SIZE]; // 0x00-END
-    size_t tid_length;
-    // USER Bank
-    uint8_t user[MAX_BANK_SIZE]; // 0x00-END
-    size_t user_length;
-} UHFTag;
-
-UHFData* uhf_data_alloc();
-int uhf_data_append(UHFData* uhf_data, uint8_t 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);
-
-UHFResponseData* uhf_response_data_alloc();
-UHFData* uhf_response_data_add_new_uhf_data(UHFResponseData* uhf_response_data);
-UHFData* uhf_response_data_get_uhf_data(UHFResponseData* uhf_response_data, uint index);
-void uhf_response_data_reset(UHFResponseData* uhf_response_data);
-void uhf_response_data_free(UHFResponseData* uhf_response_data);
-
-UHFTag* uhf_tag_alloc();
-void uhf_tag_reset(UHFTag* uhf_tag);
-void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data, size_t length);
-void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data, size_t length);
-void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data, size_t length);
-void uhf_tag_free(UHFTag* uhf_tag);

+ 42 - 19
uhf_device.c

@@ -1,5 +1,4 @@
 #include "uhf_device.h"
-
 #include <toolbox/path.h>
 #include <flipper_format/flipper_format.h>
 #include <uhf_rfid_icons.h>
@@ -21,7 +20,6 @@ UHFDevice* uhf_device_alloc() {
 
 void uhf_device_set_name(UHFDevice* dev, const char* name) {
     furi_assert(dev);
-
     strlcpy(dev->dev_name, name, UHF_DEV_NAME_MAX_LEN);
 }
 
@@ -33,7 +31,7 @@ static bool uhf_device_save_file(
     bool use_load_path) {
     furi_assert(dev);
 
-    UHFTag* uhf_tag = dev->uhf_tag;
+    UHFTag* uhf_tag = dev->uhf_tag_wrapper->uhf_tag;
     bool saved = false;
     FlipperFormat* file = flipper_format_file_alloc(dev->storage);
     FuriString* temp_str;
@@ -57,21 +55,35 @@ static bool uhf_device_save_file(
         // Reserved bank might be added
         // todo : maybe
         uint32_t temp_arr[1];
+        uint8_t temp_arr2[2];
+        // write pc
+        temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) >> 8) & 0xFF;
+        temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) & 0xFF);
+        if(!flipper_format_write_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
+        // write crc
+        temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) >> 8) & 0xFF;
+        temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) & 0xFF);
+        if(!flipper_format_write_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
         // write epc
-        temp_arr[0] = uhf_tag->epc_length;
+        temp_arr[0] = uhf_tag_get_epc_size(uhf_tag);
         if(!flipper_format_write_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        if(!flipper_format_write_hex(file, UHF_EPC_BANK_LABEL, uhf_tag->epc, uhf_tag->epc_length))
+        if(!flipper_format_write_hex(
+               file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
             break;
         // write tid
-        temp_arr[0] = uhf_tag->tid_length;
+        temp_arr[0] = uhf_tag_get_tid_size(uhf_tag);
         if(!flipper_format_write_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        if(!flipper_format_write_hex(file, UHF_TID_BANK_LABEL, uhf_tag->tid, uhf_tag->tid_length))
+        if(!flipper_format_write_hex(
+               file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
             break;
         // write user
-        temp_arr[0] = uhf_tag->user_length;
+        temp_arr[0] = uhf_tag_get_user_size(uhf_tag);
         if(!flipper_format_write_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_write_hex(
-               file, UHF_USER_BANK_LABEL, uhf_tag->user, uhf_tag->user_length))
+               file,
+               UHF_USER_BANK_LABEL,
+               uhf_tag_get_user(uhf_tag),
+               uhf_tag_get_user_size(uhf_tag)))
             break;
         saved = true;
     } while(0);
@@ -99,7 +111,7 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia
     FuriString* temp_str;
     temp_str = furi_string_alloc();
     bool deprecated_version = false;
-    UHFTag* uhf_tag = dev->uhf_tag;
+    UHFTag* uhf_tag = uhf_tag_alloc();
     uhf_tag_reset(uhf_tag);
     uint32_t temp_arr[1];
     if(dev->loading_cb) {
@@ -116,22 +128,34 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia
             deprecated_version = true;
             break;
         }
+        // read pc
+        uint8_t temp_arr2[2];
+        if(!flipper_format_read_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
+        uhf_tag_set_epc_pc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
+        // read crc
+        if(!flipper_format_read_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
+        uhf_tag_set_epc_crc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
         // read epc
         if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->epc_length = temp_arr[0];
-        if(!flipper_format_read_hex(file, UHF_EPC_BANK_LABEL, uhf_tag->epc, uhf_tag->epc_length))
+        uhf_tag_set_epc_size(uhf_tag, temp_arr[0]);
+        if(!flipper_format_read_hex(
+               file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
             break;
 
         // read tid
         if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->tid_length = temp_arr[0];
-        if(!flipper_format_read_hex(file, UHF_TID_BANK_LABEL, uhf_tag->tid, uhf_tag->tid_length))
+        uhf_tag_set_tid_size(uhf_tag, temp_arr[0]);
+        if(!flipper_format_read_hex(
+               file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
             break;
-
         // read user
         if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->user_length = temp_arr[0];
-        if(!flipper_format_read_hex(file, UHF_USER_BANK_LABEL, uhf_tag->user, uhf_tag->user_length))
+        uhf_tag_set_user_size(uhf_tag, temp_arr[0]);
+        if(!flipper_format_read_hex(
+               file,
+               UHF_USER_BANK_LABEL,
+               uhf_tag_get_user(uhf_tag),
+               uhf_tag_get_user_size(uhf_tag)))
             break;
 
         parsed = true;
@@ -148,10 +172,9 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia
             dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
         }
     }
-
+    uhf_tag_wrapper_set_tag(dev->uhf_tag_wrapper, uhf_tag);
     furi_string_free(temp_str);
     flipper_format_free(file);
-
     return parsed;
 }
 

+ 4 - 15
uhf_device.h

@@ -5,38 +5,27 @@
 #include <storage/storage.h>
 #include <dialogs/dialogs.h>
 #include <mbedtls/des.h>
-#include "uhf_data.h"
-
-// #include "rfal_picopass.h"
+#include "uhf_tag.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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
-            0xFF                                                                                  \
-    }
-
 #define UHF_EPC_BANK_LENGTH_LABEL "EPC_LENGTH"
 #define UHF_TID_BANK_LENGTH_LABEL "TID_LENGTH"
 #define UHF_USER_BANK_LENGTH_LABEL "USER_LENGTH"
+#define UHF_EPC_PC_LABEL "PC"
+#define UHF_EPC_CRC_LABEL "CRC"
 #define UHF_RFU_BANK_LABEL "RFU"
 #define UHF_EPC_BANK_LABEL "EPC"
 #define UHF_TID_BANK_LABEL "TID"
 #define UHF_USER_BANK_LABEL "USER"
 
 #define UHF_APP_EXTENSION ".uhf"
-// #define PICOPASS_APP_SHADOW_EXTENSION ".pas"
 
 typedef void (*UHFLoadingCallback)(void* context, bool state);
 
 typedef struct {
     Storage* storage;
     DialogsApp* dialogs;
-    // UHFResponseData* dev_data;
-    UHFTag* uhf_tag;
+    UHFTagWrapper* uhf_tag_wrapper;
     char dev_name[UHF_DEV_NAME_MAX_LEN + 1];
     FuriString* load_path;
     UHFLoadingCallback loading_cb;

+ 385 - 0
uhf_module.c

@@ -0,0 +1,385 @@
+#include "uhf_module.h"
+#include "uhf_module_cmd.h"
+
+#define DELAY_MS 100
+
+void rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
+    UNUSED(event);
+    Buffer* buf = ctx;
+    buffer_append_single(buf, data);
+    if(data == FRAME_END) buffer_close(buf);
+}
+
+M100ModuleInfo* m100_module_info_alloc() {
+    M100ModuleInfo* module_info = (M100ModuleInfo*)malloc(sizeof(M100ModuleInfo));
+    module_info->hw_version = NULL;
+    module_info->sw_version = NULL;
+    module_info->manufacturer = NULL;
+    return module_info;
+}
+
+void m100_module_info_free(M100ModuleInfo* module_info) {
+    free(module_info->hw_version);
+    free(module_info->sw_version);
+    free(module_info->manufacturer);
+    free(module_info);
+}
+M100Module* m100_module_alloc() {
+    M100Module* module = (M100Module*)malloc(sizeof(M100Module));
+    module->info = m100_module_info_alloc();
+    module->buf = buffer_alloc(128);
+    furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUDRATE);
+    module->baudrate = (uint16_t)(DEFAULT_BAUDRATE);
+    return module;
+}
+
+void m100_module_free(M100Module* module) {
+    m100_module_info_free(module->info);
+    buffer_free(module->buf);
+    free(module);
+}
+
+uint8_t checksum(const uint8_t* data, size_t length) {
+    // CheckSum8 Modulo 256
+    // Sum of Bytes % 256
+    uint64_t sum_val = 0x00;
+    for(size_t i = 0; i < length; i++) {
+        sum_val += data[i];
+    }
+    return (uint8_t)(sum_val % 0x100);
+}
+
+uint16_t crc16_genibus(const uint8_t* data, size_t length) {
+    uint16_t crc = 0xFFFF; // Initial value
+    uint16_t polynomial = 0x1021; // CRC-16/GENIBUS polynomial
+
+    for(size_t i = 0; i < length; i++) {
+        crc ^= (data[i] << 8); // Move byte into MSB of 16bit CRC
+        for(int j = 0; j < 8; j++) {
+            if(crc & 0x8000) {
+                crc = (crc << 1) ^ polynomial;
+            } else {
+                crc <<= 1;
+            }
+        }
+    }
+
+    return crc ^ 0xFFFF; // Post-inversion
+}
+
+char* m100_get_hardware_version(M100Module* module) {
+    if(module->info->hw_version != NULL) {
+        free(module->info->hw_version);
+        module->info->hw_version = NULL;
+    }
+    buffer_reset(module->buf);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)&CMD_HW_VERSION.cmd[0], CMD_HW_VERSION.length);
+    furi_delay_ms(DELAY_MS);
+    if(!buffer_get_size(module->buf)) return NULL;
+    uint8_t* data = buffer_get_data(module->buf);
+    uint16_t payload_len = data[3];
+    payload_len = (payload_len << 8) + data[4];
+    FuriString* temp_str = furi_string_alloc();
+    for(int i = 0; i < payload_len; i++) {
+        furi_string_cat_printf(temp_str, "%c", data[6 + i]);
+    }
+    char* hw_version = (char*)malloc(sizeof(char) * payload_len);
+    memcpy(hw_version, furi_string_get_cstr(temp_str), payload_len);
+    module->info->hw_version = hw_version;
+    furi_string_free(temp_str);
+    return module->info->hw_version;
+}
+char* m100_get_software_version(M100Module* module) {
+    if(module->info->sw_version != NULL) {
+        free(module->info->sw_version);
+        module->info->sw_version = NULL;
+    }
+    buffer_reset(module->buf);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)&CMD_SW_VERSION.cmd[0], CMD_SW_VERSION.length);
+    furi_delay_ms(DELAY_MS);
+    if(!buffer_get_size(module->buf)) return NULL;
+    uint8_t* data = buffer_get_data(module->buf);
+    uint16_t payload_len = data[3];
+    payload_len = (payload_len << 8) + data[4];
+    FuriString* temp_str = furi_string_alloc();
+    for(int i = 0; i < payload_len; i++) {
+        furi_string_cat_printf(temp_str, "%c", data[6 + i]);
+    }
+    char* sw_version = (char*)malloc(sizeof(char) * payload_len);
+    memcpy(sw_version, furi_string_get_cstr(temp_str), payload_len);
+    module->info->sw_version = sw_version;
+    furi_string_free(temp_str);
+    return module->info->sw_version;
+}
+char* m100_get_manufacturers(M100Module* module) {
+    if(module->info->manufacturer != NULL) {
+        free(module->info->manufacturer);
+        module->info->manufacturer = NULL;
+    }
+    buffer_reset(module->buf);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(
+        FuriHalUartIdUSART1, (uint8_t*)&CMD_MANUFACTURERS.cmd[0], CMD_MANUFACTURERS.length);
+    furi_delay_ms(DELAY_MS);
+    if(!buffer_get_size(module->buf)) return NULL;
+    uint8_t* data = buffer_get_data(module->buf);
+    uint16_t payload_len = data[3];
+    payload_len = (payload_len << 8) + data[4];
+    FuriString* temp_str = furi_string_alloc();
+    for(int i = 0; i < payload_len; i++) {
+        furi_string_cat_printf(temp_str, "%c", data[6 + i]);
+    }
+    char* manufacturer = (char*)malloc(sizeof(char) * payload_len);
+    memcpy(manufacturer, furi_string_get_cstr(temp_str), payload_len);
+    module->info->manufacturer = manufacturer;
+    furi_string_free(temp_str);
+    return module->info->manufacturer;
+}
+
+M100ResponseType m100_send_single_poll(M100Module* module, UHFTag* uhf_tag) {
+    buffer_reset(module->buf);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(
+        FuriHalUartIdUSART1, (uint8_t*)&CMD_SINGLE_POLLING.cmd[0], CMD_SINGLE_POLLING.length);
+    furi_delay_ms(DELAY_MS);
+    uint8_t* data = buffer_get_data(module->buf);
+    size_t length = buffer_get_size(module->buf);
+    if(length <= 8 && data[2] == 0xFF) return M100NoTagResponse;
+    uint16_t pc = data[6];
+    uint16_t crc = 0;
+    // mask out epc length from protocol control
+    size_t epc_len = pc;
+    epc_len >>= 3;
+    epc_len *= 2;
+    // get protocol control
+    pc <<= 8;
+    pc += data[7];
+    // get cyclic redundency check
+    crc = data[8 + epc_len];
+    crc <<= 8;
+    crc += data[8 + epc_len + 1];
+    // validate checksum
+    if(checksum(data + 1, length - 3) != data[length - 2]) return M100ValidationFail;
+    // validate crc
+    if(crc16_genibus(data + 6, epc_len + 2) != crc) return M100ValidationFail;
+    uhf_tag_set_epc_pc(uhf_tag, pc);
+    uhf_tag_set_epc_crc(uhf_tag, crc);
+    uhf_tag_set_epc(uhf_tag, data + 8, epc_len);
+    return M100Success;
+}
+
+M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag) {
+    buffer_reset(module->buf);
+    // Set select
+    uint8_t cmd[MAX_BUFFER_SIZE];
+    size_t cmd_length = CMD_SET_SELECT_PARAMETER.length;
+    size_t mask_length_bytes = uhf_tag->epc->size;
+    size_t mask_length_bits = mask_length_bytes * 8;
+    // payload len = sel param len + ptr len + mask len + epc len
+    size_t payload_len = 7 + mask_length_bytes;
+    memcpy(cmd, CMD_SET_SELECT_PARAMETER.cmd, cmd_length);
+    // set new length
+    cmd_length = 12 + mask_length_bytes + 2;
+    // set payload length
+    cmd[3] = (payload_len >> 8) & 0xFF;
+    cmd[4] = payload_len & 0xFF;
+    // set select param
+    cmd[5] = 0x01; // 0x00=rfu, 0x01=epc, 0x10=tid, 0x11=user
+    // set ptr
+    cmd[9] = 0x20; // epc data begins after 0x20
+    // set mask length
+    cmd[10] = mask_length_bits;
+    // truncate
+    cmd[11] = false;
+    // set mask
+    memcpy((void*)&cmd[12], uhf_tag->epc->data, mask_length_bytes);
+
+    // set checksum
+    cmd[cmd_length - 2] = checksum(cmd + 1, 11 + mask_length_bytes);
+    // end frame
+    cmd[cmd_length - 1] = FRAME_END;
+    furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, 12 + mask_length_bytes + 3);
+    furi_delay_ms(DELAY_MS);
+
+    uint8_t* data = buffer_get_data(module->buf);
+    if(checksum(data + 1, 5) != data[6]) return M100ValidationFail; // error in rx
+    if(data[5] != 0x00) return M100ValidationFail; // error if not 0
+
+    return M100Success;
+}
+
+UHFTag* m100_get_select_param(M100Module* module) {
+    buffer_reset(module->buf);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
+    furi_hal_uart_tx(
+        FuriHalUartIdUSART1,
+        (uint8_t*)&CMD_GET_SELECT_PARAMETER.cmd,
+        CMD_GET_SELECT_PARAMETER.length);
+    furi_delay_ms(DELAY_MS);
+    // UHFTag* uhf_tag = uhf_tag_alloc();
+    // uint8_t* data = buffer_get_data(module->buf);
+    // size_t mask_length =
+    // uhf_tag_set_epc(uhf_tag, data + 12, )
+    return NULL;
+}
+
+M100ResponseType m100_read_label_data_storage(
+    M100Module* module,
+    UHFTag* uhf_tag,
+    BankType bank,
+    uint32_t access_pwd,
+    uint16_t word_count) {
+    /*
+    Will probably remove UHFTag as param and get it from get selected tag
+        */
+    if(bank == EPCBank) return M100Success;
+    buffer_reset(module->buf);
+    uint8_t cmd[MAX_BUFFER_SIZE];
+    size_t cmd_length = CMD_READ_LABEL_DATA_STORAGE_AREA.length;
+    memcpy(cmd, CMD_READ_LABEL_DATA_STORAGE_AREA.cmd, cmd_length);
+    // set access password
+    cmd[5] = (access_pwd >> 24) & 0xFF;
+    cmd[6] = (access_pwd >> 16) & 0xFF;
+    cmd[7] = (access_pwd >> 8) & 0xFF;
+    cmd[8] = access_pwd & 0xFF;
+    // set mem bank
+    cmd[9] = (uint8_t)bank;
+    // set word counter
+    cmd[12] = (word_count >> 8) & 0xFF;
+    cmd[13] = word_count & 0xFF;
+    // calc checksum
+    cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
+    furi_delay_ms(DELAY_MS);
+    uint8_t* data = buffer_get_data(module->buf);
+    uint16_t payload_len = data[3];
+    payload_len = (payload_len << 8) + data[4];
+    size_t ptr_offset = 5 /*<-ptr offset*/ + uhf_tag->epc->size + 3 /*<-pc + ul*/;
+    size_t bank_data_length = payload_len - (ptr_offset - 5 /*dont include the offset*/);
+    if(data[2] == 0xFF) {
+        if(payload_len == 0x0001) return M100NoTagResponse;
+        return M100MemoryOverrun;
+    }
+    if(bank == TIDBank) {
+        uhf_tag_set_tid(uhf_tag, data + ptr_offset, bank_data_length);
+    } else if(bank == UserBank) {
+        uhf_tag_set_user(uhf_tag, data + ptr_offset, bank_data_length);
+    }
+    return M100Success;
+}
+
+M100ResponseType m100_write_label_data_storage(
+    M100Module* module,
+    UHFTag* saved_tag,
+    UHFTag* selected_tag,
+    BankType bank,
+    uint16_t source_address,
+    uint32_t access_pwd) {
+    buffer_reset(module->buf);
+    uint8_t cmd[MAX_BUFFER_SIZE];
+    size_t cmd_length = CMD_WRITE_LABEL_DATA_STORE.length;
+    memcpy(cmd, CMD_WRITE_LABEL_DATA_STORE.cmd, cmd_length);
+    uint16_t payload_len = 9;
+    uint16_t data_length = 0;
+    if(bank == ReservedBank) {
+        // access pwd len + kill pwd len
+        payload_len += 4;
+        data_length = 4;
+    } else if(bank == EPCBank) {
+        // epc len + pc len
+        payload_len += 4 + uhf_tag_get_epc_size(saved_tag);
+        data_length = 4 + uhf_tag_get_epc_size(saved_tag);
+        // set data
+        uint8_t tmp_arr[4];
+        tmp_arr[0] = (uint8_t)((uhf_tag_get_epc_crc(selected_tag) >> 8) & 0xFF);
+        tmp_arr[1] = (uint8_t)(uhf_tag_get_epc_crc(selected_tag) & 0xFF);
+        tmp_arr[2] = (uint8_t)((uhf_tag_get_epc_pc(saved_tag) >> 8) & 0xFF);
+        tmp_arr[3] = (uint8_t)(uhf_tag_get_epc_pc(saved_tag) & 0xFF);
+        memcpy(cmd + 14, tmp_arr, 4);
+        memcpy(cmd + 18, uhf_tag_get_epc(saved_tag), uhf_tag_get_epc_size(saved_tag));
+    } else if(bank == UserBank) {
+        payload_len += uhf_tag_get_user_size(saved_tag);
+        data_length = uhf_tag_get_user_size(saved_tag);
+        // set data
+        memcpy(cmd + 14, uhf_tag_get_user(saved_tag), uhf_tag_get_user_size(saved_tag));
+    }
+    // set payload length
+    cmd[3] = (payload_len >> 8) & 0xFF;
+    cmd[4] = payload_len & 0xFF;
+    // set access password
+    cmd[5] = (access_pwd >> 24) & 0xFF;
+    cmd[6] = (access_pwd >> 16) & 0xFF;
+    cmd[7] = (access_pwd >> 8) & 0xFF;
+    cmd[8] = access_pwd & 0xFF;
+    // set membank
+    cmd[9] = (uint8_t)bank;
+    // set source address
+    cmd[10] = (source_address >> 8) & 0xFF;
+    cmd[11] = source_address & 0xFF;
+    // set data length
+    size_t data_length_words = data_length / 2;
+    cmd[12] = (data_length_words >> 8) & 0xFF;
+    cmd[13] = data_length_words & 0xFF;
+    // update cmd len
+    cmd_length = 7 + payload_len;
+    // calculate checksum
+    cmd[cmd_length - 2] = checksum(cmd + 1, cmd_length - 3);
+    cmd[cmd_length - 1] = FRAME_END;
+    // send cmd
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
+    uint8_t max_wait = 25;
+    while(!buffer_get_size(module->buf)) {
+        furi_delay_ms(DELAY_MS);
+        if(!max_wait--) break;
+    }
+    uint8_t* buff_data = buffer_get_data(module->buf);
+    size_t buff_length = buffer_get_size(module->buf);
+    if(buff_data[2] == 0xFF && buff_length == 8)
+        return M100NoTagResponse;
+    else if(buff_data[2] == 0xFF)
+        return M100ValidationFail;
+    return M100Success;
+}
+void m100_set_baudrate(M100Module* module, uint16_t baudrate) {
+    size_t length = CMD_SET_COMMUNICATION_BAUD_RATE.length;
+    uint8_t cmd[length];
+    memcpy(cmd, CMD_SET_COMMUNICATION_BAUD_RATE.cmd, length);
+    uint16_t br_mod = baudrate / 100; // module format
+    cmd[6] = 0xFF & br_mod; // pow LSB
+    cmd[5] = 0xFF & (br_mod >> 4); // pow MSB
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
+    furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
+    module->baudrate = baudrate;
+}
+bool m100_set_working_area(M100Module* module, WorkingArea area) {
+    size_t length = CMD_SET_WORK_AREA.length;
+    uint8_t cmd[length];
+    memcpy(cmd, CMD_SET_WORK_AREA.cmd, length);
+    cmd[5] = area;
+    Buffer* buf = buffer_alloc(12);
+    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, buf);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
+    buffer_free(buf);
+    module->area = area;
+    return true;
+}
+bool m100_set_working_channel(M100Module* module, WorkingChannel channel) {
+    UNUSED(module);
+    UNUSED(channel);
+    return true;
+}
+bool m100_set_transmitting_power(M100Module* module, uint16_t power) {
+    UNUSED(module);
+    UNUSED(power);
+    return true;
+}
+bool m100_set_freq_hopping(M100Module* module, bool hopping) {
+    UNUSED(module);
+    UNUSED(hopping);
+    return true;
+}

+ 87 - 0
uhf_module.h

@@ -0,0 +1,87 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "uhf_buffer.h"
+#include "uhf_tag.h"
+#include <furi_hal.h>
+
+#define FRAME_END 0x7E
+#define DEFAULT_BAUDRATE 115200
+
+typedef struct {
+    char* hw_version;
+    char* sw_version;
+    char* manufacturer;
+} M100ModuleInfo;
+
+typedef enum {
+    WA_CHINA_900 = 1,   // Freq_CH-920.125M
+    WA_US,              // Freq_CH-902.25M
+    WA_EU,              // Freq_CH-865.1M
+    WA_CHINA_800,       // Freq_CH-840.125M
+    WA_KOREA = 6        // Freq_CH-917.1M
+} WorkingArea;
+
+typedef enum {
+    WC_CHINA_900 = 1,   // CH_Index(CN,900MHz) = (Freq_CH-920.125M)/0.25M
+    WC_US,              // CH_Index(US) = (Freq_CH-902.25M)/0.5M
+    WC_EU,              // CH_Index(EU) = (Freq_CH-865.1M)/0.2M
+    WC_CHINA_800,       // CH_Index(CN,800MHz) = (Freq_CH-840.125M)/0.25M
+    WC_KOREA = 6        // CH_Index(Korea) = (Freq_CH-917.1M)/0.2M
+} WorkingChannel;
+
+typedef enum {
+    M100Success,
+    M100ValidationFail,
+    M100NoTagResponse,
+    M100MemoryOverrun
+} M100ResponseType;
+
+typedef struct {
+    M100ModuleInfo* info;
+    uint16_t baudrate;
+    WorkingArea area;
+    WorkingChannel channel;
+    uint16_t transmitting_power;
+    bool freq_hopping;
+    Buffer* buf;
+} M100Module;
+
+M100ModuleInfo* m100_module_info_alloc();
+void m100_module_info_free(M100ModuleInfo* module_info);
+
+M100Module* m100_module_alloc();
+void m100_module_free(M100Module* module);
+uint16_t crc16_genibus(const uint8_t* data, size_t length);
+uint8_t checksum(const uint8_t* data, size_t length);
+
+// Function prototypes
+char* m100_get_hardware_version(M100Module* module);
+char* m100_get_software_version(M100Module* module);
+char* m100_get_manufacturers(M100Module* module);
+
+void m100_set_baudrate(M100Module* module, uint16_t baudrate);
+bool m100_set_working_area(M100Module* module, WorkingArea area);
+bool m100_set_working_channel(M100Module* module, WorkingChannel channel);
+bool m100_set_transmitting_power(M100Module* module, uint16_t power);
+bool m100_set_freq_hopping(M100Module* module, bool hopping);
+
+// gen2 cmds
+M100ResponseType m100_send_single_poll(M100Module* module, UHFTag* uhf_tag);
+M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag);
+M100ResponseType m100_read_label_data_storage(
+    M100Module* module,
+    UHFTag* uhf_tag,
+    BankType bank,
+    uint32_t access_pwd,
+    uint16_t word_count);
+
+M100ResponseType m100_write_label_data_storage(
+    M100Module* module,
+    UHFTag* saved_tag,
+    UHFTag* selected_tag,
+    BankType bank,
+    uint16_t source_address,
+    uint32_t access_pwd);

+ 48 - 0
uhf_module_cmd.h

@@ -0,0 +1,48 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct {
+    const uint8_t* cmd;
+    size_t length;
+} Command;
+
+// Define the command data arrays
+static const uint8_t CMD_HW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, 0x7E};
+static const uint8_t CMD_SW_VERSION_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x01, 0x05, 0x7E};
+static const uint8_t CMD_MANUFACTURERS_DATA[] = {0xBB, 0x00, 0x03, 0x00, 0x01, 0x02, 0x06, 0x7E};
+static const uint8_t CMD_SINGLE_POLLING_DATA[] = {0xBB, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7E};
+static const uint8_t CMD_MULTIPLE_POLLING_DATA[] = {0xBB, 0x00, 0x27, 0x00, 0x03, 0x22, 0x27, 0x10, 0x83, 0x7E};
+static const uint8_t CMD_STOP_MULTIPLE_POLLING_DATA[] = {0xBB, 0x00, 0x28, 0x00, 0x00, 0x28, 0x7E};
+static const uint8_t CMD_SET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0C, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x20, 0x60, 0x00, 0x30, 0x75, 0x1F, 0xEB, 0x70, 0x5C, 0x59, 0x04, 0xE3, 0xD5, 0x0D, 0x70, 0xAD, 0x7E};
+static const uint8_t CMD_GET_SELECT_PARAMETER_DATA[] = {0xBB, 0x00, 0x0B, 0x00, 0x00, 0x0B, 0x7E};
+static const uint8_t CMD_SET_SELECT_MODE_DATA[] = {0xBB, 0x00, 0x12, 0x00, 0x01, 0x01, 0x14, 0x7E};
+static const uint8_t CMD_READ_LABEL_DATA_STORAGE_AREA_DATA[] = {0xBB, 0x00, 0x39, 0x00, 0x09, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x45, 0x7E};
+static const uint8_t CMD_WRITE_LABEL_DATA_STORE_DATA[] = {0xBB, 0x00, 0x49, 0x00, 0x0D, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, 0x6D, 0x7E};
+static const uint8_t CMD_LOCK_LABEL_DATA_STORE_DATA[] = {0xBB, 0x00, 0x82, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0x80, 0x09, 0x7E};
+static const uint8_t CMD_INACTIVATE_KILL_TAG_DATA[] = {0xBB, 0x00, 0x65, 0x00, 0x04, 0x00, 0x00, 0xFF, 0xFF, 0x67, 0x7E};
+static const uint8_t CMD_SET_COMMUNICATION_BAUD_RATE_DATA[] = {0xBB, 0x00, 0x11, 0x00, 0x02, 0x00, 0xC0, 0xD3, 0x7E};
+static const uint8_t CMD_GET_QUERY_PARAMETERS_DATA[] = {0xBB, 0x00, 0x0D, 0x00, 0x00, 0x0D, 0x7E};
+static const uint8_t CMD_SET_QUERY_PARAMETER_DATA[] = {0xBB, 0x00, 0x0E, 0x00, 0x02, 0x10, 0x20, 0x40, 0x7E};
+static const uint8_t CMD_SET_WORK_AREA_DATA[] = {0xBB, 0x00, 0x07, 0x00, 0x01, 0x01, 0x09, 0x7E};
+
+
+// Define the Command structs
+static const Command CMD_HW_VERSION = {CMD_HW_VERSION_DATA, sizeof(CMD_HW_VERSION_DATA)};
+static const Command CMD_SW_VERSION = {CMD_SW_VERSION_DATA, sizeof(CMD_SW_VERSION_DATA)};
+static const Command CMD_MANUFACTURERS = {CMD_MANUFACTURERS_DATA, sizeof(CMD_MANUFACTURERS_DATA)};
+static const Command CMD_SINGLE_POLLING = {CMD_SINGLE_POLLING_DATA, sizeof(CMD_SINGLE_POLLING_DATA)};
+static const Command CMD_MULTIPLE_POLLING = {CMD_MULTIPLE_POLLING_DATA, sizeof(CMD_MULTIPLE_POLLING_DATA)};
+static const Command CMD_STOP_MULTIPLE_POLLING = {CMD_STOP_MULTIPLE_POLLING_DATA, sizeof(CMD_STOP_MULTIPLE_POLLING_DATA)};
+static const Command CMD_SET_SELECT_PARAMETER = {CMD_SET_SELECT_PARAMETER_DATA, sizeof(CMD_SET_SELECT_PARAMETER_DATA)};
+static const Command CMD_GET_SELECT_PARAMETER = {CMD_GET_SELECT_PARAMETER_DATA, sizeof(CMD_GET_SELECT_PARAMETER_DATA)};
+static const Command CMD_SET_SELECT_MODE = {CMD_SET_SELECT_MODE_DATA, sizeof(CMD_SET_SELECT_MODE_DATA)};
+static const Command CMD_READ_LABEL_DATA_STORAGE_AREA = {CMD_READ_LABEL_DATA_STORAGE_AREA_DATA, sizeof(CMD_READ_LABEL_DATA_STORAGE_AREA_DATA)};
+static const Command CMD_WRITE_LABEL_DATA_STORE = {CMD_WRITE_LABEL_DATA_STORE_DATA, sizeof(CMD_WRITE_LABEL_DATA_STORE_DATA)};
+static const Command CMD_LOCK_LABEL_DATA_STORE = {CMD_LOCK_LABEL_DATA_STORE_DATA, sizeof(CMD_LOCK_LABEL_DATA_STORE_DATA)};
+static const Command CMD_INACTIVATE_KILL_TAG = {CMD_INACTIVATE_KILL_TAG_DATA, sizeof(CMD_INACTIVATE_KILL_TAG_DATA)};
+static const Command CMD_SET_COMMUNICATION_BAUD_RATE = {CMD_SET_COMMUNICATION_BAUD_RATE_DATA, sizeof(CMD_SET_COMMUNICATION_BAUD_RATE_DATA)};
+static const Command CMD_GET_QUERY_PARAMETERS = {CMD_GET_QUERY_PARAMETERS_DATA, sizeof(CMD_GET_QUERY_PARAMETERS_DATA)};
+static const Command CMD_SET_QUERY_PARAMETER = {CMD_SET_QUERY_PARAMETER_DATA, sizeof(CMD_SET_QUERY_PARAMETER_DATA)};
+static const Command CMD_SET_WORK_AREA = {CMD_SET_WORK_AREA_DATA, sizeof(CMD_SET_WORK_AREA_DATA)};

+ 116 - 0
uhf_tag.c

@@ -0,0 +1,116 @@
+#include "uhf_tag.h"
+#include <stdlib.h>
+#include <string.h>
+
+UHFTagWrapper* uhf_tag_wrapper_alloc() {
+    UHFTagWrapper* uhf_tag_wrapper = (UHFTagWrapper*)malloc(sizeof(UHFTagWrapper));
+    uhf_tag_wrapper->uhf_tag = NULL;
+    return uhf_tag_wrapper;
+}
+
+void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag) {
+    if(uhf_tag_wrapper->uhf_tag != NULL) {
+        uhf_tag_free(uhf_tag_wrapper->uhf_tag);
+    }
+    uhf_tag_wrapper->uhf_tag = uhf_tag;
+}
+
+void uhf_tag_wrapper_free(UHFTagWrapper* uhf_tag_wrapper) {
+    uhf_tag_free(uhf_tag_wrapper->uhf_tag);
+    free(uhf_tag_wrapper);
+}
+
+UHFTag* uhf_tag_alloc() {
+    UHFTag* uhf_tag = (UHFTag*)malloc(sizeof(UHFTag));
+    uhf_tag->reserved = (ReservedMemoryBank*)malloc(sizeof(ReservedMemoryBank));
+    uhf_tag->epc = (EPCMemoryBank*)malloc(sizeof(EPCMemoryBank));
+    uhf_tag->tid = (TIDMemoryBank*)malloc(sizeof(TIDMemoryBank));
+    uhf_tag->user = (UserMemoryBank*)malloc(sizeof(UserMemoryBank));
+    return uhf_tag;
+}
+
+void uhf_tag_reset(UHFTag* uhf_tag) {
+    uhf_tag->epc->crc = 0;
+    uhf_tag->epc->pc = 0;
+    uhf_tag->epc->size = 0;
+    uhf_tag->tid->size = 0;
+    uhf_tag->user->size = 0;
+}
+
+void uhf_tag_free(UHFTag* uhf_tag) {
+    if(uhf_tag == NULL) return;
+    free(uhf_tag->reserved);
+    free(uhf_tag->epc);
+    free(uhf_tag->tid);
+    free(uhf_tag->user);
+    free(uhf_tag);
+}
+
+void uhf_tag_set_epc_pc(UHFTag* uhf_tag, uint16_t pc) {
+    uhf_tag->epc->pc = pc;
+}
+
+void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc) {
+    uhf_tag->epc->crc = crc;
+}
+
+void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
+    memcpy(uhf_tag->epc->data, data_in, size);
+    uhf_tag->epc->size = size;
+}
+
+void uhf_tag_set_epc_size(UHFTag* uhf_tag, size_t size) {
+    uhf_tag->epc->size = size;
+}
+
+void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
+    memcpy(uhf_tag->tid->data, data_in, size);
+    uhf_tag->tid->size = size;
+}
+
+void uhf_tag_set_tid_size(UHFTag* uhf_tag, size_t size) {
+    uhf_tag->tid->size = size;
+}
+
+void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
+    memcpy(uhf_tag->user->data, data_in, size);
+    uhf_tag->user->size = size;
+}
+
+void uhf_tag_set_user_size(UHFTag* uhf_tag, size_t size) {
+    uhf_tag->user->size = size;
+}
+
+// getters
+
+uint8_t* uhf_tag_get_epc(UHFTag* uhf_tag) {
+    return uhf_tag->epc->data;
+}
+
+size_t uhf_tag_get_epc_size(UHFTag* uhf_tag) {
+    return uhf_tag->epc->size;
+}
+
+uint16_t uhf_tag_get_epc_pc(UHFTag* uhf_tag) {
+    return uhf_tag->epc->pc;
+}
+
+uint16_t uhf_tag_get_epc_crc(UHFTag* uhf_tag) {
+    return uhf_tag->epc->crc;
+}
+
+uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag) {
+    return uhf_tag->tid->data;
+}
+
+size_t uhf_tag_get_tid_size(UHFTag* uhf_tag) {
+    return uhf_tag->tid->size;
+}
+
+uint8_t* uhf_tag_get_user(UHFTag* uhf_tag) {
+    return uhf_tag->user->data;
+}
+
+size_t uhf_tag_get_user_size(UHFTag* uhf_tag) {
+    return uhf_tag->user->size;
+}

+ 79 - 0
uhf_tag.h

@@ -0,0 +1,79 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+// storage enum
+typedef enum { ReservedBank, EPCBank, TIDBank, UserBank } BankType;
+
+// Reserved Memory Bank
+typedef struct {
+    uint8_t kill_password[2]; // 2 bytes (16 bits) for kill password
+    uint8_t access_password[2]; // 2 bytes (16 bits) for access password
+} ReservedMemoryBank;
+
+// EPC Memory Bank
+typedef struct {
+    size_t size; // Size of EPC memory data
+    uint8_t data[18]; // 2 bytes for CRC16, 2 bytes for PC, and max 14 bytes for EPC
+    uint16_t pc;
+    uint16_t crc;
+} EPCMemoryBank;
+
+// TID Memory Bank
+typedef struct {
+    size_t size; // Size of TID memory data
+    uint8_t data[16]; // 4 bytes for Class ID and max 12 bytes for TID data
+} TIDMemoryBank;
+
+// User Memory Bank
+typedef struct {
+    size_t size; // Size of user memory data
+    uint8_t data[64]; // Assuming max 512 bits (64 bytes) for User Memory
+} UserMemoryBank;
+
+// EPC Gen 2 Tag containing all memory banks
+typedef struct {
+    ReservedMemoryBank* reserved;
+    EPCMemoryBank* epc;
+    TIDMemoryBank* tid;
+    UserMemoryBank* user;
+} UHFTag;
+
+typedef struct UHFTagWrapper {
+    UHFTag* uhf_tag;
+} UHFTagWrapper;
+
+UHFTagWrapper* uhf_tag_wrapper_alloc();
+void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag);
+void uhf_tag_wrapper_free(UHFTagWrapper* uhf_tag_wrapper);
+
+UHFTag* uhf_tag_alloc();
+void uhf_tag_reset(UHFTag* uhf_tag);
+void uhf_tag_free(UHFTag* uhf_tag);
+
+void uhf_tag_set_kill_pwd(UHFTag* uhf_tag, uint8_t* data_in);
+void uhf_tag_set_access_pwd(UHFTag* uhf_tag, uint8_t* data_in);
+void uhf_tag_set_epc_pc(UHFTag* uhf_tag, uint16_t pc);
+void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc);
+void uhf_tag_set_epc(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
+void uhf_tag_set_epc_size(UHFTag* uhf_tag, size_t size);
+void uhf_tag_set_tid(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
+void uhf_tag_set_tid_size(UHFTag* uhf_tag, size_t size);
+void uhf_tag_set_user(UHFTag* uhf_tag, uint8_t* data_in, size_t size);
+void uhf_tag_set_user_size(UHFTag* uhf_tag, size_t size);
+
+uint8_t* uhf_tag_get_kill_pwd(UHFTag* uhf_tag);
+uint8_t* uhf_tag_get_access_pwd(UHFTag* uhf_tag);
+uint8_t* uhf_tag_get_epc(UHFTag* uhf_tag);
+uint16_t uhf_tag_get_epc_pc(UHFTag* uhf_tag);
+uint16_t uhf_tag_get_epc_crc(UHFTag* uhf_tag);
+size_t uhf_tag_get_epc_size(UHFTag* uhf_tag);
+uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag);
+size_t uhf_tag_get_tid_size(UHFTag* uhf_tag);
+uint8_t* uhf_tag_get_user(UHFTag* uhf_tag);
+size_t uhf_tag_get_user_size(UHFTag* uhf_tag);
+
+// debug
+char* uhf_tag_get_cstr(UHFTag* uhf_tag);

+ 70 - 186
uhf_worker.c

@@ -1,203 +1,85 @@
 #include "uhf_worker.h"
-#include "uhf_cmd.h"
-
-#define CB_DELAY 50
-
-// uart callback functions
-void module_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
-    UNUSED(event);
-    UHFData* uhf_data = ctx;
-    uhf_data_append(uhf_data, data);
-}
+#include "uhf_tag.h"
 
 // yrm100 module commands
 UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) {
-    UHFResponseData* uhf_response_data = uhf_worker->response_data;
-    uhf_response_data_reset(uhf_response_data);
-    // FURI_LOG_E("log", "freeing done");
-    UHFData* hardware_version = uhf_response_data->head;
-    UHFData* software_version = uhf_response_data_add_new_uhf_data(uhf_response_data);
-    UHFData* manufacturer = uhf_response_data_add_new_uhf_data(uhf_response_data);
-    // FURI_LOG_E("log", "alloc done");
-    furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUD_RATE);
-    // read hardware version
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, hardware_version);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_HARDWARE_VERSION.cmd, CMD_HARDWARE_VERSION.length);
-    furi_delay_ms(CB_DELAY);
-    // read software version
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, software_version);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_SOFTWARE_VERSION.cmd, CMD_SOFTWARE_VERSION.length);
-    furi_delay_ms(CB_DELAY);
-    // read manufacturer
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, manufacturer);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_MANUFACTURERS.cmd, CMD_MANUFACTURERS.length);
-    furi_delay_ms(CB_DELAY);
-    // verify that we received all data
-    if(!hardware_version->end || !software_version->end || !manufacturer->end) {
-        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;
-
+    char* hw_version = m100_get_hardware_version(uhf_worker->module);
+    char* sw_version = m100_get_software_version(uhf_worker->module);
+    char* manufacturer = m100_get_manufacturers(uhf_worker->module);
+    // verify all data exists
+    if(hw_version == NULL || sw_version == NULL || manufacturer == NULL) return UHFWorkerEventFail;
     return UHFWorkerEventSuccess;
 }
 
-static uint8_t get_epc_length_in_bits(uint8_t pc) {
-    uint8_t epc_length = pc;
-    epc_length >>= 3;
-    return (uint8_t)epc_length * 16; // x-words * 16 bits
-}
-
-static bool send_set_select_command(UHFData* selected_tag, UHFBank bank) {
-    bool success = false;
-    // Set select
-    UHFData* select_cmd = uhf_data_alloc();
-    select_cmd->start = true;
-    select_cmd->length = CMD_SET_SELECT_PARAMETER.length;
-    memcpy((void*)&select_cmd->data, (void*)&CMD_SET_SELECT_PARAMETER.cmd[0], select_cmd->length);
-    // set select param
-    size_t mask_length_bits = (size_t)get_epc_length_in_bits(selected_tag->data[6]);
-    size_t mask_length_bytes = (size_t)mask_length_bits / 8;
-    select_cmd->data[5] = bank; // 0x00=rfu, 0x01=epc, 0x10=tid, 0x11=user
-    // set ptr
-    select_cmd->data[9] = 0x20; // epc data begins after 0x20
-    // set mask length
-    select_cmd->data[10] = mask_length_bits;
-    // set mask starting position
-    select_cmd->length = 12;
-    // set mask
-    for(size_t i = 0; i < mask_length_bytes; i++) {
-        uhf_data_append(select_cmd, selected_tag->data[8 + i]);
-    }
-    uhf_data_append(select_cmd, 0x00); // add checksum section
-    uhf_data_append(select_cmd, FRAME_END); // command end
-    // add checksum
-    select_cmd->data[select_cmd->length - 2] = uhf_data_calculate_checksum(select_cmd);
-    UHFData* select_response = uhf_data_alloc();
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, select_response);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, select_cmd->data, select_cmd->length);
-    furi_delay_ms(CB_DELAY);
-
-    success = select_response->data[5] == 0x00;
-
-    uhf_data_free(select_cmd);
-    uhf_data_free(select_response);
-
-    return success;
-}
-
-static bool read_bank(UHFData* read_bank_cmd, UHFData* response_bank, UHFBank bank) {
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, response_bank);
-    read_bank_cmd->data[9] = bank;
-    read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
-    uhf_data_reset(response_bank);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
-    furi_delay_ms(CB_DELAY);
-    return response_bank->data[2] == read_bank_cmd->data[2];
-}
-
-UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
-    // debug
-    // FuriString* temp_str;
-    // temp_str = furi_string_alloc();
-    // e-debug
-    UHFResponseData* uhf_response_data = uhf_worker->response_data;
-    uhf_response_data_reset(uhf_response_data);
-    UHFData* raw_read_data = uhf_response_data_get_uhf_data(uhf_response_data, 0);
-    furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUD_RATE);
-    furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, raw_read_data);
-    uhf_data_reset(raw_read_data);
+UHFTag* send_polling_command(UHFWorker* uhf_worker) {
     // read epc bank
+    UHFTag* uhf_tag = uhf_tag_alloc();
     while(true) {
-        furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_SINGLE_POLLING.cmd, CMD_SINGLE_POLLING.length);
+        M100ResponseType status = m100_send_single_poll(uhf_worker->module, uhf_tag);
         furi_delay_ms(100);
         if(uhf_worker->state == UHFWorkerStateStop) {
-            return UHFWorkerEventAborted;
-        }
-        if(raw_read_data->end) {
-            if(raw_read_data->data[1] == 0x01 && raw_read_data->data[5] == 0x15) {
-                uhf_data_reset(raw_read_data);
-                continue;
-            } else if(raw_read_data->data[1] == 0x02)
-                break; // read success
+            uhf_tag_free(uhf_tag);
+            return NULL;
         }
+        if(status == M100Success) break;
     }
+    return uhf_tag;
+}
 
-    // todo : rfu ?
-    UHFTag* uhf_tag = uhf_worker->uhf_tag;
-    uhf_tag_reset(uhf_tag);
-
-    // add to tag object
-    UHFData* raw_bank_data = uhf_data_alloc();
-    size_t epc_length = (size_t)get_epc_length_in_bits(raw_read_data->data[6]) / 8;
-    size_t offset = (size_t)(8 + epc_length);
-
-    UHFData* read_bank_cmd = uhf_data_alloc();
-    read_bank_cmd->length = CMD_READ_LABEL_DATA_STORAGE.length;
-    memcpy(
-        (void*)&read_bank_cmd->data[0],
-        (void*)&CMD_READ_LABEL_DATA_STORAGE.cmd[0],
-        read_bank_cmd->length);
-
-    if(!send_set_select_command(raw_read_data, EPC_BANK)) return UHFWorkerEventFail;
-
-    int retry = 3;
+static UHFWorkerEvent
+    read_bank_till_max_length(UHFWorker* uhf_worker, UHFTag* uhf_tag, BankType bank) {
+    unsigned int retry = 3, word_low = 5, word_high = 100;
+    unsigned int word_size;
+    M100ResponseType status;
     do {
-        if(read_bank(read_bank_cmd, raw_bank_data, EPC_BANK)) {
-            uhf_tag_set_epc(uhf_tag, raw_bank_data->data + offset, epc_length + 2);
-            FURI_LOG_E("TAG", "epc read");
-            break;
+        if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
+        if(word_low >= word_high) return UHFWorkerEventSuccess;
+        word_size = (word_low + word_high) / 2;
+        status = m100_read_label_data_storage(uhf_worker->module, uhf_tag, bank, 0, word_size);
+        if(status == M100Success) {
+            word_low = word_size + 1;
+        } else if(status == M100MemoryOverrun) {
+            word_high = word_size - 1;
+        } else if(status == M100NoTagResponse) {
+            retry--;
         }
+    } while(retry);
+    return UHFWorkerEventSuccess;
+}
 
-    } while(retry--);
-    // // debug
-    // furi_string_reset(temp_str);
-    // for(size_t i = 0; i < raw_bank_data->length; i++) {
-    //     furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
-    // }
-    // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
-    // // e-debug
-    uhf_data_reset(raw_bank_data);
-    retry = 3;
-    do {
-        if(read_bank(read_bank_cmd, raw_bank_data, TID_BANK)) {
-            uhf_tag_set_tid(uhf_tag, raw_bank_data->data + offset, 16);
-            break;
-        }
-    } while(retry--);
-    // // debug
-    // furi_string_reset(temp_str);
-    // for(size_t i = 0; i < raw_bank_data->length; i++) {
-    //     furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
-    // }
-    // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
-    // // e-debug
-    uhf_data_reset(raw_bank_data);
-    retry = 3;
-    if(raw_read_data->data[6] & 0x04) {
-        do {
-            if(read_bank(read_bank_cmd, raw_bank_data, USER_BANK)) {
-                uhf_tag_set_user(uhf_tag, raw_bank_data->data + offset, 16);
-                break;
-            }
-        } while(retry--);
-    }
-    // // debug
-    // furi_string_reset(temp_str);
-    // for(size_t i = 0; i < raw_bank_data->length; i++) {
-    //     furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
-    // }
-    // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
-    // // e-debug
-    uhf_data_reset(raw_bank_data);
-    uhf_data_free(raw_bank_data);
-    uhf_data_free(read_bank_cmd);
-    // debug
-    // furi_string_free(temp_str);
-    // e-debug
+UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
+    UHFTag* uhf_tag = send_polling_command(uhf_worker);
+    if(uhf_tag == NULL) return UHFWorkerEventAborted;
+    uhf_tag_wrapper_set_tag(uhf_worker->uhf_tag_wrapper, uhf_tag);
+    // Todo : set select here
+    if(m100_set_select(uhf_worker->module, uhf_tag) != M100Success) return UHFWorkerEventFail;
+    // read tid
+    UHFWorkerEvent event;
+    event = read_bank_till_max_length(uhf_worker, uhf_tag, TIDBank);
+    if(event != UHFWorkerEventSuccess) return event;
+    // read user
+    event = read_bank_till_max_length(uhf_worker, uhf_tag, UserBank);
+    if(event != UHFWorkerEventSuccess) return event;
+    return UHFWorkerEventSuccess;
+}
 
+UHFWorkerEvent write_single_card(UHFWorker* uhf_worker) {
+    UHFTag* uhf_tag_des = send_polling_command(uhf_worker);
+    if(uhf_tag_des == NULL) return UHFWorkerEventAborted;
+    UHFTag* uhf_tag_from = uhf_worker->uhf_tag_wrapper->uhf_tag;
+    if(m100_set_select(uhf_worker->module, uhf_tag_des) != M100Success) return UHFWorkerEventFail;
+    do {
+        M100ResponseType rp_type = m100_write_label_data_storage(
+            uhf_worker->module, uhf_tag_from, uhf_tag_des, UserBank, 0, 0);
+        if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
+        if(rp_type == M100Success) break;
+    } while(true);
+    do {
+        M100ResponseType rp_type = m100_write_label_data_storage(
+            uhf_worker->module, uhf_tag_from, uhf_tag_des, EPCBank, 0, 0);
+        if(uhf_worker->state == UHFWorkerStateStop) return UHFWorkerEventAborted;
+        if(rp_type == M100Success) break;
+    } while(true);
     return UHFWorkerEventSuccess;
 }
 
@@ -206,10 +88,12 @@ int32_t uhf_worker_task(void* ctx) {
     if(uhf_worker->state == UHFWorkerStateVerify) {
         UHFWorkerEvent event = verify_module_connected(uhf_worker);
         uhf_worker->callback(event, uhf_worker->ctx);
-    }
-    if(uhf_worker->state == UHFWorkerStateDetectSingle) {
+    } else if(uhf_worker->state == UHFWorkerStateDetectSingle) {
         UHFWorkerEvent event = read_single_card(uhf_worker);
         uhf_worker->callback(event, uhf_worker->ctx);
+    } else if(uhf_worker->state == UHFWorkerStateWriteSingle) {
+        UHFWorkerEvent event = write_single_card(uhf_worker);
+        uhf_worker->callback(event, uhf_worker->ctx);
     }
     return 0;
 }
@@ -217,7 +101,7 @@ int32_t uhf_worker_task(void* ctx) {
 UHFWorker* uhf_worker_alloc() {
     UHFWorker* uhf_worker = (UHFWorker*)malloc(sizeof(UHFWorker));
     uhf_worker->thread = furi_thread_alloc_ex("UHFWorker", 8 * 1024, uhf_worker_task, uhf_worker);
-    uhf_worker->response_data = uhf_response_data_alloc();
+    uhf_worker->module = m100_module_alloc();
     uhf_worker->callback = NULL;
     uhf_worker->ctx = NULL;
     return uhf_worker;
@@ -251,6 +135,6 @@ void uhf_worker_stop(UHFWorker* uhf_worker) {
 void uhf_worker_free(UHFWorker* uhf_worker) {
     furi_assert(uhf_worker);
     furi_thread_free(uhf_worker->thread);
-    uhf_response_data_free(uhf_worker->response_data);
+    m100_module_free(uhf_worker->module);
     free(uhf_worker);
 }

+ 3 - 3
uhf_worker.h

@@ -2,7 +2,7 @@
 
 #include <furi.h>
 #include <furi_hal.h>
-#include "uhf_data.h"
+#include "uhf_module.h"
 
 typedef enum {
     // Init states
@@ -30,10 +30,10 @@ typedef void (*UHFWorkerCallback)(UHFWorkerEvent event, void* ctx);
 
 typedef struct UHFWorker {
     FuriThread* thread;
-    UHFResponseData* response_data;
-    UHFTag* uhf_tag;
+    M100Module* module;
     UHFWorkerCallback callback;
     UHFWorkerState state;
+    UHFTagWrapper* uhf_tag_wrapper;
     void* ctx;
 } UHFWorker;