bt.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "bt_i.h"
  2. uint32_t bt_view_exit(void* context) {
  3. (void)context;
  4. return VIEW_NONE;
  5. }
  6. void bt_update_statusbar(void* arg) {
  7. furi_assert(arg);
  8. Bt* bt = arg;
  9. BtMessage m = {.type = BtMessageTypeUpdateStatusbar};
  10. furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
  11. }
  12. void bt_switch_freq(void* arg) {
  13. furi_assert(arg);
  14. Bt* bt = arg;
  15. BtMessage m = {.type = BtMessageTypeStartTestToneTx};
  16. furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
  17. }
  18. Bt* bt_alloc() {
  19. Bt* bt = furi_alloc(sizeof(Bt));
  20. bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL);
  21. bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL);
  22. osTimerStart(bt->update_status_timer, 4000);
  23. bt->hopping_mode_timer = osTimerNew(bt_switch_freq, osTimerPeriodic, bt, NULL);
  24. bt->gui = furi_record_open("gui");
  25. bt->menu = furi_record_open("menu");
  26. bt->state.type = BtStatusReady;
  27. bt->state.param.channel = BtChannel2402;
  28. bt->state.param.power = BtPower0dB;
  29. bt->state.param.datarate = BtDateRate1M;
  30. bt->statusbar_view_port = view_port_alloc();
  31. view_port_set_width(bt->statusbar_view_port, 5);
  32. view_port_draw_callback_set(bt->statusbar_view_port, bt_draw_statusbar_callback, bt);
  33. view_port_enabled_set(bt->statusbar_view_port, false);
  34. gui_add_view_port(bt->gui, bt->statusbar_view_port, GuiLayerStatusBarLeft);
  35. bt->menu_icon = assets_icons_get(A_Bluetooth_14);
  36. bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon);
  37. menu_item_subitem_add(
  38. bt->menu_item, menu_item_alloc_function("Test tone TX", NULL, bt_menu_test_tone_tx, bt));
  39. menu_item_subitem_add(
  40. bt->menu_item,
  41. menu_item_alloc_function("Test packet TX", NULL, bt_menu_test_packet_tx, bt));
  42. menu_item_subitem_add(
  43. bt->menu_item, menu_item_alloc_function("Test tone RX", NULL, bt_menu_test_tone_rx, bt));
  44. menu_item_subitem_add(
  45. bt->menu_item, menu_item_alloc_function("Start app", NULL, bt_menu_start_app, bt));
  46. bt->view_test_tone_tx = view_alloc();
  47. view_set_context(bt->view_test_tone_tx, bt);
  48. view_set_draw_callback(bt->view_test_tone_tx, bt_view_test_tone_tx_draw);
  49. view_allocate_model(
  50. bt->view_test_tone_tx, ViewModelTypeLocking, sizeof(BtViewTestToneTxModel));
  51. view_set_input_callback(bt->view_test_tone_tx, bt_view_test_tone_tx_input);
  52. bt->view_test_packet_tx = view_alloc();
  53. view_set_context(bt->view_test_packet_tx, bt);
  54. view_set_draw_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_draw);
  55. view_allocate_model(
  56. bt->view_test_packet_tx, ViewModelTypeLocking, sizeof(BtViewTestPacketTxModel));
  57. view_set_input_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_input);
  58. bt->view_test_tone_rx = view_alloc();
  59. view_set_context(bt->view_test_tone_rx, bt);
  60. view_set_draw_callback(bt->view_test_tone_rx, bt_view_test_tone_rx_draw);
  61. view_allocate_model(bt->view_test_tone_rx, ViewModelTypeLocking, sizeof(BtViewTestRxModel));
  62. view_set_input_callback(bt->view_test_tone_rx, bt_view_test_tone_rx_input);
  63. bt->view_start_app = view_alloc();
  64. view_set_context(bt->view_start_app, bt);
  65. view_set_draw_callback(bt->view_start_app, bt_view_app_draw);
  66. view_set_previous_callback(bt->view_start_app, bt_view_exit);
  67. bt->view_dispatcher = view_dispatcher_alloc();
  68. view_dispatcher_add_view(bt->view_dispatcher, BtViewTestToneTx, bt->view_test_tone_tx);
  69. view_dispatcher_add_view(bt->view_dispatcher, BtViewTestPacketTx, bt->view_test_packet_tx);
  70. view_dispatcher_add_view(bt->view_dispatcher, BtViewTestToneRx, bt->view_test_tone_rx);
  71. view_dispatcher_add_view(bt->view_dispatcher, BtViewStartApp, bt->view_start_app);
  72. Gui* gui = furi_record_open("gui");
  73. view_dispatcher_attach_to_gui(bt->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
  74. with_value_mutex(
  75. bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); });
  76. return bt;
  77. }
  78. void bt_draw_statusbar_callback(Canvas* canvas, void* context) {
  79. canvas_draw_icon_name(canvas, 0, 0, I_Bluetooth_5x8);
  80. }
  81. void bt_menu_test_tone_tx(void* context) {
  82. furi_assert(context);
  83. Bt* bt = context;
  84. bt->state.type = BtStatusToneTx;
  85. BtMessage message = {
  86. .type = BtMessageTypeStartTestToneTx,
  87. .param.channel = bt->state.param.channel,
  88. .param.power = bt->state.param.power};
  89. furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
  90. }
  91. void bt_menu_test_packet_tx(void* context) {
  92. furi_assert(context);
  93. Bt* bt = context;
  94. bt->state.type = BtStatusPacketSetup;
  95. BtMessage message = {
  96. .type = BtMessageTypeSetupTestPacketTx,
  97. .param.channel = bt->state.param.channel,
  98. .param.datarate = bt->state.param.datarate};
  99. furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
  100. }
  101. void bt_menu_test_tone_rx(void* context) {
  102. furi_assert(context);
  103. Bt* bt = context;
  104. bt->state.type = BtStatusToneRx;
  105. BtMessage message = {
  106. .type = BtMessageTypeStartTestRx,
  107. .param.channel = bt->state.param.channel,
  108. .param.power = bt->state.param.power};
  109. furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
  110. }
  111. void bt_menu_start_app(void* context) {
  112. furi_assert(context);
  113. Bt* bt = context;
  114. bt->state.type = BtStatusStartedApp;
  115. BtMessage message = {.type = BtMessageTypeStartApp};
  116. furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
  117. }
  118. int32_t bt_task() {
  119. Bt* bt = bt_alloc();
  120. furi_record_create("bt", bt);
  121. api_hal_bt_init();
  122. BtMessage message;
  123. while(1) {
  124. furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
  125. if(message.type == BtMessageTypeStartTestToneTx) {
  126. // Start test tx
  127. api_hal_bt_stop_tone_tx();
  128. if(bt->state.type == BtStatusToneTx) {
  129. api_hal_bt_start_tone_tx(message.param.channel, message.param.power);
  130. } else {
  131. bt->state.param.channel =
  132. bt_switch_channel(InputKeyRight, bt->state.param.channel);
  133. bt->state.param.power = BtPower6dB;
  134. api_hal_bt_start_tone_tx(bt->state.param.channel, bt->state.param.power);
  135. }
  136. with_view_model(
  137. bt->view_test_tone_tx, (BtViewTestToneTxModel * model) {
  138. model->type = bt->state.type;
  139. model->channel = bt->state.param.channel;
  140. model->power = bt->state.param.power;
  141. return true;
  142. });
  143. view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestToneTx);
  144. } else if(message.type == BtMessageTypeStopTestToneTx) {
  145. // Stop test tone tx
  146. api_hal_bt_stop_tone_tx();
  147. bt->state.type = BtStatusReady;
  148. } else if(message.type == BtMessageTypeSetupTestPacketTx) {
  149. // Update packet test setup
  150. api_hal_bt_stop_packet_test();
  151. with_view_model(
  152. bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) {
  153. model->type = bt->state.type;
  154. model->channel = bt->state.param.channel;
  155. model->datarate = bt->state.param.datarate;
  156. return true;
  157. });
  158. view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
  159. } else if(message.type == BtMessageTypeStartTestPacketTx) {
  160. // Start sending packets
  161. api_hal_bt_start_packet_tx(message.param.channel, 1, message.param.datarate);
  162. with_view_model(
  163. bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) {
  164. model->type = bt->state.type;
  165. model->channel = bt->state.param.channel;
  166. model->datarate = bt->state.param.datarate;
  167. return true;
  168. });
  169. view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
  170. } else if(message.type == BtMessageTypeStopTestPacketTx) {
  171. // Stop test packet tx
  172. api_hal_bt_stop_packet_test();
  173. bt->state.type = BtStatusReady;
  174. } else if(message.type == BtMessageTypeStartTestRx) {
  175. // Start test rx
  176. api_hal_bt_start_rx(message.param.channel);
  177. with_view_model(
  178. bt->view_test_tone_rx, (BtViewTestRxModel * model) {
  179. model->channel = bt->state.param.channel;
  180. return true;
  181. });
  182. view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestToneRx);
  183. } else if(message.type == BtMessageTypeStopTestRx) {
  184. // Stop test rx
  185. api_hal_bt_stop_rx();
  186. bt->state.type = BtStatusReady;
  187. } else if(message.type == BtMessageTypeStartApp) {
  188. // Start app
  189. view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewStartApp);
  190. if(api_hal_bt_start_app()) {
  191. bt->state.type = BtStatusStartedApp;
  192. }
  193. } else if(message.type == BtMessageTypeUpdateStatusbar) {
  194. // Update statusbar
  195. view_port_enabled_set(bt->statusbar_view_port, api_hal_bt_is_alive());
  196. }
  197. }
  198. return 0;
  199. }