infrared_controller.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "infrared_controller.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. #include <infrared.h>
  5. #include <infrared_worker.h>
  6. #include <stdlib.h>
  7. #define TAG "InfraredController"
  8. struct InfraredController {
  9. LaserTagTeam team;
  10. InfraredWorker* worker;
  11. FuriThread* rx_thread;
  12. volatile bool rx_running;
  13. volatile bool hit_received;
  14. FuriMutex* mutex;
  15. };
  16. static void infrared_rx_callback(void* context, InfraredWorkerSignal* received_signal) {
  17. FURI_LOG_D(TAG, "RX callback triggered");
  18. furi_assert(context);
  19. furi_assert(received_signal);
  20. InfraredController* controller = (InfraredController*)context;
  21. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  22. FURI_LOG_D(TAG, "Context and received signal validated");
  23. const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
  24. if(message != NULL) {
  25. uint32_t received_command = message->address;
  26. FURI_LOG_D(TAG, "Received command: 0x%lx", (unsigned long)received_command);
  27. if((controller->team == TeamRed && received_command == IR_COMMAND_BLUE_TEAM) ||
  28. (controller->team == TeamBlue && received_command == IR_COMMAND_RED_TEAM)) {
  29. controller->hit_received = true;
  30. FURI_LOG_D(
  31. TAG, "Hit detected for team: %s", controller->team == TeamRed ? "Red" : "Blue");
  32. }
  33. } else {
  34. FURI_LOG_E(TAG, "Received NULL message");
  35. }
  36. furi_mutex_release(controller->mutex);
  37. }
  38. static int32_t infrared_rx_thread(void* context) {
  39. FURI_LOG_D(TAG, "RX thread started");
  40. furi_assert(context);
  41. InfraredController* controller = (InfraredController*)context;
  42. while(controller->rx_running) {
  43. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  44. FURI_LOG_D(TAG, "Starting infrared_worker_rx_start");
  45. // Check for worker validity before starting
  46. if(controller->worker) {
  47. infrared_worker_rx_start(controller->worker);
  48. FURI_LOG_D(TAG, "infrared_worker_rx_start succeeded");
  49. } else {
  50. FURI_LOG_E(TAG, "InfraredWorker is NULL");
  51. furi_mutex_release(controller->mutex);
  52. continue;
  53. }
  54. furi_mutex_release(controller->mutex);
  55. FURI_LOG_D(TAG, "Waiting for thread flags");
  56. FuriStatus status = furi_thread_flags_wait(0, FuriFlagWaitAny, 10);
  57. if(status == FuriStatusErrorTimeout) {
  58. FURI_LOG_D(TAG, "RX loop timeout, continuing");
  59. } else {
  60. FURI_LOG_D(TAG, "RX loop received flag: %d", status);
  61. }
  62. }
  63. FURI_LOG_D(TAG, "RX thread stopping");
  64. return 0;
  65. }
  66. InfraredController* infrared_controller_alloc() {
  67. FURI_LOG_D(TAG, "Allocating InfraredController");
  68. InfraredController* controller = malloc(sizeof(InfraredController));
  69. if(!controller) {
  70. FURI_LOG_E(TAG, "Failed to allocate InfraredController struct");
  71. return NULL;
  72. }
  73. FURI_LOG_D(TAG, "InfraredController struct allocated");
  74. controller->team = TeamRed;
  75. FURI_LOG_D(TAG, "Team initialized to Red");
  76. FURI_LOG_D(TAG, "Allocating InfraredWorker");
  77. controller->worker = infrared_worker_alloc();
  78. if(!controller->worker) {
  79. FURI_LOG_E(TAG, "Failed to allocate InfraredWorker");
  80. free(controller);
  81. return NULL;
  82. }
  83. FURI_LOG_D(TAG, "InfraredWorker allocated");
  84. controller->rx_running = true;
  85. controller->hit_received = false;
  86. FURI_LOG_D(TAG, "Creating mutex");
  87. controller->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  88. if(!controller->mutex) {
  89. FURI_LOG_E(TAG, "Failed to create mutex");
  90. infrared_worker_free(controller->worker);
  91. free(controller);
  92. return NULL;
  93. }
  94. FURI_LOG_D(TAG, "Setting up RX callback");
  95. infrared_worker_rx_set_received_signal_callback(
  96. controller->worker, infrared_rx_callback, controller);
  97. FURI_LOG_D(TAG, "Allocating RX thread");
  98. controller->rx_thread = furi_thread_alloc();
  99. if(!controller->rx_thread) {
  100. FURI_LOG_E(TAG, "Failed to allocate RX thread");
  101. furi_mutex_free(controller->mutex);
  102. infrared_worker_free(controller->worker);
  103. free(controller);
  104. return NULL;
  105. }
  106. furi_thread_set_name(controller->rx_thread, "IR_Rx_Thread");
  107. furi_thread_set_stack_size(controller->rx_thread, 1024);
  108. furi_thread_set_context(controller->rx_thread, controller);
  109. furi_thread_set_callback(controller->rx_thread, infrared_rx_thread);
  110. FURI_LOG_D(TAG, "Starting RX thread");
  111. furi_thread_start(controller->rx_thread);
  112. FURI_LOG_D(TAG, "Starting InfraredWorker RX");
  113. infrared_worker_rx_start(controller->worker);
  114. FURI_LOG_D(TAG, "InfraredController allocated successfully");
  115. return controller;
  116. }
  117. void infrared_controller_free(InfraredController* controller) {
  118. FURI_LOG_D(TAG, "Freeing InfraredController");
  119. furi_assert(controller);
  120. controller->rx_running = false;
  121. FURI_LOG_D(TAG, "Stopping RX thread");
  122. furi_thread_join(controller->rx_thread);
  123. furi_thread_free(controller->rx_thread);
  124. FURI_LOG_D(TAG, "Stopping InfraredWorker RX");
  125. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  126. infrared_worker_rx_stop(controller->worker);
  127. infrared_worker_free(controller->worker);
  128. furi_mutex_release(controller->mutex);
  129. furi_mutex_free(controller->mutex);
  130. free(controller);
  131. FURI_LOG_D(TAG, "InfraredController freed");
  132. }
  133. void infrared_controller_set_team(InfraredController* controller, LaserTagTeam team) {
  134. furi_assert(controller);
  135. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  136. controller->team = team;
  137. furi_mutex_release(controller->mutex);
  138. FURI_LOG_D(TAG, "Team set to %s", (team == TeamRed) ? "Red" : "Blue");
  139. }
  140. void infrared_controller_send(InfraredController* controller) {
  141. FURI_LOG_D(TAG, "Sending IR signal");
  142. furi_assert(controller);
  143. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  144. uint32_t command = (controller->team == TeamRed) ? IR_COMMAND_RED_TEAM : IR_COMMAND_BLUE_TEAM;
  145. InfraredMessage message = {
  146. .protocol = InfraredProtocolNEC, .address = 0x00, .command = command, .repeat = false};
  147. infrared_worker_set_decoded_signal(controller->worker, &message);
  148. FURI_LOG_D(TAG, "Starting IR transmission");
  149. infrared_worker_tx_set_get_signal_callback(
  150. controller->worker, infrared_worker_tx_get_signal_steady_callback, NULL);
  151. infrared_worker_tx_start(controller->worker);
  152. furi_delay_ms(250);
  153. infrared_worker_tx_stop(controller->worker);
  154. FURI_LOG_D(TAG, "IR signal sent");
  155. furi_mutex_release(controller->mutex);
  156. }
  157. bool infrared_controller_receive(InfraredController* controller) {
  158. furi_assert(controller);
  159. furi_mutex_acquire(controller->mutex, FuriWaitForever);
  160. bool hit = controller->hit_received;
  161. controller->hit_received = false;
  162. furi_mutex_release(controller->mutex);
  163. FURI_LOG_D(TAG, "Checking for hit: %s", hit ? "Hit received" : "No hit");
  164. return hit;
  165. }