ibutton_worker.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <atomic.h>
  4. #include "ibutton_worker_i.h"
  5. typedef enum {
  6. iButtonMessageEnd,
  7. iButtonMessageStop,
  8. iButtonMessageRead,
  9. iButtonMessageWrite,
  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() {
  21. iButtonWorker* worker = malloc(sizeof(iButtonWorker));
  22. worker->key_p = NULL;
  23. worker->key_data = malloc(ibutton_key_get_max_size());
  24. worker->host = onewire_host_alloc();
  25. worker->slave = onewire_slave_alloc();
  26. worker->writer = ibutton_writer_alloc(worker->host);
  27. worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0);
  28. worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage));
  29. worker->mode_index = iButtonWorkerIdle;
  30. worker->read_cb = NULL;
  31. worker->write_cb = NULL;
  32. worker->emulate_cb = NULL;
  33. worker->cb_ctx = NULL;
  34. worker->thread = furi_thread_alloc_ex("iButtonWorker", 2048, ibutton_worker_thread, worker);
  35. worker->protocols = protocol_dict_alloc(ibutton_protocols, iButtonProtocolMax);
  36. return worker;
  37. }
  38. void ibutton_worker_read_set_callback(
  39. iButtonWorker* worker,
  40. iButtonWorkerReadCallback callback,
  41. void* context) {
  42. furi_check(worker->mode_index == iButtonWorkerIdle);
  43. worker->read_cb = callback;
  44. worker->cb_ctx = context;
  45. }
  46. void ibutton_worker_write_set_callback(
  47. iButtonWorker* worker,
  48. iButtonWorkerWriteCallback callback,
  49. void* context) {
  50. furi_check(worker->mode_index == iButtonWorkerIdle);
  51. worker->write_cb = callback;
  52. worker->cb_ctx = context;
  53. }
  54. void ibutton_worker_emulate_set_callback(
  55. iButtonWorker* worker,
  56. iButtonWorkerEmulateCallback callback,
  57. void* context) {
  58. furi_check(worker->mode_index == iButtonWorkerIdle);
  59. worker->emulate_cb = callback;
  60. worker->cb_ctx = context;
  61. }
  62. void ibutton_worker_read_start(iButtonWorker* worker, iButtonKey* key) {
  63. iButtonMessage message = {.type = iButtonMessageRead, .data.key = key};
  64. furi_check(
  65. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  66. }
  67. void ibutton_worker_write_start(iButtonWorker* worker, iButtonKey* key) {
  68. iButtonMessage message = {.type = iButtonMessageWrite, .data.key = key};
  69. furi_check(
  70. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  71. }
  72. void ibutton_worker_emulate_start(iButtonWorker* worker, iButtonKey* key) {
  73. iButtonMessage message = {.type = iButtonMessageEmulate, .data.key = key};
  74. furi_check(
  75. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  76. }
  77. void ibutton_worker_stop(iButtonWorker* worker) {
  78. iButtonMessage message = {.type = iButtonMessageStop};
  79. furi_check(
  80. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  81. }
  82. void ibutton_worker_free(iButtonWorker* worker) {
  83. ibutton_writer_free(worker->writer);
  84. onewire_slave_free(worker->slave);
  85. onewire_host_free(worker->host);
  86. onewire_device_free(worker->device);
  87. protocol_dict_free(worker->protocols);
  88. furi_message_queue_free(worker->messages);
  89. furi_thread_free(worker->thread);
  90. free(worker->key_data);
  91. free(worker);
  92. }
  93. void ibutton_worker_start_thread(iButtonWorker* worker) {
  94. furi_thread_start(worker->thread);
  95. }
  96. void ibutton_worker_stop_thread(iButtonWorker* worker) {
  97. iButtonMessage message = {.type = iButtonMessageEnd};
  98. furi_check(
  99. furi_message_queue_put(worker->messages, &message, FuriWaitForever) == FuriStatusOk);
  100. furi_thread_join(worker->thread);
  101. }
  102. void ibutton_worker_switch_mode(iButtonWorker* worker, iButtonWorkerMode mode) {
  103. ibutton_worker_modes[worker->mode_index].stop(worker);
  104. worker->mode_index = mode;
  105. ibutton_worker_modes[worker->mode_index].start(worker);
  106. }
  107. void ibutton_worker_notify_emulate(iButtonWorker* worker) {
  108. iButtonMessage message = {.type = iButtonMessageNotifyEmulate};
  109. furi_check(furi_message_queue_put(worker->messages, &message, 0) == FuriStatusOk);
  110. }
  111. void ibutton_worker_set_key_p(iButtonWorker* worker, iButtonKey* key) {
  112. worker->key_p = key;
  113. }
  114. static int32_t ibutton_worker_thread(void* thread_context) {
  115. iButtonWorker* worker = thread_context;
  116. bool running = true;
  117. iButtonMessage message;
  118. FuriStatus status;
  119. ibutton_worker_modes[worker->mode_index].start(worker);
  120. while(running) {
  121. status = furi_message_queue_get(
  122. worker->messages, &message, ibutton_worker_modes[worker->mode_index].quant);
  123. if(status == FuriStatusOk) {
  124. switch(message.type) {
  125. case iButtonMessageEnd:
  126. ibutton_worker_switch_mode(worker, iButtonWorkerIdle);
  127. ibutton_worker_set_key_p(worker, NULL);
  128. running = false;
  129. break;
  130. case iButtonMessageStop:
  131. ibutton_worker_switch_mode(worker, iButtonWorkerIdle);
  132. ibutton_worker_set_key_p(worker, NULL);
  133. break;
  134. case iButtonMessageRead:
  135. ibutton_worker_set_key_p(worker, message.data.key);
  136. ibutton_worker_switch_mode(worker, iButtonWorkerRead);
  137. break;
  138. case iButtonMessageWrite:
  139. ibutton_worker_set_key_p(worker, message.data.key);
  140. ibutton_worker_switch_mode(worker, iButtonWorkerWrite);
  141. break;
  142. case iButtonMessageEmulate:
  143. ibutton_worker_set_key_p(worker, message.data.key);
  144. ibutton_worker_switch_mode(worker, iButtonWorkerEmulate);
  145. break;
  146. case iButtonMessageNotifyEmulate:
  147. if(worker->emulate_cb) {
  148. worker->emulate_cb(worker->cb_ctx, true);
  149. }
  150. break;
  151. }
  152. } else if(status == FuriStatusErrorTimeout) {
  153. ibutton_worker_modes[worker->mode_index].tick(worker);
  154. } else {
  155. furi_crash("iButton worker error");
  156. }
  157. }
  158. ibutton_worker_modes[worker->mode_index].stop(worker);
  159. return 0;
  160. }