lf-rfid.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include <furi.h>
  2. #include <api-hal.h>
  3. #include <gui/gui.h>
  4. #include <stream_buffer.h>
  5. typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
  6. typedef struct {
  7. uint8_t dummy;
  8. } RxEvent;
  9. typedef struct {
  10. union {
  11. InputEvent input;
  12. RxEvent rx;
  13. } value;
  14. EventType type;
  15. } AppEvent;
  16. typedef struct {
  17. uint32_t freq_khz;
  18. bool on;
  19. uint8_t customer_id;
  20. uint32_t em_data;
  21. bool dirty;
  22. bool dirty_freq;
  23. } State;
  24. static void render_callback(Canvas* canvas, void* ctx) {
  25. State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
  26. canvas_clear(canvas);
  27. canvas_set_color(canvas, ColorBlack);
  28. canvas_set_font(canvas, FontPrimary);
  29. canvas_draw_str(canvas, 2, 12, "LF RFID");
  30. canvas_draw_str(canvas, 2, 24, state->on ? "Reading" : "Emulating");
  31. char buf[30];
  32. snprintf(buf, sizeof(buf), "%d kHz", (int)state->freq_khz);
  33. canvas_draw_str(canvas, 2, 36, buf);
  34. snprintf(buf, sizeof(buf), "%02d:%010ld", state->customer_id, state->em_data);
  35. canvas_draw_str(canvas, 2, 45, buf);
  36. release_mutex((ValueMutex*)ctx, state);
  37. }
  38. static void input_callback(InputEvent* input_event, void* ctx) {
  39. osMessageQueueId_t event_queue = ctx;
  40. if(input_event->type != InputTypeShort) return;
  41. AppEvent event;
  42. event.type = EventTypeKey;
  43. event.value.input = *input_event;
  44. osMessageQueuePut(event_queue, &event, 1, osWaitForever);
  45. }
  46. extern TIM_HandleTypeDef TIM_C;
  47. void em4100_emulation(uint8_t* data, GpioPin* pin);
  48. void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data);
  49. GpioPin debug_0 = {.pin = GPIO_PIN_2, .port = GPIOB};
  50. GpioPin debug_1 = {.pin = GPIO_PIN_3, .port = GPIOC};
  51. extern COMP_HandleTypeDef hcomp1;
  52. typedef struct {
  53. osMessageQueueId_t event_queue;
  54. uint32_t prev_dwt;
  55. int8_t symbol;
  56. bool center;
  57. size_t symbol_cnt;
  58. StreamBufferHandle_t stream_buffer;
  59. uint8_t* int_buffer;
  60. } ComparatorCtx;
  61. void init_comp_ctx(ComparatorCtx* ctx) {
  62. ctx->prev_dwt = 0;
  63. ctx->symbol = -1; // init state
  64. ctx->center = false;
  65. ctx->symbol_cnt = 0;
  66. xStreamBufferReset(ctx->stream_buffer);
  67. for(size_t i = 0; i < 64; i++) {
  68. ctx->int_buffer[i] = 0;
  69. }
  70. }
  71. void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
  72. ComparatorCtx* ctx = (ComparatorCtx*)comp_ctx;
  73. uint32_t dt = (DWT->CYCCNT - ctx->prev_dwt) / (SystemCoreClock / 1000000.0f);
  74. ctx->prev_dwt = DWT->CYCCNT;
  75. if(dt < 150) return; // supress noise
  76. // wait message will be consumed
  77. if(xStreamBufferBytesAvailable(ctx->stream_buffer) == 64) return;
  78. hal_gpio_write(&debug_0, true);
  79. // TOOD F4 and F5 differ
  80. bool rx_value = hal_gpio_get_rfid_in_level();
  81. if(dt > 384) {
  82. // change symbol 0->1 or 1->0
  83. ctx->symbol = rx_value;
  84. ctx->center = true;
  85. } else {
  86. // same symbol as prev or center
  87. ctx->center = !ctx->center;
  88. }
  89. /*
  90. hal_gpio_write(&debug_1, true);
  91. delay_us(center ? 10 : 30);
  92. hal_gpio_write(&debug_1, false);
  93. */
  94. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  95. if(ctx->center && ctx->symbol != -1) {
  96. /*
  97. hal_gpio_write(&debug_0, true);
  98. delay_us(symbol ? 10 : 30);
  99. hal_gpio_write(&debug_0, false);
  100. */
  101. ctx->int_buffer[ctx->symbol_cnt] = ctx->symbol;
  102. ctx->symbol_cnt++;
  103. }
  104. // check preamble
  105. if(ctx->symbol_cnt <= 9 && ctx->symbol == 0) {
  106. ctx->symbol_cnt = 0;
  107. ctx->symbol = -1;
  108. }
  109. // check stop bit
  110. if(ctx->symbol_cnt == 64 && ctx->symbol == 1) {
  111. ctx->symbol_cnt = 0;
  112. ctx->symbol = -1;
  113. }
  114. // TODO
  115. // write only 9..64 symbols directly to streambuffer
  116. if(ctx->symbol_cnt == 64) {
  117. if(xStreamBufferSendFromISR(
  118. ctx->stream_buffer, ctx->int_buffer, 64, &xHigherPriorityTaskWoken) == 64) {
  119. AppEvent event;
  120. event.type = EventTypeRx;
  121. osMessageQueuePut(ctx->event_queue, &event, 0, 0);
  122. }
  123. ctx->symbol_cnt = 0;
  124. }
  125. hal_gpio_write(&debug_0, false);
  126. portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  127. }
  128. const uint8_t ROW_SIZE = 4;
  129. const uint8_t LINE_SIZE = 10;
  130. static bool even_check(uint8_t* buf) {
  131. uint8_t col_parity_sum[ROW_SIZE];
  132. for(uint8_t col = 0; col < ROW_SIZE; col++) {
  133. col_parity_sum[col] = 0;
  134. }
  135. // line parity
  136. for(uint8_t line = 0; line < LINE_SIZE; line++) {
  137. printf("%d: ", line);
  138. uint8_t parity_sum = 0;
  139. for(uint8_t col = 0; col < ROW_SIZE; col++) {
  140. parity_sum += buf[line * (ROW_SIZE + 1) + col];
  141. col_parity_sum[col] += buf[line * (ROW_SIZE + 1) + col];
  142. printf("%d ", buf[line * (ROW_SIZE + 1) + col]);
  143. }
  144. if((1 & parity_sum) != buf[line * (ROW_SIZE + 1) + ROW_SIZE]) {
  145. printf(
  146. "line parity fail at %d (%d : %d)\n",
  147. line,
  148. parity_sum,
  149. buf[line * (ROW_SIZE + 1) + ROW_SIZE]);
  150. return false;
  151. }
  152. printf("\r\n");
  153. }
  154. for(uint8_t col = 0; col < ROW_SIZE; col++) {
  155. if((1 & col_parity_sum[col]) != buf[LINE_SIZE * (ROW_SIZE + 1) + col]) {
  156. printf(
  157. "col parity fail at %d (%d : %d)\n",
  158. col,
  159. col_parity_sum[col],
  160. buf[LINE_SIZE * (ROW_SIZE + 1) + col]);
  161. return false;
  162. }
  163. }
  164. return true;
  165. }
  166. static void extract_data(uint8_t* buf, uint8_t* customer, uint32_t* em_data) {
  167. uint32_t data = 0;
  168. uint8_t offset = 0;
  169. printf("customer: ");
  170. for(uint8_t line = 0; line < 2; line++) {
  171. for(uint8_t col = 0; col < ROW_SIZE; col++) {
  172. uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
  173. data |= bit << (7 - offset);
  174. printf("%ld ", bit);
  175. offset++;
  176. }
  177. }
  178. printf("\r\n");
  179. *customer = data;
  180. data = 0;
  181. offset = 0;
  182. printf("data: ");
  183. for(uint8_t line = 2; line < LINE_SIZE; line++) {
  184. for(uint8_t col = 0; col < ROW_SIZE; col++) {
  185. uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
  186. data |= bit << (31 - offset);
  187. printf("%ld ", bit);
  188. offset++;
  189. }
  190. }
  191. printf("\r\n");
  192. *em_data = data;
  193. }
  194. int32_t lf_rfid_workaround(void* p) {
  195. osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
  196. // create pin
  197. GpioPin pull_pin = {.pin = RFID_PULL_Pin, .port = RFID_PULL_GPIO_Port};
  198. // TODO open record
  199. GpioPin* pull_pin_record = &pull_pin;
  200. hal_gpio_init(pull_pin_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  201. hal_gpio_init(&debug_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  202. hal_gpio_init(&debug_1, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
  203. // pulldown iBtn pin to prevent interference from ibutton
  204. hal_gpio_init((GpioPin*)&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
  205. hal_gpio_write((GpioPin*)&ibutton_gpio, false);
  206. // init ctx
  207. ComparatorCtx comp_ctx;
  208. // internal buffer
  209. uint8_t int_bufer[64];
  210. comp_ctx.stream_buffer = xStreamBufferCreate(64, 64);
  211. comp_ctx.int_buffer = int_bufer;
  212. comp_ctx.event_queue = event_queue;
  213. init_comp_ctx(&comp_ctx);
  214. if(comp_ctx.stream_buffer == NULL) {
  215. printf("cannot create stream buffer\r\n");
  216. return 255;
  217. }
  218. // start comp
  219. HAL_COMP_Start(&hcomp1);
  220. uint8_t raw_data[64];
  221. for(size_t i = 0; i < 64; i++) {
  222. raw_data[i] = 0;
  223. }
  224. State _state;
  225. _state.freq_khz = 125;
  226. _state.on = false;
  227. _state.customer_id = 00;
  228. _state.em_data = 4378151;
  229. _state.dirty = true;
  230. _state.dirty_freq = true;
  231. ValueMutex state_mutex;
  232. if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
  233. printf("cannot create mutex\r\n");
  234. return 255;
  235. }
  236. ViewPort* view_port = view_port_alloc();
  237. view_port_draw_callback_set(view_port, render_callback, &state_mutex);
  238. view_port_input_callback_set(view_port, input_callback, event_queue);
  239. // Open GUI and register view_port
  240. Gui* gui = furi_record_open("gui");
  241. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  242. AppEvent event;
  243. while(1) {
  244. osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 1024 / 8);
  245. if(event.type == EventTypeRx && event_status == osOK) {
  246. size_t received = xStreamBufferReceive(comp_ctx.stream_buffer, raw_data, 64, 0);
  247. printf("received: %d\r\n", received);
  248. if(received == 64) {
  249. if(even_check(&raw_data[9])) {
  250. State* state = (State*)acquire_mutex_block(&state_mutex);
  251. extract_data(&raw_data[9], &state->customer_id, &state->em_data);
  252. printf("customer: %02d, data: %010lu\n", state->customer_id, state->em_data);
  253. release_mutex(&state_mutex, state);
  254. view_port_update(view_port);
  255. api_hal_light_set(LightGreen, 0xFF);
  256. osDelay(50);
  257. api_hal_light_set(LightGreen, 0x00);
  258. }
  259. }
  260. } else {
  261. State* state = (State*)acquire_mutex_block(&state_mutex);
  262. if(event_status == osOK) {
  263. if(event.type == EventTypeKey) {
  264. // press events
  265. if(event.value.input.key == InputKeyBack) {
  266. break;
  267. }
  268. if(event.value.input.key == InputKeyUp) {
  269. state->dirty_freq = true;
  270. state->freq_khz += 10;
  271. }
  272. if(event.value.input.key == InputKeyDown) {
  273. state->dirty_freq = true;
  274. state->freq_khz -= 10;
  275. }
  276. if(event.value.input.key == InputKeyLeft) {
  277. }
  278. if(event.value.input.key == InputKeyRight) {
  279. }
  280. if(event.value.input.key == InputKeyOk) {
  281. state->dirty = true;
  282. state->on = !state->on;
  283. }
  284. }
  285. } else {
  286. // event timeout
  287. }
  288. if(state->dirty) {
  289. if(state->on) {
  290. hal_gpio_write(pull_pin_record, false);
  291. init_comp_ctx(&comp_ctx);
  292. api_interrupt_add(
  293. comparator_trigger_callback, InterruptTypeComparatorTrigger, &comp_ctx);
  294. } else {
  295. prepare_data(state->em_data, state->customer_id, raw_data);
  296. api_interrupt_remove(
  297. comparator_trigger_callback, InterruptTypeComparatorTrigger);
  298. }
  299. state->dirty_freq = true; // config new PWM next
  300. state->dirty = false;
  301. }
  302. if(state->dirty_freq) {
  303. hal_pwmn_set(
  304. state->on ? 0.5 : 0.0, (float)(state->freq_khz * 1000), &LFRFID_TIM, LFRFID_CH);
  305. state->dirty_freq = false;
  306. }
  307. if(!state->on) {
  308. em4100_emulation(raw_data, pull_pin_record);
  309. }
  310. release_mutex(&state_mutex, state);
  311. view_port_update(view_port);
  312. }
  313. }
  314. hal_pwmn_stop(&TIM_C, TIM_CHANNEL_1); // TODO: move to furiac_onexit
  315. api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger);
  316. hal_gpio_init(pull_pin_record, GpioModeInput, GpioPullNo, GpioSpeedLow);
  317. hal_gpio_init((GpioPin*)&ibutton_gpio, GpioModeInput, GpioPullNo, GpioSpeedLow);
  318. // TODO remove all view_ports create by app
  319. view_port_enabled_set(view_port, false);
  320. gui_remove_view_port(gui, view_port);
  321. view_port_free(view_port);
  322. HAL_COMP_Stop(&hcomp1);
  323. vStreamBufferDelete(comp_ctx.stream_buffer);
  324. osMessageQueueDelete(event_queue);
  325. return 0;
  326. }