uhf_worker.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #include "uhf_worker.h"
  2. #include "uhf_cmd.h"
  3. #define CB_DELAY 50
  4. // uart callback functions
  5. void module_rx_callback(UartIrqEvent event, uint8_t data, void* ctx) {
  6. UNUSED(event);
  7. UHFData* uhf_data = ctx;
  8. uhf_data_append(uhf_data, data);
  9. }
  10. // yrm100 module commands
  11. UHFWorkerEvent verify_module_connected(UHFWorker* uhf_worker) {
  12. UHFResponseData* uhf_response_data = uhf_worker->response_data;
  13. uhf_response_data_reset(uhf_response_data);
  14. // FURI_LOG_E("log", "freeing done");
  15. UHFData* hardware_version = uhf_response_data->head;
  16. UHFData* software_version = uhf_response_data_add_new_uhf_data(uhf_response_data);
  17. UHFData* manufacturer = uhf_response_data_add_new_uhf_data(uhf_response_data);
  18. // FURI_LOG_E("log", "alloc done");
  19. furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUD_RATE);
  20. // read hardware version
  21. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, hardware_version);
  22. furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_HARDWARE_VERSION.cmd, CMD_HARDWARE_VERSION.length);
  23. furi_delay_ms(CB_DELAY);
  24. // read software version
  25. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, software_version);
  26. furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_SOFTWARE_VERSION.cmd, CMD_SOFTWARE_VERSION.length);
  27. furi_delay_ms(CB_DELAY);
  28. // read manufacturer
  29. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, manufacturer);
  30. furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_MANUFACTURERS.cmd, CMD_MANUFACTURERS.length);
  31. furi_delay_ms(CB_DELAY);
  32. // verify that we received all data
  33. if(!hardware_version->end || !software_version->end || !manufacturer->end) {
  34. return UHFWorkerEventFail;
  35. }
  36. // verify all data was received correctly
  37. if(!uhf_data_verfiy_checksum(hardware_version) ||
  38. !uhf_data_verfiy_checksum(software_version) || !uhf_data_verfiy_checksum(manufacturer))
  39. return UHFWorkerEventFail;
  40. return UHFWorkerEventSuccess;
  41. }
  42. uint8_t get_epc_length_in_bits(uint8_t pc) {
  43. uint8_t epc_length = pc;
  44. epc_length >>= 3;
  45. return (uint8_t)epc_length * 16; // x-words * 16 bits
  46. }
  47. bool send_set_select_command(UHFData* selected_tag, UHFBank bank) {
  48. bool success = false;
  49. // Set select
  50. UHFData* select_cmd = uhf_data_alloc();
  51. select_cmd->start = true;
  52. select_cmd->length = CMD_SET_SELECT_PARAMETER.length;
  53. memcpy((void*)&select_cmd->data, (void*)&CMD_SET_SELECT_PARAMETER.cmd[0], select_cmd->length);
  54. // set select param
  55. size_t mask_length_bits = (size_t)get_epc_length_in_bits(selected_tag->data[6]);
  56. size_t mask_length_bytes = (size_t)mask_length_bits / 8;
  57. select_cmd->data[5] = bank; // 0x00=rfu, 0x01=epc, 0x10=tid, 0x11=user
  58. // set ptr
  59. select_cmd->data[9] = 0x20; // epc data begins after 0x20
  60. // set mask length
  61. select_cmd->data[10] = mask_length_bits;
  62. // set mask starting position
  63. select_cmd->length = 12;
  64. // set mask
  65. for(size_t i = 0; i < mask_length_bytes; i++) {
  66. uhf_data_append(select_cmd, selected_tag->data[8 + i]);
  67. }
  68. uhf_data_append(select_cmd, 0x00); // add checksum section
  69. uhf_data_append(select_cmd, FRAME_END); // command end
  70. // add checksum
  71. select_cmd->data[select_cmd->length - 2] = uhf_data_calculate_checksum(select_cmd);
  72. UHFData* select_response = uhf_data_alloc();
  73. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, select_response);
  74. furi_hal_uart_tx(FuriHalUartIdUSART1, select_cmd->data, select_cmd->length);
  75. furi_delay_ms(CB_DELAY);
  76. success = select_response->data[5] == 0x00;
  77. uhf_data_free(select_cmd);
  78. uhf_data_free(select_response);
  79. return success;
  80. }
  81. bool read_bank(UHFData* read_bank_cmd, UHFData* response_bank, UHFBank bank) {
  82. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, response_bank);
  83. read_bank_cmd->data[9] = bank;
  84. read_bank_cmd->data[read_bank_cmd->length - 2] = uhf_data_calculate_checksum(read_bank_cmd);
  85. uhf_data_reset(response_bank);
  86. furi_hal_uart_tx(FuriHalUartIdUSART1, read_bank_cmd->data, read_bank_cmd->length);
  87. furi_delay_ms(CB_DELAY);
  88. return response_bank->data[2] == read_bank_cmd->data[2];
  89. }
  90. bool write_bank(UHFData* write_bank_cmd, UHFBank bank, uint8_t* bank_data, size_t bank_len) {
  91. UHFData* rp_data = uhf_data_alloc();
  92. write_bank_cmd->end = false;
  93. for(size_t i = 0; i < write_bank_cmd->length; i++) {
  94. continue;
  95. }
  96. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, rp_data);
  97. for(int i = 5; i < 9; i++) { // no access password for now
  98. write_bank_cmd->data[i] = 0;
  99. }
  100. write_bank_cmd->data[9] = bank;
  101. size_t word_len = bank_len / 2;
  102. write_bank_cmd->data[13] = word_len;
  103. write_bank_cmd->length = 14;
  104. write_bank_cmd->start = true;
  105. for(size_t i = 0; i < bank_len; i++) {
  106. uhf_data_append(write_bank_cmd, bank_data[i]);
  107. }
  108. uhf_data_append(write_bank_cmd, 00);
  109. uhf_data_append(write_bank_cmd, FRAME_END);
  110. write_bank_cmd->data[4] = write_bank_cmd->length - 7;
  111. write_bank_cmd->data[write_bank_cmd->length - 2] = uhf_data_calculate_checksum(write_bank_cmd);
  112. furi_hal_uart_tx(FuriHalUartIdUSART1, write_bank_cmd->data, write_bank_cmd->length);
  113. furi_delay_ms(CB_DELAY);
  114. bool success = rp_data->data[2] == write_bank_cmd->data[2];
  115. uhf_data_free(rp_data);
  116. return success;
  117. }
  118. UHFWorkerEvent send_polling_command(UHFWorker* uhf_worker, UHFData* raw_read_data) {
  119. furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, module_rx_callback, raw_read_data);
  120. uhf_data_reset(raw_read_data);
  121. // read epc bank
  122. while(true) {
  123. furi_hal_uart_tx(FuriHalUartIdUSART1, CMD_SINGLE_POLLING.cmd, CMD_SINGLE_POLLING.length);
  124. furi_delay_ms(100);
  125. if(uhf_worker->state == UHFWorkerStateStop) {
  126. return UHFWorkerEventAborted;
  127. }
  128. if(raw_read_data->end) {
  129. if(raw_read_data->data[1] == 0x01 && raw_read_data->data[5] == 0x15) {
  130. uhf_data_reset(raw_read_data);
  131. continue;
  132. } else if(raw_read_data->data[1] == 0x02)
  133. break; // read success
  134. }
  135. }
  136. return UHFWorkerEventSuccess;
  137. }
  138. UHFWorkerEvent read_single_card(UHFWorker* uhf_worker) {
  139. // debug
  140. // FuriString* temp_str;
  141. // temp_str = furi_string_alloc();
  142. // e-debug
  143. UHFResponseData* uhf_response_data = uhf_worker->response_data;
  144. uhf_response_data_reset(uhf_response_data);
  145. UHFData* raw_read_data = uhf_response_data_get_uhf_data(uhf_response_data, 0);
  146. furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUD_RATE);
  147. send_polling_command(uhf_worker, raw_read_data);
  148. // todo : rfu ?
  149. UHFTag* uhf_tag = uhf_worker->uhf_tag;
  150. uhf_tag_reset(uhf_tag);
  151. // add to tag object
  152. UHFData* raw_bank_data = uhf_data_alloc();
  153. size_t epc_length = (size_t)get_epc_length_in_bits(raw_read_data->data[6]) / 8;
  154. size_t offset = (size_t)(8 + epc_length);
  155. UHFData* read_bank_cmd = uhf_data_alloc();
  156. read_bank_cmd->length = CMD_READ_LABEL_DATA_STORAGE.length;
  157. memcpy(
  158. (void*)&read_bank_cmd->data[0],
  159. (void*)&CMD_READ_LABEL_DATA_STORAGE.cmd[0],
  160. read_bank_cmd->length);
  161. if(!send_set_select_command(raw_read_data, EPC_BANK)) return UHFWorkerEventFail;
  162. int retry = 3;
  163. do {
  164. if(read_bank(read_bank_cmd, raw_bank_data, EPC_BANK)) {
  165. uhf_tag_set_epc(uhf_tag, raw_bank_data->data + offset, epc_length + 2);
  166. break;
  167. }
  168. } while(retry--);
  169. // // debug
  170. // furi_string_reset(temp_str);
  171. // for(size_t i = 0; i < raw_bank_data->length; i++) {
  172. // furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
  173. // }
  174. // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
  175. // // e-debug
  176. uhf_data_reset(raw_bank_data);
  177. retry = 3;
  178. do {
  179. if(read_bank(read_bank_cmd, raw_bank_data, TID_BANK)) {
  180. uhf_tag_set_tid(uhf_tag, raw_bank_data->data + offset, 16);
  181. break;
  182. }
  183. } while(retry--);
  184. // // debug
  185. // furi_string_reset(temp_str);
  186. // for(size_t i = 0; i < raw_bank_data->length; i++) {
  187. // furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
  188. // }
  189. // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
  190. // // e-debug
  191. uhf_data_reset(raw_bank_data);
  192. retry = 3;
  193. if(raw_read_data->data[6] & 0x04) {
  194. do {
  195. if(read_bank(read_bank_cmd, raw_bank_data, USER_BANK)) {
  196. uhf_tag_set_user(uhf_tag, raw_bank_data->data + offset, 16);
  197. break;
  198. }
  199. } while(retry--);
  200. }
  201. // // debug
  202. // furi_string_reset(temp_str);
  203. // for(size_t i = 0; i < raw_bank_data->length; i++) {
  204. // furi_string_cat_printf(temp_str, "%02x ", raw_bank_data->data[i]);
  205. // }
  206. // FURI_LOG_E("TAG", "data = %s", furi_string_get_cstr(temp_str));
  207. // // e-debug
  208. uhf_data_reset(raw_bank_data);
  209. uhf_data_free(raw_bank_data);
  210. uhf_data_free(read_bank_cmd);
  211. // debug
  212. // furi_string_free(temp_str);
  213. // e-debug
  214. return UHFWorkerEventSuccess;
  215. }
  216. UHFWorkerEvent write_single_card(UHFWorker* uhf_worker) {
  217. UHFResponseData* uhf_response_data = uhf_worker->response_data;
  218. uhf_response_data_reset(uhf_response_data);
  219. UHFData* raw_read_data = uhf_response_data_get_uhf_data(uhf_response_data, 0);
  220. furi_hal_uart_set_br(FuriHalUartIdUSART1, DEFAULT_BAUD_RATE);
  221. send_polling_command(uhf_worker, raw_read_data);
  222. // todo : rfu ?
  223. UHFTag* uhf_tag = uhf_worker->uhf_tag;
  224. UHFData* write_bank_cmd = uhf_data_alloc();
  225. write_bank_cmd->length = CMD_WRITE_LABEL_DATA_STORAGE.length;
  226. memcpy(
  227. (void*)&write_bank_cmd->data[0],
  228. (void*)&CMD_WRITE_LABEL_DATA_STORAGE.cmd[0],
  229. write_bank_cmd->length);
  230. if(!send_set_select_command(raw_read_data, EPC_BANK)) return UHFWorkerEventFail;
  231. if(raw_read_data->data[6] & 0x04) {
  232. if(!write_bank(write_bank_cmd, USER_BANK, uhf_tag->user, uhf_tag->user_length))
  233. return UHFWorkerEventFail;
  234. }
  235. uint8_t write_data[uhf_tag->epc_length + 2];
  236. memcpy(&write_data, &raw_read_data->data[raw_read_data->length - 4], 2);
  237. memcpy(&write_data[2], &uhf_tag->epc, uhf_tag->epc_length);
  238. write_data[10] = 0xF1;
  239. if(!write_bank(write_bank_cmd, EPC_BANK, write_data, uhf_tag->epc_length + 2)) {
  240. return UHFWorkerEventFail;
  241. }
  242. return UHFWorkerEventSuccess;
  243. }
  244. int32_t uhf_worker_task(void* ctx) {
  245. UHFWorker* uhf_worker = ctx;
  246. if(uhf_worker->state == UHFWorkerStateVerify) {
  247. UHFWorkerEvent event = verify_module_connected(uhf_worker);
  248. uhf_worker->callback(event, uhf_worker->ctx);
  249. } else if(uhf_worker->state == UHFWorkerStateDetectSingle) {
  250. UHFWorkerEvent event = read_single_card(uhf_worker);
  251. uhf_worker->callback(event, uhf_worker->ctx);
  252. } else if(uhf_worker->state == UHFWorkerStateWriteSingle) {
  253. UHFWorkerEvent event = write_single_card(uhf_worker);
  254. uhf_worker->callback(event, uhf_worker->ctx);
  255. }
  256. return 0;
  257. }
  258. UHFWorker* uhf_worker_alloc() {
  259. UHFWorker* uhf_worker = (UHFWorker*)malloc(sizeof(UHFWorker));
  260. uhf_worker->thread = furi_thread_alloc_ex("UHFWorker", 8 * 1024, uhf_worker_task, uhf_worker);
  261. uhf_worker->response_data = uhf_response_data_alloc();
  262. uhf_worker->callback = NULL;
  263. uhf_worker->ctx = NULL;
  264. return uhf_worker;
  265. }
  266. void uhf_worker_change_state(UHFWorker* worker, UHFWorkerState state) {
  267. worker->state = state;
  268. }
  269. void uhf_worker_start(
  270. UHFWorker* uhf_worker,
  271. UHFWorkerState state,
  272. UHFWorkerCallback callback,
  273. void* ctx) {
  274. uhf_worker->state = state;
  275. uhf_worker->callback = callback;
  276. uhf_worker->ctx = ctx;
  277. furi_thread_start(uhf_worker->thread);
  278. }
  279. void uhf_worker_stop(UHFWorker* uhf_worker) {
  280. furi_assert(uhf_worker);
  281. furi_assert(uhf_worker->thread);
  282. if(furi_thread_get_state(uhf_worker->thread) != FuriThreadStateStopped) {
  283. uhf_worker_change_state(uhf_worker, UHFWorkerStateStop);
  284. furi_thread_join(uhf_worker->thread);
  285. }
  286. }
  287. void uhf_worker_free(UHFWorker* uhf_worker) {
  288. furi_assert(uhf_worker);
  289. furi_thread_free(uhf_worker->thread);
  290. uhf_response_data_free(uhf_worker->response_data);
  291. free(uhf_worker);
  292. }