MX 2 лет назад
Родитель
Сommit
0e6e3e4757
16 измененных файлов с 372 добавлено и 339 удалено
  1. 24 84
      README.md
  2. 2 2
      application.fam
  3. BIN
      assets/img/uhf_demo_app.jpg
  4. BIN
      assets/img/uhf_demo_app2.jpg
  5. 0 0
      icons/uhf_10px.png
  6. 1 1
      scenes/uhf_scene_device_info.c
  7. 0 1
      scenes/uhf_scene_read_tag.c
  8. 5 3
      scenes/uhf_scene_verify.c
  9. 3 1
      uhf_app.c
  10. 36 16
      uhf_device.c
  11. 2 11
      uhf_device.h
  12. 142 37
      uhf_module.c
  13. 38 19
      uhf_module.h
  14. 59 0
      uhf_tag.c
  15. 5 0
      uhf_tag.h
  16. 55 164
      uhf_worker.c

+ 24 - 84
README.md

@@ -1,21 +1,34 @@
 # [UHF]RFID App for FlipperZero
 # [UHF]RFID App for FlipperZero
 
 
-![FlipperZero](assets/img/uhf_demo_app.jpg)
+![FlipperZero](assets/img/uhf_demo_app2.jpg)
 
 
 ## Overview
 ## 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.
 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.
