[FL-580] Prepare BLE for certification (#376)
* api-hal-bt: separate bt init to core init and app start * bt: add continuous TX and RX tests * bt: finish rx test on Back button click * api-hal-bt: check core 2 started, same f4 and f5 implementation * bt: refactoring, move hopping test logic to main thread Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									b920248693
								
							
						
					
					
						commit
						0af6c9882e
					
				| @ -1,13 +1,41 @@ | ||||
| #include "bt_i.h" | ||||
| 
 | ||||
| uint32_t bt_view_exit(void* context) { | ||||
|     (void)context; | ||||
|     return VIEW_NONE; | ||||
| } | ||||
| 
 | ||||
| void bt_update_statusbar(void* arg) { | ||||
|     furi_assert(arg); | ||||
|     Bt* bt = arg; | ||||
|     BtMessage m = {.type = BtMessageTypeUpdateStatusbar}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_switch_freq(void* arg) { | ||||
|     furi_assert(arg); | ||||
|     Bt* bt = arg; | ||||
|     BtMessage m = {.type = BtMessageTypeStartTestToneTx}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| Bt* bt_alloc() { | ||||
|     Bt* bt = furi_alloc(sizeof(Bt)); | ||||
| 
 | ||||
|     bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL); | ||||
|     bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL); | ||||
|     osTimerStart(bt->update_status_timer, 4000); | ||||
|     bt->hopping_mode_timer = osTimerNew(bt_switch_freq, osTimerPeriodic, bt, NULL); | ||||
|     bt->cli = furi_record_open("cli"); | ||||
|     cli_add_command(bt->cli, "bt_info", bt_cli_info, bt); | ||||
|     bt->gui = furi_record_open("gui"); | ||||
|     bt->menu = furi_record_open("menu"); | ||||
| 
 | ||||
|     bt->state.type = BtStatusReady; | ||||
|     bt->state.param.channel = BtChannel2402; | ||||
|     bt->state.param.power = BtPower0dB; | ||||
|     bt->state.param.datarate = BtDateRate1M; | ||||
| 
 | ||||
|     bt->statusbar_view_port = view_port_alloc(); | ||||
|     view_port_set_width(bt->statusbar_view_port, 5); | ||||
|     view_port_draw_callback_set(bt->statusbar_view_port, bt_draw_statusbar_callback, bt); | ||||
| @ -16,9 +44,48 @@ Bt* bt_alloc() { | ||||
| 
 | ||||
|     bt->menu_icon = assets_icons_get(A_Bluetooth_14); | ||||
|     bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, menu_item_alloc_function("Test tone TX", NULL, bt_menu_test_tone_tx, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, | ||||
|         menu_item_alloc_function("Test packet TX", NULL, bt_menu_test_packet_tx, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, menu_item_alloc_function("Test tone RX", NULL, bt_menu_test_tone_rx, bt)); | ||||
|     menu_item_subitem_add( | ||||
|         bt->menu_item, menu_item_alloc_function("Start app", NULL, bt_menu_start_app, bt)); | ||||
| 
 | ||||
|     bt->view_test_tone_tx = view_alloc(); | ||||
|     view_set_context(bt->view_test_tone_tx, bt); | ||||
|     view_set_draw_callback(bt->view_test_tone_tx, bt_view_test_tone_tx_draw); | ||||
|     view_allocate_model( | ||||
|         bt->view_test_tone_tx, ViewModelTypeLocking, sizeof(BtViewTestToneTxModel)); | ||||
|     view_set_input_callback(bt->view_test_tone_tx, bt_view_test_tone_tx_input); | ||||
|     bt->view_test_packet_tx = view_alloc(); | ||||
|     view_set_context(bt->view_test_packet_tx, bt); | ||||
|     view_set_draw_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_draw); | ||||
|     view_allocate_model( | ||||
|         bt->view_test_packet_tx, ViewModelTypeLocking, sizeof(BtViewTestPacketTxModel)); | ||||
|     view_set_input_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_input); | ||||
|     bt->view_test_tone_rx = view_alloc(); | ||||
|     view_set_context(bt->view_test_tone_rx, bt); | ||||
|     view_set_draw_callback(bt->view_test_tone_rx, bt_view_test_tone_rx_draw); | ||||
|     view_allocate_model(bt->view_test_tone_rx, ViewModelTypeLocking, sizeof(BtViewTestRxModel)); | ||||
|     view_set_input_callback(bt->view_test_tone_rx, bt_view_test_tone_rx_input); | ||||
|     bt->view_start_app = view_alloc(); | ||||
|     view_set_context(bt->view_start_app, bt); | ||||
|     view_set_draw_callback(bt->view_start_app, bt_view_app_draw); | ||||
|     view_set_previous_callback(bt->view_start_app, bt_view_exit); | ||||
|     bt->view_dispatcher = view_dispatcher_alloc(); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestToneTx, bt->view_test_tone_tx); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestPacketTx, bt->view_test_packet_tx); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestToneRx, bt->view_test_tone_rx); | ||||
|     view_dispatcher_add_view(bt->view_dispatcher, BtViewStartApp, bt->view_start_app); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     view_dispatcher_attach_to_gui(bt->view_dispatcher, gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     with_value_mutex( | ||||
|         bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); }); | ||||
| 
 | ||||
