uhf_device.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #include "uhf_device.h"
  2. #include <toolbox/path.h>
  3. #include <flipper_format/flipper_format.h>
  4. #include <uhf_rfid_icons.h>
  5. #define TAG "UHFDevice"
  6. static const char* uhf_file_header = "Flipper UHF RFID device";
  7. static const uint32_t uhf_file_version = 1;
  8. UHFDevice* uhf_device_alloc() {
  9. UHFDevice* uhf_device = malloc(sizeof(UHFDevice));
  10. uhf_device->storage = furi_record_open(RECORD_STORAGE);
  11. uhf_device->dialogs = furi_record_open(RECORD_DIALOGS);
  12. uhf_device->load_path = furi_string_alloc();
  13. return uhf_device;
  14. }
  15. void uhf_device_set_name(UHFDevice* dev, const char* name) {
  16. furi_assert(dev);
  17. strlcpy(dev->dev_name, name, UHF_DEV_NAME_MAX_LEN);
  18. }
  19. static bool uhf_device_save_file(
  20. UHFDevice* dev,
  21. const char* dev_name,
  22. const char* folder,
  23. const char* extension,
  24. bool use_load_path) {
  25. furi_assert(dev);
  26. UHFTag* uhf_tag = dev->uhf_tag_wrapper->uhf_tag;
  27. bool saved = false;
  28. FlipperFormat* file = flipper_format_file_alloc(dev->storage);
  29. FuriString* temp_str;
  30. temp_str = furi_string_alloc();
  31. do {
  32. if(use_load_path && !furi_string_empty(dev->load_path)) {
  33. // Get directory name
  34. path_extract_dirname(furi_string_get_cstr(dev->load_path), temp_str);
  35. // Make path to file to save
  36. furi_string_cat_printf(temp_str, "/%s%s", dev_name, extension);
  37. } else {
  38. // First remove uhf device file if it was saved
  39. furi_string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
  40. }
  41. // Open file
  42. if(!flipper_format_file_open_always(file, furi_string_get_cstr(temp_str))) break;
  43. // Write header
  44. if(!flipper_format_write_header_cstr(file, uhf_file_header, uhf_file_version)) break;
  45. // Reserved bank might be added
  46. // todo : maybe
  47. uint32_t temp_arr[1];
  48. uint8_t temp_arr2[2];
  49. // write pc
  50. temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) >> 8) & 0xFF;
  51. temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_pc(uhf_tag) & 0xFF);
  52. if(!flipper_format_write_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
  53. // write crc
  54. temp_arr2[0] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) >> 8) & 0xFF;
  55. temp_arr2[1] = (uint8_t)(uhf_tag_get_epc_crc(uhf_tag) & 0xFF);
  56. if(!flipper_format_write_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
  57. // write epc
  58. temp_arr[0] = uhf_tag_get_epc_size(uhf_tag);
  59. if(!flipper_format_write_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  60. if(!flipper_format_write_hex(
  61. file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
  62. break;
  63. // write tid
  64. temp_arr[0] = uhf_tag_get_tid_size(uhf_tag);
  65. if(!flipper_format_write_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  66. if(!flipper_format_write_hex(
  67. file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
  68. break;
  69. // write user
  70. temp_arr[0] = uhf_tag_get_user_size(uhf_tag);
  71. if(!flipper_format_write_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  72. if(!flipper_format_write_hex(
  73. file,
  74. UHF_USER_BANK_LABEL,
  75. uhf_tag_get_user(uhf_tag),
  76. uhf_tag_get_user_size(uhf_tag)))
  77. break;
  78. saved = true;
  79. } while(0);
  80. if(!saved) {
  81. dialog_message_show_storage_error(dev->dialogs, "Can not save\nfile");
  82. }
  83. furi_string_free(temp_str);
  84. flipper_format_free(file);
  85. return saved;
  86. }
  87. bool uhf_device_save(UHFDevice* dev, const char* dev_name) {
  88. return uhf_device_save_file(
  89. dev, dev_name, STORAGE_APP_DATA_PATH_PREFIX, UHF_APP_EXTENSION, true);
  90. return false;
  91. }
  92. // uncomment
  93. static bool uhf_device_load_data(UHFDevice* dev, FuriString* path, bool show_dialog) {
  94. bool parsed = false;
  95. FlipperFormat* file = flipper_format_file_alloc(dev->storage);
  96. // UHFResponseData* uhf_response_data = dev->dev_data;
  97. FuriString* temp_str;
  98. temp_str = furi_string_alloc();
  99. bool deprecated_version = false;
  100. UHFTag* uhf_tag = uhf_tag_alloc();
  101. uhf_tag_reset(uhf_tag);
  102. uint32_t temp_arr[1];
  103. if(dev->loading_cb) {
  104. dev->loading_cb(dev->loading_cb_ctx, true);
  105. }
  106. do {
  107. if(!flipper_format_file_open_existing(file, furi_string_get_cstr(path))) break;
  108. // Read and verify file header
  109. uint32_t version = 0;
  110. if(!flipper_format_read_header(file, temp_str, &version)) break;
  111. if(furi_string_cmp_str(temp_str, uhf_file_header) || (version != uhf_file_version)) {
  112. deprecated_version = true;
  113. break;
  114. }
  115. // read pc
  116. uint8_t temp_arr2[2];
  117. if(!flipper_format_read_hex(file, UHF_EPC_PC_LABEL, temp_arr2, 2)) break;
  118. uhf_tag_set_epc_pc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
  119. // read crc
  120. if(!flipper_format_read_hex(file, UHF_EPC_CRC_LABEL, temp_arr2, 2)) break;
  121. uhf_tag_set_epc_crc(uhf_tag, (temp_arr2[0] << 8) + temp_arr2[1]);
  122. // read epc
  123. if(!flipper_format_read_uint32(file, UHF_EPC_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  124. uhf_tag_set_epc_size(uhf_tag, temp_arr[0]);
  125. if(!flipper_format_read_hex(
  126. file, UHF_EPC_BANK_LABEL, uhf_tag_get_epc(uhf_tag), uhf_tag_get_epc_size(uhf_tag)))
  127. break;
  128. // read tid
  129. if(!flipper_format_read_uint32(file, UHF_TID_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  130. uhf_tag_set_tid_size(uhf_tag, temp_arr[0]);
  131. if(!flipper_format_read_hex(
  132. file, UHF_TID_BANK_LABEL, uhf_tag_get_tid(uhf_tag), uhf_tag_get_tid_size(uhf_tag)))
  133. break;
  134. // read user
  135. if(!flipper_format_read_uint32(file, UHF_USER_BANK_LENGTH_LABEL, temp_arr, 1)) break;
  136. uhf_tag_set_user_size(uhf_tag, temp_arr[0]);
  137. if(!flipper_format_read_hex(
  138. file,
  139. UHF_USER_BANK_LABEL,
  140. uhf_tag_get_user(uhf_tag),
  141. uhf_tag_get_user_size(uhf_tag)))
  142. break;
  143. parsed = true;
  144. } while(false);
  145. if(dev->loading_cb) {
  146. dev->loading_cb(dev->loading_cb_ctx, false);
  147. }
  148. if((!parsed) && (show_dialog)) {
  149. if(deprecated_version) {
  150. dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
  151. } else {
  152. dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
  153. }
  154. }
  155. uhf_tag_wrapper_set_tag(dev->uhf_tag_wrapper, uhf_tag);
  156. furi_string_free(temp_str);
  157. flipper_format_free(file);
  158. return parsed;
  159. }
  160. void uhf_device_free(UHFDevice* uhf_dev) {
  161. furi_assert(uhf_dev);
  162. furi_record_close(RECORD_STORAGE);
  163. furi_record_close(RECORD_DIALOGS);
  164. furi_string_free(uhf_dev->load_path);
  165. free(uhf_dev);
  166. }
  167. bool uhf_file_select(UHFDevice* dev) {
  168. furi_assert(dev);
  169. FuriString* uhf_app_folder;
  170. uhf_app_folder = furi_string_alloc_set(STORAGE_APP_DATA_PATH_PREFIX);
  171. DialogsFileBrowserOptions browser_options;
  172. dialog_file_browser_set_basic_options(&browser_options, UHF_APP_EXTENSION, &I_Nfc_10px);
  173. browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
  174. bool res =
  175. dialog_file_browser_show(dev->dialogs, dev->load_path, uhf_app_folder, &browser_options);
  176. furi_string_free(uhf_app_folder);
  177. if(res) {
  178. FuriString* filename;
  179. filename = furi_string_alloc();
  180. path_extract_filename(dev->load_path, filename, true);
  181. strncpy(dev->dev_name, furi_string_get_cstr(filename), UHF_DEV_NAME_MAX_LEN);
  182. res = uhf_device_load_data(dev, dev->load_path, true);
  183. if(res) {
  184. uhf_device_set_name(dev, dev->dev_name);
  185. }
  186. furi_string_free(filename);
  187. }
  188. return res;
  189. }
  190. bool uhf_device_delete(UHFDevice* dev, bool use_load_path) {
  191. furi_assert(dev);
  192. bool deleted = false;
  193. FuriString* file_path;
  194. file_path = furi_string_alloc();
  195. do {
  196. // Delete original file
  197. if(use_load_path && !furi_string_empty(dev->load_path)) {
  198. furi_string_set(file_path, dev->load_path);
  199. } else {
  200. furi_string_printf(file_path, APP_DATA_PATH("%s%s"), dev->dev_name, UHF_APP_EXTENSION);
  201. }
  202. if(!storage_simply_remove(dev->storage, furi_string_get_cstr(file_path))) break;
  203. deleted = true;
  204. } while(0);
  205. if(!deleted) {
  206. dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
  207. }
  208. furi_string_free(file_path);
  209. return deleted;
  210. }
  211. void uhf_device_set_loading_callback(UHFDevice* dev, UHFLoadingCallback callback, void* context) {
  212. furi_assert(dev);
  213. dev->loading_cb = callback;
  214. dev->loading_cb_ctx = context;
  215. }