+- Icon added by [@xMasterX](https://github.com/xMasterX)
+- App is now named `[(Q)M100] UHF RFID`, meaning for M100 and QM100 modules
+
 ## Features
 ## Features
 
 
 - [x] Read Single UHF RFID tag.
 - [x] Read Single UHF RFID tag.
 - [x] View saved 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
 ## Requirements
 
 
@@ -43,88 +56,12 @@ To run this application on FlipperZero, you will need:
 2. Connect the uhf module to the flipper via gpio.
 2. Connect the uhf module to the flipper via gpio.
 3. Navigate to the UHF RFID app on FlipperZero's menu.
 3. Navigate to the UHF RFID app on FlipperZero's menu.
 4. Currently Reading the EPC tag is the only usable option
 4. Currently Reading the EPC tag is the only usable option
-... will further update this page as it development goes
+   ... will further update this page as it development goes
 
 
 ## Contributions
 ## Contributions
 
 
 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.
 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
 ## Disclaimer
 
 
 - This application is provided as-is and may contain bugs or issues.
 - This application is provided as-is and may contain bugs or issues.
@@ -134,6 +71,9 @@ typedef struct {
 ## Extra Resources
 ## Extra Resources
 
 
 - [MagicRF M100&QM100_Firmware_manual_en.pdf](assets/res/MagicRF_M100&QM100_Firmware_manual_en.pdf)
 - [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)
+- [MagicRF Chip DS](http://www.magicrf.com/product_en.htm)
 
 
 ## Contact
 ## Contact
 
 

+ 2 - 2
application.fam

@@ -1,6 +1,6 @@
 App(
 App(
     appid="uhf_rfid",
     appid="uhf_rfid",
-    name="[YRM100] UHF RFID",
+    name="[(Q)M100] UHF RFID",
     apptype=FlipperAppType.EXTERNAL,
     apptype=FlipperAppType.EXTERNAL,
     targets=["f7"],
     targets=["f7"],
     entry_point="uhf_app_main",
     entry_point="uhf_app_main",
@@ -10,7 +10,7 @@ App(
     ],
     ],
     stack_size=4 * 1024,
     stack_size=4 * 1024,
     order=30,
     order=30,
-    fap_icon="uhf_10px.png",
+    fap_icon="icons/uhf_10px.png",
     fap_category="RFID",
     fap_category="RFID",
     fap_icon_assets="icons",
     fap_icon_assets="icons",
     fap_icon_assets_symbol="uhf_rfid",
     fap_icon_assets_symbol="uhf_rfid",

BIN
assets/img/uhf_demo_app.jpg


BIN
assets/img/uhf_demo_app2.jpg


+ 0 - 0
uhf_10px.png → icons/uhf_10px.png


+ 1 - 1
scenes/uhf_scene_device_info.c

@@ -81,7 +81,7 @@ void change_view_on_event(UHFApp* uhf_app) {
         furi_string_get_cstr(furi_temp_str));
         furi_string_get_cstr(furi_temp_str));
 
 
     widget_add_string_multiline_element(
     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(
     widget_add_button_element(
         uhf_app->widget,
         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);
     uhf_worker_stop(uhf_app->worker);
     // Clear view
     // Clear view
     popup_reset(uhf_app->popup);
     popup_reset(uhf_app->popup);
-
     uhf_blink_stop(uhf_app);
     uhf_blink_stop(uhf_app);
 }
 }

+ 5 - 3
scenes/uhf_scene_verify.c

@@ -42,6 +42,10 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                 widget_reset(uhf_app->widget);
                 widget_reset(uhf_app->widget);
                 furi_string_reset(temp_str);
                 furi_string_reset(temp_str);
                 uhf_worker_stop(uhf_app->worker);
                 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_worker_start(
                     uhf_app->worker,
                     uhf_app->worker,
                     UHFWorkerStateVerify,
                     UHFWorkerStateVerify,
@@ -113,7 +117,7 @@ bool uhf_scene_verify_on_event(void* ctx, SceneManagerEvent event) {
                     AlignCenter,
                     AlignCenter,
                     AlignCenter,
                     AlignCenter,
                     FontSecondary,
                     FontSecondary,
-                    "Please connect your module.\nPlease refer to the git@frux-c/uhf_rfid for help.");
+                    "Please refer to the git@frux-c/uhf_rfid for help.");
                 widget_add_button_element(
                 widget_add_button_element(
                     uhf_app->widget,
                     uhf_app->widget,
                     GuiButtonTypeLeft,
                     GuiButtonTypeLeft,
@@ -138,8 +142,6 @@ void uhf_scene_verify_on_exit(void* ctx) {
     furi_string_free(temp_str);
     furi_string_free(temp_str);
     // Stop worker
     // Stop worker
     uhf_worker_stop(uhf_app->worker);
     uhf_worker_stop(uhf_app->worker);
-    // Clear view
-    // popup_reset(uhf_app->popup);
     // clear widget
     // clear widget
     widget_reset(uhf_app->widget);
     widget_reset(uhf_app->widget);
 }
 }

+ 3 - 1
uhf_app.c

@@ -187,13 +187,15 @@ int32_t uhf_app_main(void* ctx) {
 
 
     // enable 5v pin
     // enable 5v pin
     furi_hal_power_enable_otg();
     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);
     scene_manager_next_scene(uhf_app->scene_manager, UHFSceneVerify);
     view_dispatcher_run(uhf_app->view_dispatcher);
     view_dispatcher_run(uhf_app->view_dispatcher);
 
 
     // disable 5v pin
     // disable 5v pin
     furi_hal_power_disable_otg();
     furi_hal_power_disable_otg();
-
+    // furi_hal_gpio_disable_int_callback()
     // exit app
     // exit app
     uhf_free(uhf_app);
     uhf_free(uhf_app);
     return 0;
     return 0;

+ 36 - 16
uhf_device.c

@@ -55,23 +55,35 @@ static bool uhf_device_save_file(
         // Reserved bank might be added
         // Reserved bank might be added
         // todo : maybe
         // todo : maybe
         uint32_t temp_arr[1];
         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
         // write epc
-        temp_arr[0] = uhf_tag->epc->size;
+        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_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_write_hex(
         if(!flipper_format_write_hex(
-               file, UHF_EPC_BANK_LABEL, uhf_tag->epc->data, uhf_tag->epc->size))
+               file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
             break;
             break;
         // write tid
         // write tid
-        temp_arr[0] = uhf_tag->tid->size;
+        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_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_write_hex(
         if(!flipper_format_write_hex(
-               file, UHF_TID_BANK_LABEL, uhf_tag->tid->data, uhf_tag->tid->size))
+               file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
             break;
             break;
         // write user
         // write user
-        temp_arr[0] = uhf_tag->user->size;
+        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_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_write_hex(
         if(!flipper_format_write_hex(
-               file, UHF_USER_BANK_LABEL, uhf_tag->user->data, uhf_tag->user->size))
+               file,
+               UHF_USER_BANK_LABEL,
+               uhf_tag_get_user(uhf_tag),
+               uhf_tag_get_user_size(uhf_tag)))
             break;
             break;
         saved = true;
         saved = true;
     } while(0);
     } while(0);
@@ -99,7 +111,7 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia
     FuriString* temp_str;
     FuriString* temp_str;
     temp_str = furi_string_alloc();
     temp_str = furi_string_alloc();
     bool deprecated_version = false;
     bool deprecated_version = false;
-    UHFTag* uhf_tag = dev->uhf_tag_wrapper->uhf_tag;
+    UHFTag* uhf_tag = uhf_tag_alloc();
     uhf_tag_reset(uhf_tag);
     uhf_tag_reset(uhf_tag);
     uint32_t temp_arr[1];
     uint32_t temp_arr[1];
     if(dev->loading_cb) {
     if(dev->loading_cb) {
@@ -116,25 +128,34 @@ static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dia
             deprecated_version = true;
             deprecated_version = true;
             break;
             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
         // read epc
         if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->epc->size = temp_arr[0];
+        uhf_tag_set_epc_size(uhf_tag, temp_arr[0]);
         if(!flipper_format_read_hex(
         if(!flipper_format_read_hex(
-               file, UHF_EPC_BANK_LABEL, uhf_tag->epc->data, uhf_tag->epc->size))
+               file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
             break;
             break;
 
 
         // read tid
         // read tid
         if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->tid->size = temp_arr[0];
+        uhf_tag_set_tid_size(uhf_tag, temp_arr[0]);
         if(!flipper_format_read_hex(
         if(!flipper_format_read_hex(
-               file, UHF_TID_BANK_LABEL, uhf_tag->tid->data, uhf_tag->tid->size))
+               file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
             break;
             break;
-
         // read user
         // read user
         if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
         if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
-        uhf_tag->user->size = temp_arr[0];
+        uhf_tag_set_user_size(uhf_tag, temp_arr[0]);
         if(!flipper_format_read_hex(
         if(!flipper_format_read_hex(
-               file, UHF_USER_BANK_LABEL, uhf_tag->user->data, uhf_tag->user->size))
+               file,
+               UHF_USER_BANK_LABEL,
+               uhf_tag_get_user(uhf_tag),
+               uhf_tag_get_user_size(uhf_tag)))
             break;
             break;
 
 
         parsed = true;
         parsed = true;
@@ -151,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");
             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);
     furi_string_free(temp_str);
     flipper_format_free(file);
     flipper_format_free(file);
-
     return parsed;
     return parsed;
 }
 }
 
 

+ 2 - 11
uhf_device.h

@@ -7,21 +7,12 @@
 #include <mbedtls/des.h>
 #include <mbedtls/des.h>
 #include "uhf_tag.h"
 #include "uhf_tag.h"
 
 
-// #include "rfal_picopass.h"
-
 #define UHF_DEV_NAME_MAX_LEN 22
 #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_EPC_BANK_LENGTH_LABEL "EPC_LENGTH"
 #define UHF_TID_BANK_LENGTH_LABEL "TID_LENGTH"
 #define UHF_TID_BANK_LENGTH_LABEL "TID_LENGTH"
 #define UHF_USER_BANK_LENGTH_LABEL "USER_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_RFU_BANK_LABEL "RFU"
 #define UHF_EPC_BANK_LABEL "EPC"
 #define UHF_EPC_BANK_LABEL "EPC"
 #define UHF_TID_BANK_LABEL "TID"
 #define UHF_TID_BANK_LABEL "TID"

+ 142 - 37
uhf_module.c

@@ -1,7 +1,7 @@
 #include "uhf_module.h"
 #include "uhf_module.h"
 #include "uhf_module_cmd.h"
 #include "uhf_module_cmd.h"
 
 
-#define DELAY_MS 50
+#define DELAY_MS 100
 
 
 void rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
 void rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
     UNUSED(event);
     UNUSED(event);
@@ -68,7 +68,10 @@ uint16_t crc16_genibus(const uint8_t* data, size_t length) {
 }
 }
 
 
 char* m100_get_hardware_version(M100Module* module) {
 char* m100_get_hardware_version(M100Module* module) {
-    if(module->info->hw_version != NULL) return module->info->hw_version;
+    if(module->info->hw_version != NULL) {
+        free(module->info->hw_version);
+        module->info->hw_version = NULL;
+    }
     buffer_reset(module->buf);
     buffer_reset(module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, 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_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)&CMD_HW_VERSION.cmd[0], CMD_HW_VERSION.length);
@@ -88,7 +91,10 @@ char* m100_get_hardware_version(M100Module* module) {
     return module->info->hw_version;
     return module->info->hw_version;
 }
 }
 char* m100_get_software_version(M100Module* module) {
 char* m100_get_software_version(M100Module* module) {
-    if(module->info->sw_version != NULL) return module->info->sw_version;
+    if(module->info->sw_version != NULL) {
+        free(module->info->sw_version);
+        module->info->sw_version = NULL;
+    }
     buffer_reset(module->buf);
     buffer_reset(module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, 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_hal_uart_tx(FuriHalUartIdUSART1, (uint8_t*)&CMD_SW_VERSION.cmd[0], CMD_SW_VERSION.length);
@@ -108,7 +114,10 @@ char* m100_get_software_version(M100Module* module) {
     return module->info->sw_version;
     return module->info->sw_version;
 }
 }
 char* m100_get_manufacturers(M100Module* module) {
 char* m100_get_manufacturers(M100Module* module) {
-    if(module->info->manufacturer != NULL) return module->info->manufacturer;
+    if(module->info->manufacturer != NULL) {
+        free(module->info->manufacturer);
+        module->info->manufacturer = NULL;
+    }
     buffer_reset(module->buf);
     buffer_reset(module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
     furi_hal_uart_tx(
     furi_hal_uart_tx(
@@ -129,7 +138,7 @@ char* m100_get_manufacturers(M100Module* module) {
     return module->info->manufacturer;
     return module->info->manufacturer;
 }
 }
 
 
-UHFTag* m100_send_single_poll(M100Module* module) {
+M100ResponseType m100_send_single_poll(M100Module* module, UHFTag* uhf_tag) {
     buffer_reset(module->buf);
     buffer_reset(module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
     furi_hal_uart_tx(
     furi_hal_uart_tx(
@@ -137,7 +146,7 @@ UHFTag* m100_send_single_poll(M100Module* module) {
     furi_delay_ms(DELAY_MS);
     furi_delay_ms(DELAY_MS);
     uint8_t* data = buffer_get_data(module->buf);
     uint8_t* data = buffer_get_data(module->buf);
     size_t length = buffer_get_size(module->buf);
     size_t length = buffer_get_size(module->buf);
-    if(length <= 8 && data[2] == 0xFF) return NULL;
+    if(length <= 8 && data[2] == 0xFF) return M100NoTagResponse;
     uint16_t pc = data[6];
     uint16_t pc = data[6];
     uint16_t crc = 0;
     uint16_t crc = 0;
     // mask out epc length from protocol control
     // mask out epc length from protocol control
@@ -152,26 +161,16 @@ UHFTag* m100_send_single_poll(M100Module* module) {
     crc <<= 8;
     crc <<= 8;
     crc += data[8 + epc_len + 1];
     crc += data[8 + epc_len + 1];
     // validate checksum
     // validate checksum
-    uint8_t cs = checksum(data + 1, length - 3);
-    for(size_t i = 0; i < length; i++){
-        FURI_LOG_E("m100", "data[%d]=%02X", i, data[i]);
-    }
-    if(cs != data[length - 2]) return NULL;
-    FURI_LOG_E("m100", "checksum pass");
+    if(checksum(data + 1, length - 3) != data[length - 2]) return M100ValidationFail;
     // validate crc
     // validate crc
-    uint16_t ccrc = crc16_genibus(data + 6, epc_len + 2);
-    FURI_LOG_E("m100", "crc found = %04X, calculated crc = %04X", crc, ccrc);
-    if(ccrc != crc) return NULL;
-    FURI_LOG_E("m100", "crc pass");
-    UHFTag* uhf_tag = uhf_tag_alloc();
+    if(crc16_genibus(data + 6, epc_len + 2) != crc) return M100ValidationFail;
     uhf_tag_set_epc_pc(uhf_tag, pc);
     uhf_tag_set_epc_pc(uhf_tag, pc);
     uhf_tag_set_epc_crc(uhf_tag, crc);
     uhf_tag_set_epc_crc(uhf_tag, crc);
     uhf_tag_set_epc(uhf_tag, data + 8, epc_len);
     uhf_tag_set_epc(uhf_tag, data + 8, epc_len);
-    FURI_LOG_E("m100", "returning tag");
-    return uhf_tag;
+    return M100Success;
 }
 }
 
 
-bool m100_set_select(M100Module* module, UHFTag* uhf_tag) {
+M100ResponseType m100_set_select(M100Module* module, UHFTag* uhf_tag) {
     buffer_reset(module->buf);
     buffer_reset(module->buf);
     // Set select
     // Set select
     uint8_t cmd[MAX_BUFFER_SIZE];
     uint8_t cmd[MAX_BUFFER_SIZE];
@@ -181,6 +180,8 @@ bool m100_set_select(M100Module* module, UHFTag* uhf_tag) {
     // payload len = sel param len + ptr len + mask len + epc len
     // payload len = sel param len + ptr len + mask len + epc len
     size_t payload_len = 7 + mask_length_bytes;
     size_t payload_len = 7 + mask_length_bytes;
     memcpy(cmd, CMD_SET_SELECT_PARAMETER.cmd, cmd_length);
     memcpy(cmd, CMD_SET_SELECT_PARAMETER.cmd, cmd_length);
+    // set new length
+    cmd_length = 12 + mask_length_bytes + 2;
     // set payload length
     // set payload length
     cmd[3] = (payload_len >> 8) & 0xFF;
     cmd[3] = (payload_len >> 8) & 0xFF;
     cmd[4] = payload_len & 0xFF;
     cmd[4] = payload_len & 0xFF;
@@ -194,36 +195,51 @@ bool m100_set_select(M100Module* module, UHFTag* uhf_tag) {
     cmd[11] = false;
     cmd[11] = false;
     // set mask
     // set mask
     memcpy((void*)&cmd[12], uhf_tag->epc->data, mask_length_bytes);
     memcpy((void*)&cmd[12], uhf_tag->epc->data, mask_length_bytes);
+
     // set checksum
     // set checksum
-    cmd[12 + mask_length_bytes + 1] = checksum(cmd + 1, 11 + mask_length_bytes);
+    cmd[cmd_length - 2] = checksum(cmd + 1, 11 + mask_length_bytes);
     // end frame
     // end frame
-    cmd[12 + mask_length_bytes + 2] = FRAME_END;
+    cmd[cmd_length - 1] = FRAME_END;
     furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
     furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, rx_callback, module->buf);
     furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, 12 + mask_length_bytes + 3);
     furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, 12 + mask_length_bytes + 3);
     furi_delay_ms(DELAY_MS);
     furi_delay_ms(DELAY_MS);
 
 
     uint8_t* data = buffer_get_data(module->buf);
     uint8_t* data = buffer_get_data(module->buf);
-    if(checksum(data + 1, 5) != data[6]) return false; // error in rx
-    if(data[5] != 0x00) return false; // error if not 0
+    if(checksum(data + 1, 5) != data[6]) return M100ValidationFail; // error in rx
+    if(data[5] != 0x00) return M100ValidationFail; // error if not 0
 
 
-    return true;
+    return M100Success;
 }
 }
 
 
-UHFTag* m100_get_select_param(M100Module module) {
-    UNUSED(module);
+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;
     return NULL;
 }
 }
 
 
-bool m100_read_label_data_storage(
+M100ResponseType m100_read_label_data_storage(
     M100Module* module,
     M100Module* module,
     UHFTag* uhf_tag,
     UHFTag* uhf_tag,
     BankType bank,
     BankType bank,
-    uint32_t access_pwd) {
-    UNUSED(uhf_tag);
+    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);
     buffer_reset(module->buf);
     uint8_t cmd[MAX_BUFFER_SIZE];
     uint8_t cmd[MAX_BUFFER_SIZE];
-    size_t length = CMD_READ_LABEL_DATA_STORAGE_AREA.length;
-    memcpy(cmd, CMD_READ_LABEL_DATA_STORAGE_AREA.cmd, length);
+    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
     // set access password
     cmd[5] = (access_pwd >> 24) & 0xFF;
     cmd[5] = (access_pwd >> 24) & 0xFF;
     cmd[6] = (access_pwd >> 16) & 0xFF;
     cmd[6] = (access_pwd >> 16) & 0xFF;
@@ -231,14 +247,104 @@ bool m100_read_label_data_storage(
     cmd[8] = access_pwd & 0xFF;
     cmd[8] = access_pwd & 0xFF;
     // set mem bank
     // set mem bank
     cmd[9] = (uint8_t)bank;
     cmd[9] = (uint8_t)bank;
-    // recalc checksum
-    cmd[length - 2] = checksum(cmd + 1, length - 3);
+    // 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_set_irq_cb(FuriHalUartIdUSART1, rx_callback, module->buf);
-    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
+    furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, cmd_length);
     furi_delay_ms(DELAY_MS);
     furi_delay_ms(DELAY_MS);
-    return true;
+    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) {
 void m100_set_baudrate(M100Module* module, uint16_t baudrate) {
     size_t length = CMD_SET_COMMUNICATION_BAUD_RATE.length;
     size_t length = CMD_SET_COMMUNICATION_BAUD_RATE.length;
     uint8_t cmd[length];
     uint8_t cmd[length];
@@ -246,7 +352,6 @@ void m100_set_baudrate(M100Module* module, uint16_t baudrate) {
     uint16_t br_mod = baudrate / 100; // module format
     uint16_t br_mod = baudrate / 100; // module format
     cmd[6] = 0xFF & br_mod; // pow LSB
     cmd[6] = 0xFF & br_mod; // pow LSB
     cmd[5] = 0xFF & (br_mod >> 4); // pow MSB
     cmd[5] = 0xFF & (br_mod >> 4); // pow MSB
-    // furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL);
     furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
     furi_hal_uart_tx(FuriHalUartIdUSART1, cmd, length);
     furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
     furi_hal_uart_set_br(FuriHalUartIdUSART1, baudrate);
     module->baudrate = baudrate;
     module->baudrate = baudrate;

+ 38 - 19
uhf_module.h

@@ -10,29 +10,36 @@
 #define FRAME_END 0x7E
 #define FRAME_END 0x7E
 #define DEFAULT_BAUDRATE 115200
 #define DEFAULT_BAUDRATE 115200
 
 
-typedef struct{
+typedef struct {
     char* hw_version;
     char* hw_version;
     char* sw_version;
     char* sw_version;
     char* manufacturer;
     char* manufacturer;
-}M100ModuleInfo;
+} 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
+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;
 } 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
+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;
 } WorkingChannel;
 
 
-typedef struct{
+typedef enum {
+    M100Success,
+    M100ValidationFail,
+    M100NoTagResponse,
+    M100MemoryOverrun
+} M100ResponseType;
+
+typedef struct {
     M100ModuleInfo* info;
     M100ModuleInfo* info;
     uint16_t baudrate;
     uint16_t baudrate;
     WorkingArea area;
     WorkingArea area;
@@ -55,7 +62,6 @@ char* m100_get_hardware_version(M100Module* module);
 char* m100_get_software_version(M100Module* module);
 char* m100_get_software_version(M100Module* module);
 char* m100_get_manufacturers(M100Module* module);
 char* m100_get_manufacturers(M100Module* module);
 
 
-// set attrs
 void m100_set_baudrate(M100Module* module, uint16_t baudrate);
 void m100_set_baudrate(M100Module* module, uint16_t baudrate);
 bool m100_set_working_area(M100Module* module, WorkingArea area);
 bool m100_set_working_area(M100Module* module, WorkingArea area);
 bool m100_set_working_channel(M100Module* module, WorkingChannel channel);
 bool m100_set_working_channel(M100Module* module, WorkingChannel channel);
@@ -63,6 +69,19 @@ bool m100_set_transmitting_power(M100Module* module, uint16_t power);
 bool m100_set_freq_hopping(M100Module* module, bool hopping);
 bool m100_set_freq_hopping(M100Module* module, bool hopping);
 
 
 // gen2 cmds
 // gen2 cmds
-UHFTag* m100_send_single_poll(M100Module* module);
-bool m100_set_select(M100Module* module, UHFTag* uhf_tag);
-bool m100_read_label_data_storage(M100Module* module, UHFTag* uhf_tag, BankType bank, uint32_t access_pwd);
+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);

+ 59 - 0
uhf_tag.c

@@ -9,6 +9,9 @@ UHFTagWrapper* uhf_tag_wrapper_alloc() {
 }
 }
 
 
 void uhf_tag_wrapper_set_tag(UHFTagWrapper* uhf_tag_wrapper, UHFTag* uhf_tag) {
 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;
     uhf_tag_wrapper->uhf_tag = uhf_tag;
 }
 }
 
 
@@ -54,4 +57,60 @@ 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(UHFTag* uhf_tag, uint8_t* data_in, size_t size) {
     memcpy(uhf_tag->epc->data, data_in, size);
     memcpy(uhf_tag->epc->data, data_in, size);
     uhf_tag->epc->size = 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;
 }
 }

+ 5 - 0
uhf_tag.h

@@ -58,12 +58,17 @@ 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_pc(UHFTag* uhf_tag, uint16_t pc);
 void uhf_tag_set_epc_crc(UHFTag* uhf_tag, uint16_t crc);
 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(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(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(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_kill_pwd(UHFTag* uhf_tag);
 uint8_t* uhf_tag_get_access_pwd(UHFTag* uhf_tag);
 uint8_t* uhf_tag_get_access_pwd(UHFTag* uhf_tag);
 uint8_t* uhf_tag_get_epc(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);
 size_t uhf_tag_get_epc_size(UHFTag* uhf_tag);
 uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag);
 uint8_t* uhf_tag_get_tid(UHFTag* uhf_tag);
 size_t uhf_tag_get_tid_size(UHFTag* uhf_tag);
 size_t uhf_tag_get_tid_size(UHFTag* uhf_tag);

+ 55 - 164
uhf_worker.c

@@ -11,185 +11,77 @@ UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) {
     return UHFWorkerEventSuccess;
     return UHFWorkerEventSuccess;
 }
 }
 
 
-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
-}
-
-// 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];
-// }
-
-// bool write_bank(UHFData* write_bank_cmd, UHFBank bank, uint8_t* bank_data, size_t bank_len) {
-//     UHFData* rp_data = uhf_data_alloc();
-//     write_bank_cmd->end = false;
-//     for(size_t i = 0; i < write_bank_cmd->length; i++) {
-//         continue;
-//     }
-//     furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, rp_data);
-//     for(int i = 5; i < 9; i++) { // no access password for now
-//         write_bank_cmd->data[i] = 0;
-//     }
-//     write_bank_cmd->data[9] = bank;
-//     size_t word_len = bank_len / 2;
-//     write_bank_cmd->data[13] = word_len;
-//     write_bank_cmd->length = 14;
-//     write_bank_cmd->start = true;
-//     for(size_t i = 0; i < bank_len; i++) {
-//         uhf_data_append(write_bank_cmd, bank_data[i]);
-//     }
-//     uhf_data_append(write_bank_cmd, 00);
-//     uhf_data_append(write_bank_cmd, FRAME_END);
-//     write_bank_cmd->data[4] = write_bank_cmd->length - 7;
-//     write_bank_cmd->data[write_bank_cmd->length - 2] = uhf_data_calculate_checksum(write_bank_cmd);
-//     furi_hal_uart_tx(FuriHalUartIdUSART1, write_bank_cmd->data, write_bank_cmd->length);
-//     furi_delay_ms(CB_DELAY);
-//     bool success = rp_data->data[2] == write_bank_cmd->data[2];
-//     uhf_data_free(rp_data);
-//     return success;
-// }
-
 UHFTag* send_polling_command(UHFWorker* uhf_worker) {
 UHFTag* send_polling_command(UHFWorker* uhf_worker) {
     // read epc bank
     // read epc bank
-    UHFTag* uhf_tag;
+    UHFTag* uhf_tag = uhf_tag_alloc();
     while(true) {
     while(true) {
-        uhf_tag = m100_send_single_poll(uhf_worker->module);
+        M100ResponseType status = m100_send_single_poll(uhf_worker->module, uhf_tag);
         furi_delay_ms(100);
         furi_delay_ms(100);
         if(uhf_worker->state == UHFWorkerStateStop) {
         if(uhf_worker->state == UHFWorkerStateStop) {
+            uhf_tag_free(uhf_tag);
             return NULL;
             return NULL;
         }
         }
-        if(uhf_tag != NULL) break;
-        FURI_LOG_E("WKR", "null still");
+        if(status == M100Success) break;
     }
     }
     return uhf_tag;
     return uhf_tag;
 }
 }
 
 
+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(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;
+}
+
 UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
 UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
     UHFTag* uhf_tag = send_polling_command(uhf_worker);
     UHFTag* uhf_tag = send_polling_command(uhf_worker);
     if(uhf_tag == NULL) return UHFWorkerEventAborted;
     if(uhf_tag == NULL) return UHFWorkerEventAborted;
     uhf_tag_wrapper_set_tag(uhf_worker->uhf_tag_wrapper, uhf_tag);
     uhf_tag_wrapper_set_tag(uhf_worker->uhf_tag_wrapper, uhf_tag);
     // Todo : set select here
     // Todo : set select here
-    bool select_success = m100_set_select(uhf_worker->module, uhf_tag);
-    FURI_LOG_E("TAG", "select success = %d", select_success);
-
-    // Todo : read rfu
-    m100_read_label_data_storage(uhf_worker->module, uhf_tag, ReservedBank, 0);
-    // Todo : read epc
-    m100_read_label_data_storage(uhf_worker->module, uhf_tag, EPCBank, 0);
-    // Todo : read tid
-    m100_read_label_data_storage(uhf_worker->module, uhf_tag, TIDBank, 0);
-    // Todo : read user
-    m100_read_label_data_storage(uhf_worker->module, uhf_tag, UserBank, 0);
-    // 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;
-    // 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);
-    //         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;
-    // 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
-
+    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;
     return UHFWorkerEventSuccess;
 }
 }
 
 
-// UHFWorkerEvent write_single_card(UHFWorker* uhf_worker) {
-//     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);
-
-//     send_polling_command(uhf_worker, raw_read_data);
-//     // todo : rfu ?
-//     UHFTag* uhf_tag = uhf_worker->uhf_tag;
-
-//     UHFData* write_bank_cmd = uhf_data_alloc();
-//     write_bank_cmd->length = CMD_WRITE_LABEL_DATA_STORAGE.length;
-
-//     memcpy(
-//         (void*)&write_bank_cmd->data[0],
-//         (void*)&CMD_WRITE_LABEL_DATA_STORAGE.cmd[0],
-//         write_bank_cmd->length);
-//     if(!send_set_select_command(raw_read_data, EPC_BANK)) return UHFWorkerEventFail;
-
-//     if(raw_read_data->data[6] & 0x04) {
-//         if(!write_bank(write_bank_cmd, USER_BANK, uhf_tag->user, uhf_tag->user_length))
-//             return UHFWorkerEventFail;
-//     }
-//     uint8_t write_data[uhf_tag->epc_length + 2];
-//     memcpy(&write_data, &raw_read_data->data[raw_read_data->length - 4], 2);
-//     memcpy(&write_data[2], &uhf_tag->epc, uhf_tag->epc_length);
-//     write_data[10] = 0xF1;
-//     if(!write_bank(write_bank_cmd, EPC_BANK, write_data, uhf_tag->epc_length + 2)) {
-//         return UHFWorkerEventFail;
-//     }
-//     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;
+}
 
 
 int32_t uhf_worker_task(void* ctx) {
 int32_t uhf_worker_task(void* ctx) {
     UHFWorker* uhf_worker = ctx;
     UHFWorker* uhf_worker = ctx;
@@ -199,11 +91,10 @@ int32_t uhf_worker_task(void* ctx) {
     } else if(uhf_worker->state == UHFWorkerStateDetectSingle) {
     } else if(uhf_worker->state == UHFWorkerStateDetectSingle) {
         UHFWorkerEvent event = read_single_card(uhf_worker);
         UHFWorkerEvent event = read_single_card(uhf_worker);
         uhf_worker->callback(event, uhf_worker->ctx);
         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);
     }
     }
-    // else if(uhf_worker->state == UHFWorkerStateWriteSingle) {
-    //     UHFWorkerEvent event = write_single_card(uhf_worker);
-    //     uhf_worker->callback(event, uhf_worker->ctx);
-    // }
     return 0;
     return 0;
 }
 }