|     return bt; | ||||
| } | ||||
| 
 | ||||
| @ -26,6 +93,47 @@ void bt_draw_statusbar_callback(Canvas* canvas, void* context) { | ||||
|     canvas_draw_icon_name(canvas, 0, 0, I_Bluetooth_5x8); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_tone_tx(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatusToneTx; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeStartTestToneTx, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.power = bt->state.param.power}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_packet_tx(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatusPacketSetup; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeSetupTestPacketTx, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.datarate = bt->state.param.datarate}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_test_tone_rx(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatusToneRx; | ||||
|     BtMessage message = { | ||||
|         .type = BtMessageTypeStartTestRx, | ||||
|         .param.channel = bt->state.param.channel, | ||||
|         .param.power = bt->state.param.power}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_menu_start_app(void* context) { | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     bt->state.type = BtStatusStartedApp; | ||||
|     BtMessage message = {.type = BtMessageTypeStartApp}; | ||||
|     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK); | ||||
| } | ||||
| 
 | ||||
| void bt_cli_info(string_t args, void* context) { | ||||
|     string_t buffer; | ||||
|     string_init(buffer); | ||||
| @ -40,11 +148,81 @@ int32_t bt_task() { | ||||
|     furi_record_create("bt", bt); | ||||
| 
 | ||||
|     api_hal_bt_init(); | ||||
| 
 | ||||
|     BtMessage message; | ||||
|     while(1) { | ||||
|         view_port_enabled_set(bt->statusbar_view_port, api_hal_bt_is_alive()); | ||||
|         osDelay(1024); | ||||
|         furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK); | ||||
|         if(message.type == BtMessageTypeStartTestToneTx) { | ||||
|             // Start test tx
 | ||||
|             api_hal_bt_stop_tone_tx(); | ||||
|             if(bt->state.type == BtStatusToneTx) { | ||||
|                 api_hal_bt_start_tone_tx(message.param.channel, message.param.power); | ||||
|             } else { | ||||
|                 bt->state.param.channel = | ||||
|                     bt_switch_channel(InputKeyRight, bt->state.param.channel); | ||||
|                 bt->state.param.power = BtPower6dB; | ||||
|                 api_hal_bt_start_tone_tx(bt->state.param.channel, bt->state.param.power); | ||||
|             } | ||||
|             with_view_model( | ||||
|                 bt->view_test_tone_tx, (BtViewTestToneTxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->power = bt->state.param.power; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestToneTx); | ||||
|         } else if(message.type == BtMessageTypeStopTestToneTx) { | ||||
|             // Stop test tone tx
 | ||||
|             api_hal_bt_stop_tone_tx(); | ||||
|             bt->state.type = BtStatusReady; | ||||
|         } else if(message.type == BtMessageTypeSetupTestPacketTx) { | ||||
|             // Update packet test setup
 | ||||
|             api_hal_bt_stop_packet_tx(); | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx); | ||||
|         } else if(message.type == BtMessageTypeStartTestPacketTx) { | ||||
|             // Start sending packets
 | ||||
|             api_hal_bt_start_packet_tx(message.param.channel, message.param.datarate); | ||||
|             with_view_model( | ||||
|                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) { | ||||
|                     model->type = bt->state.type; | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     model->datarate = bt->state.param.datarate; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx); | ||||
|         } else if(message.type == BtMessageTypeStopTestPacketTx) { | ||||
|             // Stop test packet tx
 | ||||
|             api_hal_bt_stop_packet_tx(); | ||||
|             bt->state.type = BtStatusReady; | ||||
|         } else if(message.type == BtMessageTypeStartTestRx) { | ||||
|             // Start test rx
 | ||||
|             api_hal_bt_start_rx(message.param.channel); | ||||
|             with_view_model( | ||||
|                 bt->view_test_tone_rx, (BtViewTestRxModel * model) { | ||||
|                     model->channel = bt->state.param.channel; | ||||
|                     return true; | ||||
|                 }); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestToneRx); | ||||
|         } else if(message.type == BtMessageTypeStopTestRx) { | ||||
|             // Stop test rx
 | ||||
|             api_hal_bt_stop_rx(); | ||||
|             bt->state.type = BtStatusReady; | ||||
|         } else if(message.type == BtMessageTypeStartApp) { | ||||
|             // Start app
 | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewStartApp); | ||||
|             if(api_hal_bt_start_app()) { | ||||
|                 bt->state.type = BtStatusStartedApp; | ||||
|             } | ||||
|         } else if(message.type == BtMessageTypeUpdateStatusbar) { | ||||
|             // Update statusbar
 | ||||
|             view_port_enabled_set(bt->statusbar_view_port, api_hal_bt_is_alive()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @ -1 +1,3 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| typedef struct Bt Bt; | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "bt.h" | ||||
| #include "bt_views.h" | ||||
| #include "bt_types.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <api-hal.h> | ||||
| @ -9,11 +11,17 @@ | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_port.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include <menu/menu.h> | ||||
| #include <menu/menu_item.h> | ||||
| 
 | ||||
| typedef struct { | ||||
| struct Bt { | ||||
|     osMessageQueueId_t message_queue; | ||||
|     BtState state; | ||||
|     osTimerId_t update_status_timer; | ||||
|     osTimerId_t hopping_mode_timer; | ||||
|     Cli* cli; | ||||
|     Gui* gui; | ||||
|     ValueMutex* menu; | ||||
| @ -22,12 +30,27 @@ typedef struct { | ||||
|     // Menu
 | ||||
|     Icon* menu_icon; | ||||
|     MenuItem* menu_item; | ||||
| } Bt; | ||||
|     View* view_test_tone_tx; | ||||
|     View* view_test_packet_tx; | ||||
|     View* view_test_tone_rx; | ||||
|     View* view_start_app; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
| }; | ||||
| 
 | ||||
| Bt* bt_alloc(); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
| 
 | ||||
| BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan); | ||||
| 
 | ||||
| void bt_cli_info(string_t args, void* context); | ||||
| 
 | ||||
| void bt_draw_statusbar_callback(Canvas* canvas, void* context); | ||||
| 
 | ||||
| void bt_menu_test_tone_tx(void* context); | ||||
| 
 | ||||
| void bt_menu_test_packet_tx(void* context); | ||||
| 
 | ||||
| void bt_menu_test_tone_rx(void* context); | ||||
| 
 | ||||
| void bt_menu_start_app(void* context); | ||||
|  | ||||
							
								
								
									
										58
									
								
								applications/bt/bt_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								applications/bt/bt_types.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtMessageTypeStartTestToneTx, | ||||
|     BtMessageTypeHoppingTx, | ||||
|     BtMessageTypeStopTestToneTx, | ||||
|     BtMessageTypeSetupTestPacketTx, | ||||
|     BtMessageTypeStartTestPacketTx, | ||||
|     BtMessageTypeStopTestPacketTx, | ||||
|     BtMessageTypeStartTestRx, | ||||
|     BtMessageTypeStopTestRx, | ||||
|     BtMessageTypeStartApp, | ||||
|     BtMessageTypeUpdateStatusbar, | ||||
| } BtMessageType; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtStatusReady, | ||||
|     BtStatusToneTx, | ||||
|     BtStatusHoppingTx, | ||||
|     BtStatusToneRx, | ||||
|     BtStatusPacketSetup, | ||||
|     BtStatusPacketTx, | ||||
|     BtStatusStartedApp, | ||||
| } BtStateType; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtChannel2402 = 0, | ||||
|     BtChannel2440 = 19, | ||||
|     BtChannel2480 = 39, | ||||
| } BtTestChannel; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtPower0dB = 0x19, | ||||
|     BtPower2dB = 0x1B, | ||||
|     BtPower4dB = 0x1D, | ||||
|     BtPower6dB = 0x1F, | ||||
| } BtTestPower; | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtDateRate1M = 1, | ||||
|     BtDateRate2M = 2, | ||||
| } BtTestDataRate; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtTestChannel channel; | ||||
|     BtTestPower power; | ||||
|     BtTestDataRate datarate; | ||||
| } BtTestParam; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtMessageType type; | ||||
|     BtTestParam param; | ||||
| } BtMessage; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestParam param; | ||||
| } BtState; | ||||
							
								
								
									
										188
									
								
								applications/bt/bt_views.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								applications/bt/bt_views.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,188 @@ | ||||
