bt.c 9.6 KB

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