ibutton_worker.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "ibutton_worker_i.h"
  2. #include "ibutton_protocols.h"
  3. #include <core/check.h>
  4. typedef enum {
  5. iButtonMessageEnd,
  6. iButtonMessageStop,
  7. iButtonMessageRead,
  8. iButtonMessageWriteBlank,
  9. iButtonMessageWriteCopy,
  10. iButtonMessageEmulate,
  11. iButtonMessageNotifyEmulate,
  12. } iButtonMessageType;
  13. typedef struct {
  14. iButtonMessageType type;
  15. union {
  16. iButtonKey* key;
  17. } data;
  18. } iButtonMessage;
  19. static int32_t ibutton_worker_thread(void* thread_context);
  20. iButtonWorker* ibutton_worker_alloc(iButtonProtocols* protocols) {
  21. iButtonWorker* worker = malloc(sizeof(iButtonWorker));
  22. worker->protocols = protocols;
  23. worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage));
  24. worker->mode_index = iButtonWorkerModeIdle;
  25. worker->thread = furi_thread_alloc_ex("iButtonWorker", 2048, ibutton_worker_thread, worker);
  26. return worker;
  27. }
  28. void ibutton_worker_read_set_callback(
  29. iButtonWorker* worker,
  30. iButtonWorkerReadCallback callback,
  31. void* context) {
  32. furi_check(worker->mode_index == iButtonWorkerModeIdle);
  33. worker->read_cb = callback;
  34. worker->cb_ctx = context;
  35. }
  36. void ibutton_worker_write_set_callback(
  37. iButtonWorker* worker,
  38. iButtonWorkerWriteCallback callback,
  39. void* context) {
  40. furi_check(worker->mode_index == iButtonWorkerModeIdle);
  41. worker->write_cb = callback;
  42. worker->cb_ctx = context;
  43. }
  44. void ibutton_worker_emulate_set_callback(
  45. iButtonWorker* worker,
  46. iButtonWorkerEmulateCallback callback,
  47. void* context) {
  48. furi_check(worker->mode_index == iButtonWorkerModeIdle);
  49. worker->emulate_cb = callback;
  50. worker->cb_ctx = context;
  51. }
  52. void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key) {
  53. iButtonMessage message = {.type = iButtonMessageRead, .data.key = key};
  54. furi_check(
  55. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  56. }
  57. void ibutton_worker_write_blank_start(iButtonWorker* worker, iButtonKey* key) {
  58. iButtonMessage message = {.type = iButtonMessageWriteBlank, .data.key = key};
  59. furi_check(
  60. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  61. }
  62. void ibutton_worker_write_copy_start(iButtonWorker* worker, iButtonKey* key) {
  63. iButtonMessage message = {.type = iButtonMessageWriteCopy, .data.key = key};
  64. furi_check(
  65. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  66. }
  67. void ibutton_worker_emulate_start(iButtonWorker* worker, iButtonKey* key) {
  68. iButtonMessage message = {.type = iButtonMessageEmulate, .data.key = key};
  69. furi_check(
  70. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  71. }
  72. void ibutton_worker_stop(iButtonWorker* worker) {
  73. iButtonMessage message = {.type = iButtonMessageStop};
  74. furi_check(
  75. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  76. }
  77. void ibutton_worker_free(iButtonWorker* worker) {
  78. furi_message_queue_free(worker->messages);
  79. furi_thread_free(worker->thread);
  80. free(worker);
  81. }
  82. void ibutton_worker_start_thread(iButtonWorker* worker) {
  83. furi_thread_start(worker->thread);
  84. }
  85. void ibutton_worker_stop_thread(iButtonWorker* worker) {
  86. iButtonMessage message = {.type = iButtonMessageEnd};
  87. furi_check(
  88. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  89. furi_thread_join(worker->thread);
  90. }
  91. void ibutton_worker_switch_mode(iButtonWorker* worker, iButtonWorkerMode mode) {
  92. ibutton_worker_modes[worker->mode_index].stop(worker);
  93. worker->mode_index = mode;
  94. ibutton_worker_modes[worker->mode_index].start(worker);
  95. }
  96. void ibutton_worker_notify_emulate(iButtonWorker* worker) {
  97. iButtonMessage message = {.type = iButtonMessageNotifyEmulate};
  98. // we're running in an interrupt context, so we can't wait
  99. // and we can drop message if queue is full, that's ok for that message
  100. furi_message_queue_put(worker->messages, &message, 0);
  101. }
  102. void ibutton_worker_set_key_p(iButtonWorker* worker, iButtonKey* key) {
  103. worker->key = key;
  104. }
  105. static int32_t ibutton_worker_thread(void* thread_context) {
  106. iButtonWorker* worker = thread_context;
  107. bool running = true;
  108. iButtonMessage message;
  109. FuriStatus status;
  110. ibutton_worker_modes[worker->mode_index].start(worker);
  111. while(running) {
  112. status = furi_message_queue_get(
  113. worker->messages, &message, ibutton_worker_modes[worker->mode_index].quant);
  114. if(status == FuriStatusOk) {
  115. switch(message.type) {
  116. case iButtonMessageEnd:
  117. ibutton_worker_switch_mode(worker, iButtonWorkerModeIdle);
  118. ibutton_worker_set_key_p(worker, NULL);
  119. running = false;
  120. break;
  121. case iButtonMessageStop:
  122. ibutton_worker_switch_mode(worker, iButtonWorkerModeIdle);
  123. ibutton_worker_set_key_p(worker, NULL);
  124. break;
  125. case iButtonMessageRead:
  126. ibutton_worker_set_key_p(worker, message.data.key);
  127. ibutton_worker_switch_mode(worker, iButtonWorkerModeRead);
  128. break;
  129. case iButtonMessageWriteBlank:
  130. ibutton_worker_set_key_p(worker, message.data.key);
  131. ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteBlank);
  132. break;
  133. case iButtonMessageWriteCopy:
  134. ibutton_worker_set_key_p(worker, message.data.key);
  135. ibutton_worker_switch_mode(worker, iButtonWorkerModeWriteCopy);
  136. break;
  137. case iButtonMessageEmulate:
  138. ibutton_worker_set_key_p(worker, message.data.key);
  139. ibutton_worker_switch_mode(worker, iButtonWorkerModeEmulate);
  140. break;
  141. case iButtonMessageNotifyEmulate:
  142. if(worker->emulate_cb) {
  143. worker->emulate_cb(worker->cb_ctx, true);
  144. }
  145. break;
  146. }
  147. } else if(status == FuriStatusErrorTimeout) {
  148. ibutton_worker_modes[worker->mode_index].tick(worker);
  149. } else {
  150. furi_crash("iButton worker error");
  151. }
  152. }
  153. ibutton_worker_modes[worker->mode_index].stop(worker);
  154. return 0;
  155. }