| #include "bt_views.h" | ||||
| 
 | ||||
| void bt_view_test_tone_tx_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestToneTxModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Performing continous TX test"); | ||||
|     if(m->type == BtStatusToneTx) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Manual control mode"); | ||||
|     } else { | ||||
|         canvas_draw_str(canvas, 0, 24, "Hopping mode"); | ||||
|     } | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 36, buffer); | ||||
|     snprintf(buffer, sizeof(buffer), "Power:%d dB", m->power - BtPower0dB); | ||||
|     canvas_draw_str(canvas, 0, 48, buffer); | ||||
| } | ||||
| 
 | ||||
| void bt_view_test_tone_rx_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestRxModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Performing continous RX test"); | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 24, buffer); | ||||
| } | ||||
| 
 | ||||
| void bt_view_test_packet_tx_draw(Canvas* canvas, void* model) { | ||||
|     BtViewTestPacketTxModel* m = model; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Packets send TX test"); | ||||
|     if(m->type == BtStatusPacketSetup) { | ||||
|         canvas_draw_str(canvas, 0, 24, "Setup parameters"); | ||||
|         canvas_draw_str(canvas, 0, 36, "Press OK to send packets"); | ||||
|     } else { | ||||
|         canvas_draw_str(canvas, 0, 24, "Sending packets"); | ||||
|         canvas_draw_str(canvas, 0, 36, "Packets parameters:"); | ||||
|     } | ||||
|     char buffer[32]; | ||||
|     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402); | ||||
|     canvas_draw_str(canvas, 0, 48, buffer); | ||||
|     snprintf(buffer, sizeof(buffer), "Daterate:%d Mbps", m->datarate); | ||||
|     canvas_draw_str(canvas, 0, 60, buffer); | ||||
| } | ||||
| 
 | ||||
