lfrfid_cli.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <stdarg.h>
  4. #include <cli/cli.h>
  5. #include <lib/toolbox/args.h>
  6. #include <lib/lfrfid/lfrfid_worker.h>
  7. #include <storage/storage.h>
  8. #include <toolbox/stream/file_stream.h>
  9. #include <toolbox/varint.h>
  10. #include <toolbox/protocols/protocol_dict.h>
  11. #include <lfrfid/protocols/lfrfid_protocols.h>
  12. #include <lfrfid/lfrfid_raw_file.h>
  13. #include <toolbox/pulse_protocols/pulse_glue.h>
  14. static void lfrfid_cli(Cli* cli, string_t args, void* context);
  15. // app cli function
  16. void lfrfid_on_system_start() {
  17. Cli* cli = furi_record_open(RECORD_CLI);
  18. cli_add_command(cli, "rfid", CliCommandFlagDefault, lfrfid_cli, NULL);
  19. furi_record_close(RECORD_CLI);
  20. }
  21. static void lfrfid_cli_print_usage() {
  22. printf("Usage:\r\n");
  23. printf("rfid read <optional: normal | indala>\r\n");
  24. printf("rfid <write | emulate> <key_type> <key_data>\r\n");
  25. printf("rfid raw_read <ask | psk> <filename>\r\n");
  26. printf("rfid raw_emulate <filename>\r\n");
  27. };
  28. typedef struct {
  29. ProtocolId protocol;
  30. FuriEventFlag* event;
  31. } LFRFIDCliReadContext;
  32. static void lfrfid_cli_read_callback(LFRFIDWorkerReadResult result, ProtocolId proto, void* ctx) {
  33. furi_assert(ctx);
  34. LFRFIDCliReadContext* context = ctx;
  35. if(result == LFRFIDWorkerReadDone) {
  36. context->protocol = proto;
  37. FURI_SW_MEMBARRIER();
  38. }
  39. furi_event_flag_set(context->event, 1 << result);
  40. }
  41. static void lfrfid_cli_read(Cli* cli, string_t args) {
  42. string_t type_string;
  43. string_init(type_string);
  44. LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto;
  45. if(args_read_string_and_trim(args, type_string)) {
  46. if(string_cmp_str(type_string, "normal") == 0 || string_cmp_str(type_string, "ask") == 0) {
  47. // ask
  48. type = LFRFIDWorkerReadTypeASKOnly;
  49. } else if(
  50. string_cmp_str(type_string, "indala") == 0 ||
  51. string_cmp_str(type_string, "psk") == 0) {
  52. // psk
  53. type = LFRFIDWorkerReadTypePSKOnly;
  54. } else {
  55. lfrfid_cli_print_usage();
  56. string_clear(type_string);
  57. return;
  58. }
  59. }
  60. string_clear(type_string);
  61. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  62. LFRFIDWorker* worker = lfrfid_worker_alloc(dict);
  63. LFRFIDCliReadContext context;
  64. context.protocol = PROTOCOL_NO;
  65. context.event = furi_event_flag_alloc();
  66. lfrfid_worker_start_thread(worker);
  67. printf("Reading RFID...\r\nPress Ctrl+C to abort\r\n");
  68. const uint32_t available_flags = (1 << LFRFIDWorkerReadDone);
  69. lfrfid_worker_read_start(worker, type, lfrfid_cli_read_callback, &context);
  70. while(true) {
  71. uint32_t flags =
  72. furi_event_flag_wait(context.event, available_flags, FuriFlagWaitAny, 100);
  73. if(flags != FuriFlagErrorTimeout) {
  74. if(FURI_BIT(flags, LFRFIDWorkerReadDone)) {
  75. break;
  76. }
  77. }
  78. if(cli_cmd_interrupt_received(cli)) break;
  79. }
  80. lfrfid_worker_stop(worker);
  81. lfrfid_worker_stop_thread(worker);
  82. lfrfid_worker_free(worker);
  83. if(context.protocol != PROTOCOL_NO) {
  84. printf("%s ", protocol_dict_get_name(dict, context.protocol));
  85. size_t size = protocol_dict_get_data_size(dict, context.protocol);
  86. uint8_t* data = malloc(size);
  87. protocol_dict_get_data(dict, context.protocol, data, size);
  88. for(size_t i = 0; i < size; i++) {
  89. printf("%02X", data[i]);
  90. }
  91. printf("\r\n");
  92. free(data);
  93. string_t info;
  94. string_init(info);
  95. protocol_dict_render_data(dict, info, context.protocol);
  96. if(string_size(info) > 0) {
  97. printf("%s\r\n", string_get_cstr(info));
  98. }
  99. string_clear(info);
  100. }
  101. printf("Reading stopped\r\n");
  102. protocol_dict_free(dict);
  103. furi_event_flag_free(context.event);
  104. }
  105. static bool lfrfid_cli_parse_args(string_t args, ProtocolDict* dict, ProtocolId* protocol) {
  106. bool result = false;
  107. string_t protocol_name, data_text;
  108. string_init(protocol_name);
  109. string_init(data_text);
  110. size_t data_size = protocol_dict_get_max_data_size(dict);
  111. uint8_t* data = malloc(data_size);
  112. do {
  113. // load args
  114. if(!args_read_string_and_trim(args, protocol_name) ||
  115. !args_read_string_and_trim(args, data_text)) {
  116. lfrfid_cli_print_usage();
  117. break;
  118. }
  119. // check protocol arg
  120. *protocol = protocol_dict_get_protocol_by_name(dict, string_get_cstr(protocol_name));
  121. if(*protocol == PROTOCOL_NO) {
  122. printf(
  123. "Unknown protocol: %s\r\n"
  124. "Available protocols:\r\n",
  125. string_get_cstr(protocol_name));
  126. for(ProtocolId i = 0; i < LFRFIDProtocolMax; i++) {
  127. printf(
  128. "\t%s, %d bytes long\r\n",
  129. protocol_dict_get_name(dict, i),
  130. protocol_dict_get_data_size(dict, i));
  131. }
  132. break;
  133. }
  134. data_size = protocol_dict_get_data_size(dict, *protocol);
  135. // check data arg
  136. if(!args_read_hex_bytes(data_text, data, data_size)) {
  137. printf(
  138. "%s data needs to be %d bytes long\r\n",
  139. protocol_dict_get_name(dict, *protocol),
  140. data_size);
  141. break;
  142. }
  143. // load data to protocol
  144. protocol_dict_set_data(dict, *protocol, data, data_size);
  145. result = true;
  146. } while(false);
  147. free(data);
  148. string_clear(protocol_name);
  149. string_clear(data_text);
  150. return result;
  151. }
  152. static void lfrfid_cli_write_callback(LFRFIDWorkerWriteResult result, void* ctx) {
  153. furi_assert(ctx);
  154. FuriEventFlag* events = ctx;
  155. furi_event_flag_set(events, 1 << result);
  156. }
  157. static void lfrfid_cli_write(Cli* cli, string_t args) {
  158. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  159. ProtocolId protocol;
  160. if(!lfrfid_cli_parse_args(args, dict, &protocol)) {
  161. protocol_dict_free(dict);
  162. return;
  163. }
  164. LFRFIDWorker* worker = lfrfid_worker_alloc(dict);
  165. FuriEventFlag* event = furi_event_flag_alloc();
  166. lfrfid_worker_start_thread(worker);
  167. lfrfid_worker_write_start(worker, protocol, lfrfid_cli_write_callback, event);
  168. printf("Writing RFID...\r\nPress Ctrl+C to abort\r\n");
  169. const uint32_t available_flags = (1 << LFRFIDWorkerWriteOK) |
  170. (1 << LFRFIDWorkerWriteProtocolCannotBeWritten) |
  171. (1 << LFRFIDWorkerWriteFobCannotBeWritten);
  172. while(!cli_cmd_interrupt_received(cli)) {
  173. uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
  174. if(flags != FuriFlagErrorTimeout) {
  175. if(FURI_BIT(flags, LFRFIDWorkerWriteOK)) {
  176. printf("Written!\r\n");
  177. break;
  178. }
  179. if(FURI_BIT(flags, LFRFIDWorkerWriteProtocolCannotBeWritten)) {
  180. printf("This protocol cannot be written.\r\n");
  181. break;
  182. }
  183. if(FURI_BIT(flags, LFRFIDWorkerWriteFobCannotBeWritten)) {
  184. printf("Seems this fob cannot be written.\r\n");
  185. }
  186. }
  187. }
  188. printf("Writing stopped\r\n");
  189. lfrfid_worker_stop(worker);
  190. lfrfid_worker_stop_thread(worker);
  191. lfrfid_worker_free(worker);
  192. protocol_dict_free(dict);
  193. furi_event_flag_free(event);
  194. }
  195. static void lfrfid_cli_emulate(Cli* cli, string_t args) {
  196. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  197. ProtocolId protocol;
  198. if(!lfrfid_cli_parse_args(args, dict, &protocol)) {
  199. protocol_dict_free(dict);
  200. return;
  201. }
  202. LFRFIDWorker* worker = lfrfid_worker_alloc(dict);
  203. lfrfid_worker_start_thread(worker);
  204. lfrfid_worker_emulate_start(worker, protocol);
  205. printf("Emulating RFID...\r\nPress Ctrl+C to abort\r\n");
  206. while(!cli_cmd_interrupt_received(cli)) {
  207. furi_delay_ms(100);
  208. }
  209. printf("Emulation stopped\r\n");
  210. lfrfid_worker_stop(worker);
  211. lfrfid_worker_stop_thread(worker);
  212. lfrfid_worker_free(worker);
  213. protocol_dict_free(dict);
  214. }
  215. static void lfrfid_cli_raw_analyze(Cli* cli, string_t args) {
  216. UNUSED(cli);
  217. string_t filepath, info_string;
  218. string_init(filepath);
  219. string_init(info_string);
  220. Storage* storage = furi_record_open(RECORD_STORAGE);
  221. LFRFIDRawFile* file = lfrfid_raw_file_alloc(storage);
  222. do {
  223. float frequency = 0;
  224. float duty_cycle = 0;
  225. if(!args_read_probably_quoted_string_and_trim(args, filepath)) {
  226. lfrfid_cli_print_usage();
  227. break;
  228. }
  229. if(!lfrfid_raw_file_open_read(file, string_get_cstr(filepath))) {
  230. printf("Failed to open file\r\n");
  231. break;
  232. }
  233. if(!lfrfid_raw_file_read_header(file, &frequency, &duty_cycle)) {
  234. printf("Invalid header\r\n");
  235. break;
  236. }
  237. bool file_end = false;
  238. uint32_t total_warns = 0;
  239. uint32_t total_duration = 0;
  240. uint32_t total_pulse = 0;
  241. ProtocolId total_protocol = PROTOCOL_NO;
  242. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  243. protocol_dict_decoders_start(dict);
  244. while(!file_end) {
  245. uint32_t pulse = 0;
  246. uint32_t duration = 0;
  247. if(lfrfid_raw_file_read_pair(file, &duration, &pulse, &file_end)) {
  248. bool warn = false;
  249. if(pulse > duration || pulse <= 0 || duration <= 0) {
  250. total_warns += 1;
  251. warn = true;
  252. }
  253. string_printf(info_string, "[%ld %ld]", pulse, duration);
  254. printf("%-16s", string_get_cstr(info_string));
  255. string_printf(info_string, "[%ld %ld]", pulse, duration - pulse);
  256. printf("%-16s", string_get_cstr(info_string));
  257. if(warn) {
  258. printf(" <<----");
  259. }
  260. if(total_protocol == PROTOCOL_NO) {
  261. total_protocol = protocol_dict_decoders_feed(dict, true, pulse);
  262. if(total_protocol == PROTOCOL_NO) {
  263. total_protocol =
  264. protocol_dict_decoders_feed(dict, false, duration - pulse);
  265. }
  266. if(total_protocol != PROTOCOL_NO) {
  267. printf(" <FOUND %s>", protocol_dict_get_name(dict, total_protocol));
  268. }
  269. }
  270. printf("\r\n");
  271. total_pulse += pulse;
  272. total_duration += duration;
  273. if(total_protocol != PROTOCOL_NO) {
  274. break;
  275. }
  276. } else {
  277. printf("Failed to read pair\r\n");
  278. break;
  279. }
  280. }
  281. printf(" Frequency: %f\r\n", (double)frequency);
  282. printf(" Duty Cycle: %f\r\n", (double)duty_cycle);
  283. printf(" Warns: %ld\r\n", total_warns);
  284. printf(" Pulse sum: %ld\r\n", total_pulse);
  285. printf("Duration sum: %ld\r\n", total_duration);
  286. printf(" Average: %f\r\n", (double)((float)total_pulse / (float)total_duration));
  287. printf(" Protocol: ");
  288. if(total_protocol != PROTOCOL_NO) {
  289. size_t data_size = protocol_dict_get_data_size(dict, total_protocol);
  290. uint8_t* data = malloc(data_size);
  291. protocol_dict_get_data(dict, total_protocol, data, data_size);
  292. printf("%s [", protocol_dict_get_name(dict, total_protocol));
  293. for(size_t i = 0; i < data_size; i++) {
  294. printf("%02X", data[i]);
  295. if(i < data_size - 1) {
  296. printf(" ");
  297. }
  298. }
  299. printf("]\r\n");
  300. protocol_dict_render_data(dict, info_string, total_protocol);
  301. printf("%s\r\n", string_get_cstr(info_string));
  302. free(data);
  303. } else {
  304. printf("not found\r\n");
  305. }
  306. protocol_dict_free(dict);
  307. } while(false);
  308. string_clear(filepath);
  309. string_clear(info_string);
  310. lfrfid_raw_file_free(file);
  311. furi_record_close(RECORD_STORAGE);
  312. }
  313. static void lfrfid_cli_raw_read_callback(LFRFIDWorkerReadRawResult result, void* context) {
  314. furi_assert(context);
  315. FuriEventFlag* event = context;
  316. furi_event_flag_set(event, 1 << result);
  317. }
  318. static void lfrfid_cli_raw_read(Cli* cli, string_t args) {
  319. UNUSED(cli);
  320. string_t filepath, type_string;
  321. string_init(filepath);
  322. string_init(type_string);
  323. LFRFIDWorkerReadType type = LFRFIDWorkerReadTypeAuto;
  324. do {
  325. if(args_read_string_and_trim(args, type_string)) {
  326. if(string_cmp_str(type_string, "normal") == 0 ||
  327. string_cmp_str(type_string, "ask") == 0) {
  328. // ask
  329. type = LFRFIDWorkerReadTypeASKOnly;
  330. } else if(
  331. string_cmp_str(type_string, "indala") == 0 ||
  332. string_cmp_str(type_string, "psk") == 0) {
  333. // psk
  334. type = LFRFIDWorkerReadTypePSKOnly;
  335. } else {
  336. lfrfid_cli_print_usage();
  337. break;
  338. }
  339. }
  340. if(!args_read_probably_quoted_string_and_trim(args, filepath)) {
  341. lfrfid_cli_print_usage();
  342. break;
  343. }
  344. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  345. LFRFIDWorker* worker = lfrfid_worker_alloc(dict);
  346. FuriEventFlag* event = furi_event_flag_alloc();
  347. lfrfid_worker_start_thread(worker);
  348. bool overrun = false;
  349. const uint32_t available_flags = (1 << LFRFIDWorkerReadRawFileError) |
  350. (1 << LFRFIDWorkerReadRawOverrun);
  351. lfrfid_worker_read_raw_start(
  352. worker, string_get_cstr(filepath), type, lfrfid_cli_raw_read_callback, event);
  353. while(true) {
  354. uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
  355. if(flags != FuriFlagErrorTimeout) {
  356. if(FURI_BIT(flags, LFRFIDWorkerReadRawFileError)) {
  357. printf("File is not RFID raw file\r\n");
  358. break;
  359. }
  360. if(FURI_BIT(flags, LFRFIDWorkerReadRawOverrun)) {
  361. if(!overrun) {
  362. printf("Overrun\r\n");
  363. overrun = true;
  364. }
  365. }
  366. }
  367. if(cli_cmd_interrupt_received(cli)) break;
  368. }
  369. if(overrun) {
  370. printf("An overrun occurred during read\r\n");
  371. }
  372. lfrfid_worker_stop(worker);
  373. lfrfid_worker_stop_thread(worker);
  374. lfrfid_worker_free(worker);
  375. protocol_dict_free(dict);
  376. furi_event_flag_free(event);
  377. } while(false);
  378. string_clear(filepath);
  379. string_clear(type_string);
  380. }
  381. static void lfrfid_cli_raw_emulate_callback(LFRFIDWorkerEmulateRawResult result, void* context) {
  382. furi_assert(context);
  383. FuriEventFlag* event = context;
  384. furi_event_flag_set(event, 1 << result);
  385. }
  386. static void lfrfid_cli_raw_emulate(Cli* cli, string_t args) {
  387. UNUSED(cli);
  388. string_t filepath;
  389. string_init(filepath);
  390. Storage* storage = furi_record_open(RECORD_STORAGE);
  391. do {
  392. if(!args_read_probably_quoted_string_and_trim(args, filepath)) {
  393. lfrfid_cli_print_usage();
  394. break;
  395. }
  396. if(!storage_file_exists(storage, string_get_cstr(filepath))) {
  397. printf("File not found: \"%s\"\r\n", string_get_cstr(filepath));
  398. break;
  399. }
  400. ProtocolDict* dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
  401. LFRFIDWorker* worker = lfrfid_worker_alloc(dict);
  402. FuriEventFlag* event = furi_event_flag_alloc();
  403. lfrfid_worker_start_thread(worker);
  404. bool overrun = false;
  405. const uint32_t available_flags = (1 << LFRFIDWorkerEmulateRawFileError) |
  406. (1 << LFRFIDWorkerEmulateRawOverrun);
  407. lfrfid_worker_emulate_raw_start(
  408. worker, string_get_cstr(filepath), lfrfid_cli_raw_emulate_callback, event);
  409. while(true) {
  410. uint32_t flags = furi_event_flag_wait(event, available_flags, FuriFlagWaitAny, 100);
  411. if(flags != FuriFlagErrorTimeout) {
  412. if(FURI_BIT(flags, LFRFIDWorkerEmulateRawFileError)) {
  413. printf("File is not RFID raw file\r\n");
  414. break;
  415. }
  416. if(FURI_BIT(flags, LFRFIDWorkerEmulateRawOverrun)) {
  417. if(!overrun) {
  418. printf("Overrun\r\n");
  419. overrun = true;
  420. }
  421. }
  422. }
  423. if(cli_cmd_interrupt_received(cli)) break;
  424. }
  425. if(overrun) {
  426. printf("An overrun occurred during emulation\r\n");
  427. }
  428. lfrfid_worker_stop(worker);
  429. lfrfid_worker_stop_thread(worker);
  430. lfrfid_worker_free(worker);
  431. protocol_dict_free(dict);
  432. furi_event_flag_free(event);
  433. } while(false);
  434. furi_record_close(RECORD_STORAGE);
  435. string_clear(filepath);
  436. }
  437. static void lfrfid_cli(Cli* cli, string_t args, void* context) {
  438. UNUSED(context);
  439. string_t cmd;
  440. string_init(cmd);
  441. if(!args_read_string_and_trim(args, cmd)) {
  442. string_clear(cmd);
  443. lfrfid_cli_print_usage();
  444. return;
  445. }
  446. if(string_cmp_str(cmd, "read") == 0) {
  447. lfrfid_cli_read(cli, args);
  448. } else if(string_cmp_str(cmd, "write") == 0) {
  449. lfrfid_cli_write(cli, args);
  450. } else if(string_cmp_str(cmd, "emulate") == 0) {
  451. lfrfid_cli_emulate(cli, args);
  452. } else if(string_cmp_str(cmd, "raw_read") == 0) {
  453. lfrfid_cli_raw_read(cli, args);
  454. } else if(string_cmp_str(cmd, "raw_emulate") == 0) {
  455. lfrfid_cli_raw_emulate(cli, args);
  456. } else if(string_cmp_str(cmd, "raw_analyze") == 0) {
  457. lfrfid_cli_raw_analyze(cli, args);
  458. } else {
  459. lfrfid_cli_print_usage();
  460. }
  461. string_clear(cmd);
  462. }