infrared_controller.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "infrared_controller.h"
  2. #include <furi.h>
  3. #include <infrared_worker.h>
  4. #include <infrared_signal.h>
  5. #include <notification/notification_messages.h>
  6. #define TAG "InfraredController"
  7. const NotificationSequence sequence_hit = {
  8. &message_vibro_on,
  9. &message_note_d4,
  10. &message_delay_1000,
  11. &message_vibro_off,
  12. &message_sound_off,
  13. NULL,
  14. };
  15. struct InfraredController {
  16. LaserTagTeam team;
  17. InfraredWorker* worker;
  18. bool worker_rx_active;
  19. InfraredSignal* signal;
  20. NotificationApp* notification;
  21. bool hit_received;
  22. bool processing_signal;
  23. };
  24. static void infrared_rx_callback(void* context, InfraredWorkerSignal* received_signal) {
  25. FURI_LOG_I(TAG, "RX callback triggered");
  26. InfraredController* controller = (InfraredController*)context;
  27. if(controller->processing_signal) {
  28. FURI_LOG_W(TAG, "Already processing a signal, skipping callback");
  29. return;
  30. }
  31. controller->processing_signal = true;
  32. if(!received_signal) {
  33. FURI_LOG_E(TAG, "Received signal is NULL");
  34. controller->processing_signal = false;
  35. return;
  36. }
  37. const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal);
  38. FURI_LOG_I(TAG, "Received signal - signal address: %p", (void*)received_signal);
  39. if(message) {
  40. FURI_LOG_I(
  41. TAG,
  42. "Received message: protocol=%d, address=0x%lx, command=0x%lx",
  43. message->protocol,
  44. (unsigned long)message->address,
  45. (unsigned long)message->command);
  46. if((controller->team == TeamRed && message->command == IR_COMMAND_BLUE_TEAM) ||
  47. (controller->team == TeamBlue && message->command == IR_COMMAND_RED_TEAM)) {
  48. controller->hit_received = true;
  49. FURI_LOG_I(
  50. TAG, "Hit detected for team: %s", controller->team == TeamRed ? "Red" : "Blue");
  51. notification_message_block(controller->notification, &sequence_hit);
  52. }
  53. } else {
  54. FURI_LOG_W(TAG, "RX callback received NULL message");
  55. }
  56. FURI_LOG_I(TAG, "RX callback completed");
  57. controller->processing_signal = false;
  58. }
  59. InfraredController* infrared_controller_alloc() {
  60. FURI_LOG_I(TAG, "Allocating InfraredController");
  61. InfraredController* controller = malloc(sizeof(InfraredController));
  62. if(!controller) {
  63. FURI_LOG_E(TAG, "Failed to allocate InfraredController");
  64. return NULL;
  65. }
  66. controller->team = TeamRed;
  67. controller->worker = infrared_worker_alloc();
  68. controller->signal = infrared_signal_alloc();
  69. controller->notification = furi_record_open(RECORD_NOTIFICATION);
  70. controller->hit_received = false;
  71. controller->processing_signal = false;
  72. if(controller->worker && controller->signal && controller->notification) {
  73. FURI_LOG_I(
  74. TAG, "InfraredWorker, InfraredSignal, and NotificationApp allocated successfully");
  75. } else {
  76. FURI_LOG_E(TAG, "Failed to allocate resources");
  77. free(controller);
  78. return NULL;
  79. }
  80. FURI_LOG_I(TAG, "Setting up RX callback");
  81. infrared_worker_rx_set_received_signal_callback(
  82. controller->worker, infrared_rx_callback, controller);
  83. FURI_LOG_I(TAG, "InfraredController allocated successfully");
  84. return controller;
  85. }
  86. void infrared_controller_free(InfraredController* controller) {
  87. FURI_LOG_I(TAG, "Freeing InfraredController");
  88. if(controller) {
  89. if(controller->worker_rx_active) {
  90. FURI_LOG_I(TAG, "Stopping RX worker");
  91. infrared_worker_rx_stop(controller->worker);
  92. }
  93. FURI_LOG_I(TAG, "Freeing InfraredWorker and InfraredSignal");
  94. infrared_worker_free(controller->worker);
  95. infrared_signal_free(controller->signal);
  96. FURI_LOG_I(TAG, "Closing NotificationApp");
  97. furi_record_close(RECORD_NOTIFICATION);
  98. free(controller);
  99. FURI_LOG_I(TAG, "InfraredController freed successfully");
  100. } else {
  101. FURI_LOG_W(TAG, "Attempted to free NULL InfraredController");
  102. }
  103. }
  104. void infrared_controller_set_team(InfraredController* controller, LaserTagTeam team) {
  105. FURI_LOG_I(TAG, "Setting team to %s", team == TeamRed ? "Red" : "Blue");
  106. controller->team = team;
  107. }
  108. void infrared_controller_send(InfraredController* controller) {
  109. FURI_LOG_I(TAG, "Preparing to send infrared signal");
  110. InfraredMessage message = {
  111. .protocol = InfraredProtocolNEC,
  112. .address = 0x42,
  113. .command = (controller->team == TeamRed) ? IR_COMMAND_RED_TEAM : IR_COMMAND_BLUE_TEAM};
  114. FURI_LOG_I(
  115. TAG,
  116. "Prepared message: protocol=%d, address=0x%lx, command=0x%lx",
  117. message.protocol,
  118. (unsigned long)message.address,
  119. (unsigned long)message.command);
  120. if(controller->worker_rx_active) {
  121. FURI_LOG_I(TAG, "Stopping RX worker");
  122. infrared_worker_rx_stop(controller->worker);
  123. controller->worker_rx_active = false;
  124. }
  125. FURI_LOG_I(TAG, "Setting message for infrared signal");
  126. infrared_signal_set_message(controller->signal, &message);
  127. FURI_LOG_I(TAG, "Starting infrared signal transmission");
  128. infrared_signal_transmit(controller->signal);
  129. if(!controller->worker_rx_active) {
  130. infrared_worker_rx_start(controller->worker);
  131. controller->worker_rx_active = true;
  132. }
  133. FURI_LOG_I(TAG, "Infrared signal transmission completed");
  134. }
  135. bool infrared_controller_receive(InfraredController* controller) {
  136. FURI_LOG_I(TAG, "Starting infrared signal reception");
  137. if(controller->processing_signal) {
  138. FURI_LOG_W(TAG, "Cannot start reception, another signal is still being processed");
  139. return false;
  140. }
  141. if(!controller->worker_rx_active) {
  142. infrared_worker_rx_start(controller->worker);
  143. controller->worker_rx_active = true;
  144. furi_delay_ms(250);
  145. }
  146. bool hit = controller->hit_received;
  147. FURI_LOG_I(TAG, "Signal reception complete, hit received: %s", hit ? "true" : "false");
  148. controller->hit_received = false;
  149. return hit;
  150. }
  151. void infrared_controller_pause(InfraredController* controller) {
  152. if(controller->worker_rx_active) {
  153. FURI_LOG_I(TAG, "Stopping RX worker");
  154. infrared_worker_rx_stop(controller->worker);
  155. controller->worker_rx_active = false;
  156. }
  157. }
  158. void infrared_controller_resume(InfraredController* controller) {
  159. if(!controller->worker_rx_active) {
  160. FURI_LOG_I(TAG, "Starting RX worker");
  161. infrared_worker_rx_start(controller->worker);
  162. controller->worker_rx_active = true;
  163. }
  164. }