| void bt_view_app_draw(Canvas* canvas, void* model) { | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 0, 12, "Start BLE app"); | ||||
| } | ||||
| 
 | ||||
| BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan) { | ||||
|     uint8_t pos = 0; | ||||
|     BtTestChannel arr[] = {BtChannel2402, BtChannel2440, BtChannel2480}; | ||||
|     for(pos = 0; pos < sizeof(arr); pos++) { | ||||
|         if(arr[pos] == inst_chan) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if(key == InputKeyRight) { | ||||
|         pos = (pos + 1) % sizeof(arr); | ||||
|         return arr[pos]; | ||||
|     } else if(key == InputKeyLeft) { | ||||
|         if(pos) { | ||||
|             return arr[pos - 1]; | ||||
|         } else { | ||||
|             return arr[sizeof(arr) - 1]; | ||||
|         } | ||||
|     } | ||||
|     return arr[0]; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_tone_tx_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key == InputKeyBack) { | ||||
|             if(osTimerIsRunning(bt->hopping_mode_timer)) { | ||||
|                 osTimerStop(bt->hopping_mode_timer); | ||||
|             } | ||||
|             BtMessage m = {.type = BtMessageTypeStopTestToneTx}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } else { | ||||
|             if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             } else if(event->key == InputKeyUp) { | ||||
|                 if(bt->state.param.power < BtPower6dB) { | ||||
|                     bt->state.param.power += 2; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyDown) { | ||||
|                 if(bt->state.param.power > BtPower0dB) { | ||||
|                     bt->state.param.power -= 2; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyOk) { | ||||
|                 if(bt->state.type == BtStatusToneTx) { | ||||
|                     bt->state.type = BtStatusHoppingTx; | ||||
|                     osTimerStart(bt->hopping_mode_timer, 2000); | ||||
|                 } else { | ||||
|                     bt->state.type = BtStatusToneTx; | ||||
|                     osTimerStop(bt->hopping_mode_timer); | ||||
|                 } | ||||
|             } | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestToneTx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.power = bt->state.param.power}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_tone_rx_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|             bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestRx, .param.channel = bt->state.param.channel}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyBack) { | ||||
|             BtMessage m = {.type = BtMessageTypeStopTestRx}; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool bt_view_test_packet_tx_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     Bt* bt = context; | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key < InputKeyOk) { | ||||
|             // Process InputKeyUp, InputKeyDown, InputKeyLeft, InputKeyRight
 | ||||
|             if(event->key == InputKeyRight || event->key == InputKeyLeft) { | ||||
|                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel); | ||||
|             } else if(event->key == InputKeyUp) { | ||||
|                 if(bt->state.param.datarate < BtDateRate2M) { | ||||
|                     bt->state.param.datarate += 1; | ||||
|                 } | ||||
|             } else if(event->key == InputKeyDown) { | ||||
|                 if(bt->state.param.datarate > BtDateRate1M) { | ||||
|                     bt->state.param.datarate -= 1; | ||||
|                 } | ||||
|             } | ||||
|             bt->state.type = BtStatusPacketSetup; | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeSetupTestPacketTx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyOk) { | ||||
|             bt->state.type = BtStatusPacketTx; | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStartTestPacketTx, | ||||
|                 .param.channel = bt->state.param.channel, | ||||
|                 .param.datarate = bt->state.param.datarate, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             return true; | ||||
|         } else if(event->key == InputKeyBack) { | ||||
|             BtMessage m = { | ||||
|                 .type = BtMessageTypeStopTestPacketTx, | ||||
|             }; | ||||
|             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK); | ||||
|             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
							
								
								
									
										48
									
								
								applications/bt/bt_views.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								applications/bt/bt_views.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "bt_i.h" | ||||
