From 0af6c9882e31bce95d4d852ad5b4217bf8b313d9 Mon Sep 17 00:00:00 2001 From: gornekich <44112859+gornekich@users.noreply.github.com> Date: Thu, 11 Mar 2021 12:31:07 +0300 Subject: [PATCH] [FL-580] Prepare BLE for certification (#376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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: あく --- applications/bt/bt.c | 188 +++++++++++++++++- applications/bt/bt.h | 2 + applications/bt/bt_i.h | 27 ++- applications/bt/bt_types.h | 58 ++++++ applications/bt/bt_views.c | 188 ++++++++++++++++++ applications/bt/bt_views.h | 48 +++++ firmware/targets/api-hal-include/api-hal-bt.h | 21 ++ firmware/targets/f4/api-hal/api-hal-bt.c | 31 +++ firmware/targets/f4/ble-glue/app_ble.c | 7 +- firmware/targets/f4/ble-glue/app_ble.h | 1 + firmware/targets/f5/api-hal/api-hal-bt.c | 31 +++ firmware/targets/f5/ble-glue/app_ble.c | 7 +- firmware/targets/f5/ble-glue/app_ble.h | 1 + 13 files changed, 601 insertions(+), 9 deletions(-) create mode 100644 applications/bt/bt_types.h create mode 100644 applications/bt/bt_views.c create mode 100644 applications/bt/bt_views.h diff --git a/applications/bt/bt.c b/applications/bt/bt.c index 87e8f547..b4624090 100644 --- a/applications/bt/bt.c +++ b/applications/bt/bt.c @@ -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; } diff --git a/applications/bt/bt.h b/applications/bt/bt.h index 6f70f09b..b163fa69 100644 --- a/applications/bt/bt.h +++ b/applications/bt/bt.h @@ -1 +1,3 @@ #pragma once + +typedef struct Bt Bt; diff --git a/applications/bt/bt_i.h b/applications/bt/bt_i.h index 26d47def..f7213c7f 100644 --- a/applications/bt/bt_i.h +++ b/applications/bt/bt_i.h @@ -1,6 +1,8 @@ #pragma once #include "bt.h" +#include "bt_views.h" +#include "bt_types.h" #include #include @@ -9,11 +11,17 @@ #include #include +#include +#include #include #include -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); diff --git a/applications/bt/bt_types.h b/applications/bt/bt_types.h new file mode 100644 index 00000000..723a7b76 --- /dev/null +++ b/applications/bt/bt_types.h @@ -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; diff --git a/applications/bt/bt_views.c b/applications/bt/bt_views.c new file mode 100644 index 00000000..01eb4b62 --- /dev/null +++ b/applications/bt/bt_views.c @@ -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; +} diff --git a/applications/bt/bt_views.h b/applications/bt/bt_views.h new file mode 100644 index 00000000..260ab39e --- /dev/null +++ b/applications/bt/bt_views.h @@ -0,0 +1,48 @@ +#pragma once + +#include "bt_i.h" +#include "bt_types.h" + +#include +#include +#include +#include +#include +#include + +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); diff --git a/firmware/targets/api-hal-include/api-hal-bt.h b/firmware/targets/api-hal-include/api-hal-bt.h index aebe4b9b..320d98aa 100644 --- a/firmware/targets/api-hal-include/api-hal-bt.h +++ b/firmware/targets/api-hal-include/api-hal-bt.h @@ -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 diff --git a/firmware/targets/f4/api-hal/api-hal-bt.c b/firmware/targets/f4/api-hal/api-hal-bt.c index f25c0b70..e2d3aa34 100644 --- a/firmware/targets/f4/api-hal/api-hal-bt.c +++ b/firmware/targets/f4/api-hal/api-hal-bt.c @@ -4,6 +4,7 @@ #include #include #include +#include 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(); +} diff --git a/firmware/targets/f4/ble-glue/app_ble.c b/firmware/targets/f4/ble-glue/app_ble.c index 0b02e5b6..7a0997ea 100644 --- a/firmware/targets/f4/ble-glue/app_ble.c +++ b/firmware/targets/f4/ble-glue/app_ble.c @@ -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 diff --git a/firmware/targets/f4/ble-glue/app_ble.h b/firmware/targets/f4/ble-glue/app_ble.h index a2f25cb4..4d3ba876 100644 --- a/firmware/targets/f4/ble-glue/app_ble.h +++ b/firmware/targets/f4/ble-glue/app_ble.h @@ -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(); diff --git a/firmware/targets/f5/api-hal/api-hal-bt.c b/firmware/targets/f5/api-hal/api-hal-bt.c index f25c0b70..e2d3aa34 100644 --- a/firmware/targets/f5/api-hal/api-hal-bt.c +++ b/firmware/targets/f5/api-hal/api-hal-bt.c @@ -4,6 +4,7 @@ #include #include #include +#include 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(); +} diff --git a/firmware/targets/f5/ble-glue/app_ble.c b/firmware/targets/f5/ble-glue/app_ble.c index 0b02e5b6..7a0997ea 100644 --- a/firmware/targets/f5/ble-glue/app_ble.c +++ b/firmware/targets/f5/ble-glue/app_ble.c @@ -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 diff --git a/firmware/targets/f5/ble-glue/app_ble.h b/firmware/targets/f5/ble-glue/app_ble.h index a2f25cb4..4d3ba876 100644 --- a/firmware/targets/f5/ble-glue/app_ble.h +++ b/firmware/targets/f5/ble-glue/app_ble.h @@ -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();