[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"
|
#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_alloc() {
|
||||||
Bt* bt = furi_alloc(sizeof(Bt));
|
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");
|
bt->cli = furi_record_open("cli");
|
||||||
cli_add_command(bt->cli, "bt_info", bt_cli_info, bt);
|
cli_add_command(bt->cli, "bt_info", bt_cli_info, bt);
|
||||||
bt->gui = furi_record_open("gui");
|
bt->gui = furi_record_open("gui");
|
||||||
bt->menu = furi_record_open("menu");
|
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();
|
bt->statusbar_view_port = view_port_alloc();
|
||||||
view_port_set_width(bt->statusbar_view_port, 5);
|
view_port_set_width(bt->statusbar_view_port, 5);
|
||||||
view_port_draw_callback_set(bt->statusbar_view_port, bt_draw_statusbar_callback, bt);
|
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_icon = assets_icons_get(A_Bluetooth_14);
|
||||||
bt->menu_item = menu_item_alloc_menu("Bluetooth", bt->menu_icon);
|
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(
|
with_value_mutex(
|
||||||
bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); });
|
bt->menu, (Menu * menu) { menu_item_add(menu, bt->menu_item); });
|
||||||
|
|
||||||
return bt;
|
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);
|
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) {
|
void bt_cli_info(string_t args, void* context) {
|
||||||
string_t buffer;
|
string_t buffer;
|
||||||
string_init(buffer);
|
string_init(buffer);
|
||||||
@ -40,11 +148,81 @@ int32_t bt_task() {
|
|||||||
furi_record_create("bt", bt);
|
furi_record_create("bt", bt);
|
||||||
|
|
||||||
api_hal_bt_init();
|
api_hal_bt_init();
|
||||||
|
BtMessage message;
|
||||||
while(1) {
|
while(1) {
|
||||||
view_port_enabled_set(bt->statusbar_view_port, api_hal_bt_is_alive());
|
furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
|
||||||
osDelay(1024);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct Bt Bt;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "bt.h"
|
#include "bt.h"
|
||||||
|
#include "bt_views.h"
|
||||||
|
#include "bt_types.h"
|
||||||
|
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
@ -9,11 +11,17 @@
|
|||||||
|
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view_port.h>
|
#include <gui/view_port.h>
|
||||||
|
#include <gui/view.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
|
||||||
#include <menu/menu.h>
|
#include <menu/menu.h>
|
||||||
#include <menu/menu_item.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;
|
Cli* cli;
|
||||||
Gui* gui;
|
Gui* gui;
|
||||||
ValueMutex* menu;
|
ValueMutex* menu;
|
||||||
@ -22,12 +30,27 @@ typedef struct {
|
|||||||
// Menu
|
// Menu
|
||||||
Icon* menu_icon;
|
Icon* menu_icon;
|
||||||
MenuItem* menu_item;
|
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();
|
Bt* bt_alloc();
|
||||||
|
|
||||||
void bt_draw_statusbar_callback(Canvas* canvas, void* context);
|
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_cli_info(string_t args, void* context);
|
||||||
|
|
||||||
void bt_draw_statusbar_callback(Canvas* canvas, 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 */
|
/* Initialize */
|
||||||
void api_hal_bt_init();
|
void api_hal_bt_init();
|
||||||
|
|
||||||
|
/* Start BLE app */
|
||||||
|
bool api_hal_bt_start_app();
|
||||||
|
|
||||||
/* Get BT/BLE system component state */
|
/* Get BT/BLE system component state */
|
||||||
void api_hal_bt_dump_state(string_t buffer);
|
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 */
|
/* Unlock shared access to flash controller */
|
||||||
void api_hal_bt_unlock_flash();
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stm32wbxx.h>
|
#include <stm32wbxx.h>
|
||||||
#include <shci.h>
|
#include <shci.h>
|
||||||
#include <cmsis_os2.h>
|
#include <cmsis_os2.h>
|
||||||
|
#include <app_ble.h>
|
||||||
|
|
||||||
void api_hal_bt_init() {
|
void api_hal_bt_init() {
|
||||||
// Explicitly tell that we are in charge of CLK48 domain
|
// Explicitly tell that we are in charge of CLK48 domain
|
||||||
@ -12,6 +13,10 @@ void api_hal_bt_init() {
|
|||||||
APPE_Init();
|
APPE_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool api_hal_bt_start_app() {
|
||||||
|
return APP_BLE_Start();
|
||||||
|
}
|
||||||
|
|
||||||
void api_hal_bt_dump_state(string_t buffer) {
|
void api_hal_bt_dump_state(string_t buffer) {
|
||||||
BleGlueStatus status = APPE_Status();
|
BleGlueStatus status = APPE_Status();
|
||||||
if (status == BleGlueStatusStarted) {
|
if (status == BleGlueStatusStarted) {
|
||||||
@ -76,3 +81,29 @@ void api_hal_bt_unlock_flash() {
|
|||||||
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
|
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 "main.h"
|
||||||
|
|
||||||
|
#include "app_entry.h"
|
||||||
#include "app_common.h"
|
#include "app_common.h"
|
||||||
#include "dbg_trace.h"
|
#include "dbg_trace.h"
|
||||||
#include "ble.h"
|
#include "ble.h"
|
||||||
@ -158,7 +159,11 @@ bool APP_BLE_Init() {
|
|||||||
// Register the hci transport layer to handle BLE User Asynchronous Events
|
// Register the hci transport layer to handle BLE User Asynchronous Events
|
||||||
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
|
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
|
||||||
// Starts the BLE Stack on CPU2
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
// Initialization of HCI & GATT & GAP layer
|
// Initialization of HCI & GATT & GAP layer
|
||||||
|
@ -18,6 +18,7 @@ typedef enum {
|
|||||||
} APP_BLE_ConnStatus_t;
|
} APP_BLE_ConnStatus_t;
|
||||||
|
|
||||||
bool APP_BLE_Init();
|
bool APP_BLE_Init();
|
||||||
|
bool APP_BLE_Start();
|
||||||
|
|
||||||
APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
|
APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stm32wbxx.h>
|
#include <stm32wbxx.h>
|
||||||
#include <shci.h>
|
#include <shci.h>
|
||||||
#include <cmsis_os2.h>
|
#include <cmsis_os2.h>
|
||||||
|
#include <app_ble.h>
|
||||||
|
|
||||||
void api_hal_bt_init() {
|
void api_hal_bt_init() {
|
||||||
// Explicitly tell that we are in charge of CLK48 domain
|
// Explicitly tell that we are in charge of CLK48 domain
|
||||||
@ -12,6 +13,10 @@ void api_hal_bt_init() {
|
|||||||
APPE_Init();
|
APPE_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool api_hal_bt_start_app() {
|
||||||
|
return APP_BLE_Start();
|
||||||
|
}
|
||||||
|
|
||||||
void api_hal_bt_dump_state(string_t buffer) {
|
void api_hal_bt_dump_state(string_t buffer) {
|
||||||
BleGlueStatus status = APPE_Status();
|
BleGlueStatus status = APPE_Status();
|
||||||
if (status == BleGlueStatusStarted) {
|
if (status == BleGlueStatusStarted) {
|
||||||
@ -76,3 +81,29 @@ void api_hal_bt_unlock_flash() {
|
|||||||
HAL_HSEM_Release(CFG_HW_FLASH_SEMID, HSEM_CPU1_COREID);
|
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 "main.h"
|
||||||
|
|
||||||
|
#include "app_entry.h"
|
||||||
#include "app_common.h"
|
#include "app_common.h"
|
||||||
#include "dbg_trace.h"
|
#include "dbg_trace.h"
|
||||||
#include "ble.h"
|
#include "ble.h"
|
||||||
@ -158,7 +159,11 @@ bool APP_BLE_Init() {
|
|||||||
// Register the hci transport layer to handle BLE User Asynchronous Events
|
// Register the hci transport layer to handle BLE User Asynchronous Events
|
||||||
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
|
HciUserEvtProcessId = osThreadNew(HciUserEvtProcess, NULL, &HciUserEvtProcess_attr);
|
||||||
// Starts the BLE Stack on CPU2
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
// Initialization of HCI & GATT & GAP layer
|
// Initialization of HCI & GATT & GAP layer
|
||||||
|
@ -18,6 +18,7 @@ typedef enum {
|
|||||||
} APP_BLE_ConnStatus_t;
|
} APP_BLE_ConnStatus_t;
|
||||||
|
|
||||||
bool APP_BLE_Init();
|
bool APP_BLE_Init();
|
||||||
|
bool APP_BLE_Start();
|
||||||
|
|
||||||
APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
|
APP_BLE_ConnStatus_t APP_BLE_Get_Server_Connection_Status();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user