| #include "bt_types.h" | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <furi.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     BtViewTestToneTx, | ||||
|     BtViewTestPacketTx, | ||||
|     BtViewTestToneRx, | ||||
|     BtViewStartApp, | ||||
| } BtView; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestChannel channel; | ||||
|     BtTestPower power; | ||||
| } BtViewTestToneTxModel; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtStateType type; | ||||
|     BtTestChannel channel; | ||||
|     BtTestDataRate datarate; | ||||
| } BtViewTestPacketTxModel; | ||||
| 
 | ||||
| typedef struct { | ||||
|     BtTestChannel channel; | ||||
| } BtViewTestRxModel; | ||||
| 
 | ||||
| void bt_view_test_tone_tx_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_tone_tx_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_test_packet_tx_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_packet_tx_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_test_tone_rx_draw(Canvas* canvas, void* model); | ||||
| 
 | ||||
| bool bt_view_test_tone_rx_input(InputEvent* event, void* context); | ||||
| 
 | ||||
| void bt_view_app_draw(Canvas* canvas, void* model); | ||||
| @ -10,6 +10,9 @@ extern "C" { | ||||
| /* Initialize */ | ||||
| void api_hal_bt_init(); | ||||
| 
 | ||||
| /* Start BLE app */ | ||||
| bool api_hal_bt_start_app(); | ||||
| 
 | ||||
| /* Get BT/BLE system component state */ | ||||
| void api_hal_bt_dump_state(string_t buffer); | ||||
| 
 | ||||
| @ -24,6 +27,24 @@ bool api_hal_bt_lock_flash(); | ||||
| /* Unlock shared access to flash controller */ | ||||
| void api_hal_bt_unlock_flash(); | ||||
| 
 | ||||
| /* Start ble tone tx at given channel and power */ | ||||
| void api_hal_bt_start_tone_tx(uint8_t tx_channel, uint8_t power); | ||||
| 
 | ||||
| /* Stop ble tone tx */ | ||||
| void api_hal_bt_stop_tone_tx(); | ||||
| 
 | ||||
| /* Start sending ble packets at a given frequency and datarate */ | ||||
| void api_hal_bt_start_packet_tx(uint8_t frequency, uint8_t datarate); | ||||
| 
 | ||||
| /* Stop sending ble packets */ | ||||
| void api_hal_bt_stop_packet_tx(); | ||||
| 
 | ||||
| /* Set up the RF to listen to a given RF channel */ | ||||
| void api_hal_bt_start_rx(uint8_t frequency); | ||||
| 
 | ||||
| /* Stop RF listenning */ | ||||
| void api_hal_bt_stop_rx(); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #include <stm32wbxx.h> | ||||
| #include <shci.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include <app_ble.h> | ||||
| 
 | ||||
| void api_hal_bt_init() { | ||||
|     // Explicitly tell that we are in charge of CLK48 domain
 | ||||
| @ -12,6 +13,10 @@ void api_hal_bt_init() { | ||||
|     APPE_Init(); | ||||
| } | ||||
| 
 | ||||
| bool api_hal_bt_start_app() { | ||||
|     return APP_BLE_Start(); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_dump_state(string_t buffer) { | ||||
|     BleGlueStatus status = APPE_Status(); | ||||
|     if (status == BleGlueStatusStarted) { | ||||
| @ -76,3 +81,29 @@ void api_hal_bt_unlock_flash() { | ||||
|         HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_tone_tx(uint8_t tx_channel, uint8_t power) { | ||||
|     aci_hal_set_tx_power_level(0, power); | ||||
|     aci_hal_tone_start(tx_channel, 0); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_tone_tx() { | ||||
|     aci_hal_tone_stop(); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_packet_tx(uint8_t frequency, uint8_t datarate) { | ||||
|     hci_le_enhanced_transmitter_test(frequency, 0x25, 2, datarate); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_packet_tx() { | ||||
|     uint16_t num_of_packets; | ||||
|     hci_le_test_end(&num_of_packets); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_rx(uint8_t frequency) { | ||||
|     aci_hal_rx_start(frequency); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_rx() { | ||||
|     aci_hal_rx_stop(); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "main.h" | ||||
| 
 | ||||
| #include "app_entry.h" | ||||
| #include "app_common.h" | ||||
| #include "dbg_trace.h" | ||||
| #include "ble.h" | ||||
| @ -158,7 +159,11 @@ bool APP_BLE_Init() { | ||||
|   // Register the hci transport layer to handle BLE User Asynchronous Events
 | ||||
|   HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr); | ||||
|   // Starts the BLE Stack on CPU2
 | ||||
|   if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success) { | ||||
|   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success); | ||||
| } | ||||
| 
 | ||||
| bool APP_BLE_Start() { | ||||
|   if (APPE_Status() != BleGlueStatusStarted) { | ||||
|     return false; | ||||
|   } | ||||
|   // Initialization of HCI & GATT & GAP layer
 | ||||
|  | ||||
| @ -18,6 +18,7 @@ typedef enum { | ||||
| } APP_BLE_ConnStatus_t; | ||||
| 
 | ||||
| bool APP_BLE_Init(); | ||||
| bool APP_BLE_Start(); | ||||
| 
 | ||||
| APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); | ||||
| 
 | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #include <stm32wbxx.h> | ||||
| #include <shci.h> | ||||
| #include <cmsis_os2.h> | ||||
| #include <app_ble.h> | ||||
| 
 | ||||
| void api_hal_bt_init() { | ||||
|     // Explicitly tell that we are in charge of CLK48 domain
 | ||||
| @ -12,6 +13,10 @@ void api_hal_bt_init() { | ||||
|     APPE_Init(); | ||||
| } | ||||
| 
 | ||||
| bool api_hal_bt_start_app() { | ||||
|     return APP_BLE_Start(); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_dump_state(string_t buffer) { | ||||
|     BleGlueStatus status = APPE_Status(); | ||||
|     if (status == BleGlueStatusStarted) { | ||||
| @ -76,3 +81,29 @@ void api_hal_bt_unlock_flash() { | ||||
|         HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_tone_tx(uint8_t tx_channel, uint8_t power) { | ||||
|     aci_hal_set_tx_power_level(0, power); | ||||
|     aci_hal_tone_start(tx_channel, 0); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_tone_tx() { | ||||
|     aci_hal_tone_stop(); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_packet_tx(uint8_t frequency, uint8_t datarate) { | ||||
|     hci_le_enhanced_transmitter_test(frequency, 0x25, 2, datarate); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_packet_tx() { | ||||
|     uint16_t num_of_packets; | ||||
|     hci_le_test_end(&num_of_packets); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_start_rx(uint8_t frequency) { | ||||
|     aci_hal_rx_start(frequency); | ||||
| } | ||||
| 
 | ||||
| void api_hal_bt_stop_rx() { | ||||
|     aci_hal_rx_stop(); | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #include "main.h" | ||||
| 
 | ||||
| #include "app_entry.h" | ||||
| #include "app_common.h" | ||||
| #include "dbg_trace.h" | ||||
| #include "ble.h" | ||||
| @ -158,7 +159,11 @@ bool APP_BLE_Init() { | ||||
|   // Register the hci transport layer to handle BLE User Asynchronous Events
 | ||||
|   HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr); | ||||
|   // Starts the BLE Stack on CPU2
 | ||||
|   if (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) != SHCI_Success) { | ||||
|   return (SHCI_C2_BLE_Init( &ble_init_cmd_packet ) == SHCI_Success); | ||||
| } | ||||
| 
 | ||||
| bool APP_BLE_Start() { | ||||
|   if (APPE_Status() != BleGlueStatusStarted) { | ||||
|     return false; | ||||
|   } | ||||
|   // Initialization of HCI & GATT & GAP layer
 | ||||
|  | ||||
| @ -18,6 +18,7 @@ typedef enum { | ||||
| } APP_BLE_ConnStatus_t; | ||||
| 
 | ||||
| bool APP_BLE_Init(); | ||||
| bool APP_BLE_Start(); | ||||
| 
 | ||||
| APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status(); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich