Explorar o código

[FL-1363] BLE GUI tests (#505)

* bt: introduce bt CLI commands

* api-hal-bt: add get rssi

* bt: fix cli commands

* bt: fix typos

* bt: refacrote bt test names

* ble gui continue

* bt: rework carrier test gui

* bt: rework send packets test gui

* bt: rework receive packets test

* api-hal-bt: change rssi return

* bt: refactore bt gui

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Co-authored-by: SG <who.just.the.doctor@gmail.com>
gornekich %!s(int64=4) %!d(string=hai) anos
pai
achega
d040515f84

+ 101 - 53
applications/bt/bt.c

@@ -12,10 +12,15 @@ void bt_update_statusbar(void* arg) {
     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
 }
 }
 
 
-void bt_switch_freq(void* arg) {
+void bt_update_param(void* arg) {
     furi_assert(arg);
     furi_assert(arg);
     Bt* bt = arg;
     Bt* bt = arg;
-    BtMessage m = {.type = BtMessageTypeStartTestToneTx};
+    BtMessage m;
+    if(bt->state.type == BtStateHoppingTx || bt->state.type == BtStateCarrierRxRunning) {
+        m.type = BtMessageTypeStartTestCarrier;
+    } else if(bt->state.type == BtStatePacketRunning) {
+        m.type = BtMessageTypeStartTestPacketRx;
+    }
     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
 }
 }
 
 
@@ -25,14 +30,14 @@ Bt* bt_alloc() {
     bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL);
     bt->message_queue = osMessageQueueNew(8, sizeof(BtMessage), NULL);
     bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL);
     bt->update_status_timer = osTimerNew(bt_update_statusbar, osTimerPeriodic, bt, NULL);
     osTimerStart(bt->update_status_timer, 4000);
     osTimerStart(bt->update_status_timer, 4000);
-    bt->hopping_mode_timer = osTimerNew(bt_switch_freq, osTimerPeriodic, bt, NULL);
+    bt->update_param_timer = osTimerNew(bt_update_param, osTimerPeriodic, bt, NULL);
     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.type = BtStateReady;
     bt->state.param.channel = BtChannel2402;
     bt->state.param.channel = BtChannel2402;
     bt->state.param.power = BtPower0dB;
     bt->state.param.power = BtPower0dB;
-    bt->state.param.datarate = BtDateRate1M;
+    bt->state.param.datarate = BtDataRate1M;
 
 
     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);
@@ -43,40 +48,51 @@ 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(
     menu_item_subitem_add(
-        bt->menu_item, menu_item_alloc_function("Test tone TX", NULL, bt_menu_test_tone_tx, bt));
+        bt->menu_item, menu_item_alloc_function("Carrier test", NULL, bt_menu_test_carrier, bt));
     menu_item_subitem_add(
     menu_item_subitem_add(
         bt->menu_item,
         bt->menu_item,
         menu_item_alloc_function("Test packet TX", NULL, bt_menu_test_packet_tx, bt));
         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(
     menu_item_subitem_add(
         bt->menu_item, menu_item_alloc_function("Start app", NULL, bt_menu_start_app, bt));
         bt->menu_item, menu_item_alloc_function("Start app", NULL, bt_menu_start_app, bt));
+    menu_item_subitem_add(
+        bt->menu_item,
+        menu_item_alloc_function("Test packet RX", NULL, bt_menu_test_packet_rx, 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);
+    // Carrier test
+    bt->view_test_carrier = view_alloc();
+    view_set_context(bt->view_test_carrier, bt);
+    view_set_draw_callback(bt->view_test_carrier, bt_view_test_carrier_draw);
     view_allocate_model(
     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_carrier, ViewModelTypeLocking, sizeof(BtViewTestCarrierModel));
+    view_set_input_callback(bt->view_test_carrier, bt_view_test_carrier_input);
+
+    // Packet TX test
     bt->view_test_packet_tx = view_alloc();
     bt->view_test_packet_tx = view_alloc();
     view_set_context(bt->view_test_packet_tx, bt);
     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_set_draw_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_draw);
     view_allocate_model(
     view_allocate_model(
         bt->view_test_packet_tx, ViewModelTypeLocking, sizeof(BtViewTestPacketTxModel));
         bt->view_test_packet_tx, ViewModelTypeLocking, sizeof(BtViewTestPacketTxModel));
     view_set_input_callback(bt->view_test_packet_tx, bt_view_test_packet_tx_input);
     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);
+
+    // Packet RX test
+    bt->view_test_packet_rx = view_alloc();
+    view_set_context(bt->view_test_packet_rx, bt);
+    view_set_draw_callback(bt->view_test_packet_rx, bt_view_test_packet_rx_draw);
+    view_allocate_model(
+        bt->view_test_packet_rx, ViewModelTypeLocking, sizeof(BtViewTestPacketRxModel));
+    view_set_input_callback(bt->view_test_packet_rx, bt_view_test_packet_rx_input);
+
+    // Start app
     bt->view_start_app = view_alloc();
     bt->view_start_app = view_alloc();
     view_set_context(bt->view_start_app, bt);
     view_set_context(bt->view_start_app, bt);
     view_set_draw_callback(bt->view_start_app, bt_view_app_draw);
     view_set_draw_callback(bt->view_start_app, bt_view_app_draw);
     view_set_previous_callback(bt->view_start_app, bt_view_exit);
     view_set_previous_callback(bt->view_start_app, bt_view_exit);
+
+    // View dispatcher
     bt->view_dispatcher = view_dispatcher_alloc();
     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, BtViewTestCarrier, bt->view_test_carrier);
     view_dispatcher_add_view(bt->view_dispatcher, BtViewTestPacketTx, bt->view_test_packet_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, BtViewTestPacketRx, bt->view_test_packet_rx);
     view_dispatcher_add_view(bt->view_dispatcher, BtViewStartApp, bt->view_start_app);
     view_dispatcher_add_view(bt->view_dispatcher, BtViewStartApp, bt->view_start_app);
 
 
     Gui* gui = furi_record_open("gui");
     Gui* gui = furi_record_open("gui");
@@ -91,12 +107,12 @@ 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) {
+void bt_menu_test_carrier(void* context) {
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
-    bt->state.type = BtStatusToneTx;
+    bt->state.type = BtStateCarrierTx;
     BtMessage message = {
     BtMessage message = {
-        .type = BtMessageTypeStartTestToneTx,
+        .type = BtMessageTypeStartTestCarrier,
         .param.channel = bt->state.param.channel,
         .param.channel = bt->state.param.channel,
         .param.power = bt->state.param.power};
         .param.power = bt->state.param.power};
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
@@ -105,7 +121,7 @@ void bt_menu_test_tone_tx(void* context) {
 void bt_menu_test_packet_tx(void* context) {
 void bt_menu_test_packet_tx(void* context) {
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
-    bt->state.type = BtStatusPacketSetup;
+    bt->state.type = BtStatePacketSetup;
     BtMessage message = {
     BtMessage message = {
         .type = BtMessageTypeSetupTestPacketTx,
         .type = BtMessageTypeSetupTestPacketTx,
         .param.channel = bt->state.param.channel,
         .param.channel = bt->state.param.channel,
@@ -113,21 +129,21 @@ void bt_menu_test_packet_tx(void* context) {
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
 }
 }
 
 
-void bt_menu_test_tone_rx(void* context) {
+void bt_menu_test_packet_rx(void* context) {
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
-    bt->state.type = BtStatusToneRx;
+    bt->state.type = BtStatePacketSetup;
     BtMessage message = {
     BtMessage message = {
-        .type = BtMessageTypeStartTestRx,
+        .type = BtMessageTypeSetupTestPacketRx,
         .param.channel = bt->state.param.channel,
         .param.channel = bt->state.param.channel,
-        .param.power = bt->state.param.power};
+        .param.datarate = bt->state.param.datarate};
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
 }
 }
 
 
 void bt_menu_start_app(void* context) {
 void bt_menu_start_app(void* context) {
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
-    bt->state.type = BtStatusStartedApp;
+    bt->state.type = BtStateStartedApp;
     BtMessage message = {.type = BtMessageTypeStartApp};
     BtMessage message = {.type = BtMessageTypeStartApp};
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
     furi_check(osMessageQueuePut(bt->message_queue, &message, 0, osWaitForever) == osOK);
 }
 }
@@ -141,29 +157,37 @@ int32_t bt_task() {
     BtMessage message;
     BtMessage message;
     while(1) {
     while(1) {
         furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
         furi_check(osMessageQueueGet(bt->message_queue, &message, NULL, osWaitForever) == osOK);
-        if(message.type == BtMessageTypeStartTestToneTx) {
-            // Start test tx
+        if(message.type == BtMessageTypeStartTestCarrier) {
+            // Start carrier test
             api_hal_bt_stop_tone_tx();
             api_hal_bt_stop_tone_tx();
-            if(bt->state.type == BtStatusToneTx) {
+            if(bt->state.type == BtStateCarrierTx) {
                 api_hal_bt_start_tone_tx(message.param.channel, message.param.power);
                 api_hal_bt_start_tone_tx(message.param.channel, message.param.power);
-            } else {
+            } else if(bt->state.type == BtStateHoppingTx) {
                 bt->state.param.channel =
                 bt->state.param.channel =
                     bt_switch_channel(InputKeyRight, 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);
                 api_hal_bt_start_tone_tx(bt->state.param.channel, bt->state.param.power);
+            } else if(bt->state.type == BtStateCarrierRxStart) {
+                api_hal_bt_start_packet_rx(bt->state.param.channel, bt->state.param.datarate);
+                bt->state.type = BtStateCarrierRxRunning;
+            } else if(bt->state.type == BtStateCarrierRxRunning) {
+                bt->state.param.rssi = api_hal_bt_get_rssi();
             }
             }
             with_view_model(
             with_view_model(
-                bt->view_test_tone_tx, (BtViewTestToneTxModel * model) {
+                bt->view_test_carrier, (BtViewTestCarrierModel * model) {
                     model->type = bt->state.type;
                     model->type = bt->state.type;
                     model->channel = bt->state.param.channel;
                     model->channel = bt->state.param.channel;
                     model->power = bt->state.param.power;
                     model->power = bt->state.param.power;
+                    model->rssi = bt->state.param.rssi;
                     return true;
                     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;
+            view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestCarrier);
+        } else if(message.type == BtMessageTypeStopTestCarrier) {
+            if(bt->state.type == BtStateCarrierRxRunning) {
+                api_hal_bt_stop_packet_test();
+            } else {
+                api_hal_bt_stop_tone_tx();
+            }
+            bt->state.type = BtStateReady;
         } else if(message.type == BtMessageTypeSetupTestPacketTx) {
         } else if(message.type == BtMessageTypeSetupTestPacketTx) {
             // Update packet test setup
             // Update packet test setup
             api_hal_bt_stop_packet_test();
             api_hal_bt_stop_packet_test();
@@ -177,37 +201,61 @@ int32_t bt_task() {
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
         } else if(message.type == BtMessageTypeStartTestPacketTx) {
         } else if(message.type == BtMessageTypeStartTestPacketTx) {
             // Start sending packets
             // Start sending packets
-            api_hal_bt_start_packet_tx(message.param.channel, 1, message.param.datarate);
+            if(bt->state.type == BtStatePacketStart) {
+                api_hal_bt_start_packet_tx(message.param.channel, 1, message.param.datarate);
+            } else if(bt->state.type == BtStatePacketSetup) {
+                api_hal_bt_stop_packet_test();
+                bt->state.param.packets_sent = api_hal_bt_get_transmitted_packets();
+            }
             with_view_model(
             with_view_model(
                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) {
                 bt->view_test_packet_tx, (BtViewTestPacketTxModel * model) {
                     model->type = bt->state.type;
                     model->type = bt->state.type;
                     model->channel = bt->state.param.channel;
                     model->channel = bt->state.param.channel;
                     model->datarate = bt->state.param.datarate;
                     model->datarate = bt->state.param.datarate;
+                    model->packets_sent = bt->state.param.packets_sent;
                     return true;
                     return true;
                 });
                 });
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketTx);
-        } else if(message.type == BtMessageTypeStopTestPacketTx) {
-            // Stop test packet tx
+        } else if(message.type == BtMessageTypeSetupTestPacketRx) {
+            // Update packet test setup
             api_hal_bt_stop_packet_test();
             api_hal_bt_stop_packet_test();
-            bt->state.type = BtStatusReady;
-        } else if(message.type == BtMessageTypeStartTestRx) {
+            with_view_model(
+                bt->view_test_packet_rx, (BtViewTestPacketRxModel * 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, BtViewTestPacketRx);
+        } else if(message.type == BtMessageTypeStartTestPacketRx) {
             // Start test rx
             // Start test rx
-            api_hal_bt_start_rx(message.param.channel);
+            if(bt->state.type == BtStatePacketStart) {
+                api_hal_bt_start_packet_rx(message.param.channel, message.param.datarate);
+                bt->state.type = BtStatePacketRunning;
+            } else if(bt->state.type == BtStatePacketRunning) {
+                bt->state.param.rssi = api_hal_bt_get_rssi();
+            } else if(bt->state.type == BtStatePacketSetup) {
+                bt->state.param.packets_received = api_hal_bt_stop_packet_test();
+            }
             with_view_model(
             with_view_model(
-                bt->view_test_tone_rx, (BtViewTestRxModel * model) {
+                bt->view_test_packet_rx, (BtViewTestPacketRxModel * model) {
+                    model->type = bt->state.type;
                     model->channel = bt->state.param.channel;
                     model->channel = bt->state.param.channel;
+                    model->datarate = bt->state.param.datarate;
+                    model->packets_received = bt->state.param.packets_received;
+                    model->rssi = bt->state.param.rssi;
                     return true;
                     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;
+            view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewTestPacketRx);
+        } else if(message.type == BtMessageTypeStopTestPacket) {
+            // Stop test packet tx
+            api_hal_bt_stop_packet_test();
+            bt->state.type = BtStateReady;
         } else if(message.type == BtMessageTypeStartApp) {
         } else if(message.type == BtMessageTypeStartApp) {
             // Start app
             // Start app
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewStartApp);
             view_dispatcher_switch_to_view(bt->view_dispatcher, BtViewStartApp);
             if(api_hal_bt_start_app()) {
             if(api_hal_bt_start_app()) {
-                bt->state.type = BtStatusStartedApp;
+                bt->state.type = BtStateStartedApp;
             }
             }
         } else if(message.type == BtMessageTypeUpdateStatusbar) {
         } else if(message.type == BtMessageTypeUpdateStatusbar) {
             // Update statusbar
             // Update statusbar

+ 5 - 5
applications/bt/bt_i.h

@@ -21,7 +21,7 @@ struct Bt {
     osMessageQueueId_t message_queue;
     osMessageQueueId_t message_queue;
     BtState state;
     BtState state;
     osTimerId_t update_status_timer;
     osTimerId_t update_status_timer;
-    osTimerId_t hopping_mode_timer;
+    osTimerId_t update_param_timer;
     Gui* gui;
     Gui* gui;
     ValueMutex* menu;
     ValueMutex* menu;
     // Status bar
     // Status bar
@@ -29,9 +29,9 @@ struct Bt {
     // Menu
     // Menu
     Icon* menu_icon;
     Icon* menu_icon;
     MenuItem* menu_item;
     MenuItem* menu_item;
-    View* view_test_tone_tx;
+    View* view_test_carrier;
     View* view_test_packet_tx;
     View* view_test_packet_tx;
-    View* view_test_tone_rx;
+    View* view_test_packet_rx;
     View* view_start_app;
     View* view_start_app;
     ViewDispatcher* view_dispatcher;
     ViewDispatcher* view_dispatcher;
 };
 };
@@ -44,10 +44,10 @@ BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan);
 
 
 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_carrier(void* context);
 
 
 void bt_menu_test_packet_tx(void* context);
 void bt_menu_test_packet_tx(void* context);
 
 
-void bt_menu_test_tone_rx(void* context);
+void bt_menu_test_packet_rx(void* context);
 
 
 void bt_menu_start_app(void* context);
 void bt_menu_start_app(void* context);

+ 21 - 14
applications/bt/bt_types.h

@@ -1,26 +1,30 @@
 #pragma once
 #pragma once
 
 
+#include <stdint.h>
+
 typedef enum {
 typedef enum {
-    BtMessageTypeStartTestToneTx,
+    BtMessageTypeStartTestCarrier,
     BtMessageTypeHoppingTx,
     BtMessageTypeHoppingTx,
-    BtMessageTypeStopTestToneTx,
+    BtMessageTypeStopTestCarrier,
     BtMessageTypeSetupTestPacketTx,
     BtMessageTypeSetupTestPacketTx,
+    BtMessageTypeSetupTestPacketRx,
     BtMessageTypeStartTestPacketTx,
     BtMessageTypeStartTestPacketTx,
-    BtMessageTypeStopTestPacketTx,
-    BtMessageTypeStartTestRx,
-    BtMessageTypeStopTestRx,
+    BtMessageTypeStartTestPacketRx,
+    BtMessageTypeStopTestPacket,
     BtMessageTypeStartApp,
     BtMessageTypeStartApp,
     BtMessageTypeUpdateStatusbar,
     BtMessageTypeUpdateStatusbar,
 } BtMessageType;
 } BtMessageType;
 
 
 typedef enum {
 typedef enum {
-    BtStatusReady,
-    BtStatusToneTx,
-    BtStatusHoppingTx,
-    BtStatusToneRx,
-    BtStatusPacketSetup,
-    BtStatusPacketTx,
-    BtStatusStartedApp,
+    BtStateReady,
+    BtStateCarrierTx,
+    BtStateHoppingTx,
+    BtStateCarrierRxStart,
+    BtStateCarrierRxRunning,
+    BtStatePacketSetup,
+    BtStatePacketStart,
+    BtStatePacketRunning,
+    BtStateStartedApp,
 } BtStateType;
 } BtStateType;
 
 
 typedef enum {
 typedef enum {
@@ -37,14 +41,17 @@ typedef enum {
 } BtTestPower;
 } BtTestPower;
 
 
 typedef enum {
 typedef enum {
-    BtDateRate1M = 1,
-    BtDateRate2M = 2,
+    BtDataRate1M = 1,
+    BtDataRate2M = 2,
 } BtTestDataRate;
 } BtTestDataRate;
 
 
 typedef struct {
 typedef struct {
     BtTestChannel channel;
     BtTestChannel channel;
     BtTestPower power;
     BtTestPower power;
     BtTestDataRate datarate;
     BtTestDataRate datarate;
+    float rssi;
+    uint16_t packets_sent;
+    uint16_t packets_received;
 } BtTestParam;
 } BtTestParam;
 
 
 typedef struct {
 typedef struct {

+ 106 - 44
applications/bt/bt_views.c

@@ -1,30 +1,49 @@
 #include "bt_views.h"
 #include "bt_views.h"
 
 
-void bt_view_test_tone_tx_draw(Canvas* canvas, void* model) {
-    BtViewTestToneTxModel* m = model;
+void bt_view_test_carrier_draw(Canvas* canvas, void* model) {
+    BtViewTestCarrierModel* m = model;
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_font(canvas, FontSecondary);
     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");
+    canvas_draw_str(canvas, 0, 12, "Performing Cattier test");
+    if(m->type == BtStateCarrierTx) {
+        canvas_draw_str(canvas, 0, 24, "Manual Carrier TX");
+    } else if(m->type == BtStateHoppingTx) {
+        canvas_draw_str(canvas, 0, 24, "Carrier TX Hopping mode");
+    } else if(m->type == BtStateCarrierRxRunning) {
+        canvas_draw_str(canvas, 0, 24, "Manual Carrier RX");
     }
     }
     char buffer[32];
     char buffer[32];
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
     canvas_draw_str(canvas, 0, 36, buffer);
     canvas_draw_str(canvas, 0, 36, buffer);
-    snprintf(buffer, sizeof(buffer), "Power:%d dB", m->power - BtPower0dB);
+    if(m->type == BtStateCarrierTx || m->type == BtStateHoppingTx) {
+        snprintf(buffer, sizeof(buffer), "Power:%d dB", m->power - BtPower0dB);
+    } else if(m->type == BtStateCarrierRxRunning) {
+        snprintf(buffer, sizeof(buffer), "RSSI: %3.1f dB", m->rssi);
+    }
     canvas_draw_str(canvas, 0, 48, buffer);
     canvas_draw_str(canvas, 0, 48, buffer);
 }
 }
 
 
-void bt_view_test_tone_rx_draw(Canvas* canvas, void* model) {
-    BtViewTestRxModel* m = model;
+void bt_view_test_packet_rx_draw(Canvas* canvas, void* model) {
+    BtViewTestPacketRxModel* m = model;
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str(canvas, 0, 12, "Performing continous RX test");
+    canvas_draw_str(canvas, 0, 12, "Performing packets RX test");
+    if(m->type == BtStatePacketSetup) {
+        canvas_draw_str(canvas, 0, 24, "Setup parameters. Ok to start");
+    } else {
+        canvas_draw_str(canvas, 0, 24, "Receiving packets ...");
+    }
     char buffer[32];
     char buffer[32];
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
-    canvas_draw_str(canvas, 0, 24, buffer);
+    canvas_draw_str(canvas, 0, 36, buffer);
+    snprintf(buffer, sizeof(buffer), "Datarate:%d Mbps", m->datarate);
+    canvas_draw_str(canvas, 0, 48, buffer);
+    if(m->type == BtStatePacketSetup) {
+        snprintf(buffer, sizeof(buffer), "%d packets received", m->packets_received);
+    } else {
+        snprintf(buffer, sizeof(buffer), "RSSI: %3.1f dB", m->rssi);
+    }
+    canvas_draw_str(canvas, 0, 60, buffer);
 }
 }
 
 
 void bt_view_test_packet_tx_draw(Canvas* canvas, void* model) {
 void bt_view_test_packet_tx_draw(Canvas* canvas, void* model) {
@@ -32,18 +51,20 @@ void bt_view_test_packet_tx_draw(Canvas* canvas, void* model) {
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
     canvas_draw_str(canvas, 0, 12, "Packets send TX test");
     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");
+    if(m->type == BtStatePacketSetup) {
+        canvas_draw_str(canvas, 0, 24, "Setup parameters. Ok to start");
     } else {
     } else {
-        canvas_draw_str(canvas, 0, 24, "Sending packets");
-        canvas_draw_str(canvas, 0, 36, "Packets parameters:");
+        canvas_draw_str(canvas, 0, 24, "Sending packets ...");
     }
     }
     char buffer[32];
     char buffer[32];
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
     snprintf(buffer, sizeof(buffer), "Channel:%d MHz", m->channel * 2 + 2402);
+    canvas_draw_str(canvas, 0, 36, buffer);
+    snprintf(buffer, sizeof(buffer), "Datarate:%d Mbps", m->datarate);
     canvas_draw_str(canvas, 0, 48, buffer);
     canvas_draw_str(canvas, 0, 48, buffer);
-    snprintf(buffer, sizeof(buffer), "Daterate:%d Mbps", m->datarate);
-    canvas_draw_str(canvas, 0, 60, buffer);
+    if(m->packets_sent && m->type == BtStatePacketSetup) {
+        snprintf(buffer, sizeof(buffer), "%d packets sent", m->packets_sent);
+        canvas_draw_str(canvas, 0, 60, buffer);
+    }
 }
 }
 
 
 void bt_view_app_draw(Canvas* canvas, void* model) {
 void bt_view_app_draw(Canvas* canvas, void* model) {
@@ -73,16 +94,16 @@ BtTestChannel bt_switch_channel(InputKey key, BtTestChannel inst_chan) {
     return arr[0];
     return arr[0];
 }
 }
 
 
-bool bt_view_test_tone_tx_input(InputEvent* event, void* context) {
+bool bt_view_test_carrier_input(InputEvent* event, void* context) {
     furi_assert(event);
     furi_assert(event);
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
     if(event->type == InputTypeShort) {
     if(event->type == InputTypeShort) {
         if(event->key == InputKeyBack) {
         if(event->key == InputKeyBack) {
-            if(osTimerIsRunning(bt->hopping_mode_timer)) {
-                osTimerStop(bt->hopping_mode_timer);
+            if(osTimerIsRunning(bt->update_param_timer)) {
+                osTimerStop(bt->update_param_timer);
             }
             }
-            BtMessage m = {.type = BtMessageTypeStopTestToneTx};
+            BtMessage m = {.type = BtMessageTypeStopTestCarrier};
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);
             return true;
             return true;
@@ -98,16 +119,20 @@ bool bt_view_test_tone_tx_input(InputEvent* event, void* context) {
                     bt->state.param.power -= 2;
                     bt->state.param.power -= 2;
                 }
                 }
             } else if(event->key == InputKeyOk) {
             } else if(event->key == InputKeyOk) {
-                if(bt->state.type == BtStatusToneTx) {
-                    bt->state.type = BtStatusHoppingTx;
-                    osTimerStart(bt->hopping_mode_timer, 2000);
+                if(bt->state.type == BtStateCarrierTx) {
+                    bt->state.type = BtStateHoppingTx;
+                    osTimerStart(bt->update_param_timer, 2000);
+                } else if(bt->state.type == BtStateHoppingTx) {
+                    osTimerStop(bt->update_param_timer);
+                    bt->state.type = BtStateCarrierRxStart;
+                    osTimerStart(bt->update_param_timer, 200);
                 } else {
                 } else {
-                    bt->state.type = BtStatusToneTx;
-                    osTimerStop(bt->hopping_mode_timer);
+                    osTimerStop(bt->update_param_timer);
+                    bt->state.type = BtStateCarrierTx;
                 }
                 }
             }
             }
             BtMessage m = {
             BtMessage m = {
-                .type = BtMessageTypeStartTestToneTx,
+                .type = BtMessageTypeStartTestCarrier,
                 .param.channel = bt->state.param.channel,
                 .param.channel = bt->state.param.channel,
                 .param.power = bt->state.param.power};
                 .param.power = bt->state.param.power};
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
@@ -117,30 +142,58 @@ bool bt_view_test_tone_tx_input(InputEvent* event, void* context) {
     return false;
     return false;
 }
 }
 
 
-bool bt_view_test_tone_rx_input(InputEvent* event, void* context) {
+bool bt_view_test_packet_tx_input(InputEvent* event, void* context) {
     furi_assert(event);
     furi_assert(event);
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
     if(event->type == InputTypeShort) {
     if(event->type == InputTypeShort) {
-        if(event->key == InputKeyRight || event->key == InputKeyLeft) {
-            bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel);
+        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 < BtDataRate2M) {
+                    bt->state.param.datarate += 1;
+                }
+            } else if(event->key == InputKeyDown) {
+                if(bt->state.param.datarate > BtDataRate1M) {
+                    bt->state.param.datarate -= 1;
+                }
+            }
+            bt->state.type = BtStatePacketSetup;
             BtMessage m = {
             BtMessage m = {
-                .type = BtMessageTypeStartTestRx, .param.channel = bt->state.param.channel};
+                .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) {
+            if(bt->state.type == BtStatePacketSetup) {
+                bt->state.type = BtStatePacketStart;
+            } else if(bt->state.type == BtStatePacketStart) {
+                bt->state.type = BtStatePacketSetup;
+            }
+            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);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             return true;
             return true;
         } else if(event->key == InputKeyBack) {
         } else if(event->key == InputKeyBack) {
-            BtMessage m = {.type = BtMessageTypeStopTestRx};
+            BtMessage m = {
+                .type = BtMessageTypeStopTestPacket,
+            };
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);
             return true;
             return true;
-        } else {
-            return false;
         }
         }
     }
     }
     return false;
     return false;
 }
 }
 
 
-bool bt_view_test_packet_tx_input(InputEvent* event, void* context) {
+bool bt_view_test_packet_rx_input(InputEvent* event, void* context) {
     furi_assert(event);
     furi_assert(event);
     furi_assert(context);
     furi_assert(context);
     Bt* bt = context;
     Bt* bt = context;
@@ -150,34 +203,43 @@ bool bt_view_test_packet_tx_input(InputEvent* event, void* context) {
             if(event->key == InputKeyRight || event->key == InputKeyLeft) {
             if(event->key == InputKeyRight || event->key == InputKeyLeft) {
                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel);
                 bt->state.param.channel = bt_switch_channel(event->key, bt->state.param.channel);
             } else if(event->key == InputKeyUp) {
             } else if(event->key == InputKeyUp) {
-                if(bt->state.param.datarate < BtDateRate2M) {
+                if(bt->state.param.datarate < BtDataRate2M) {
                     bt->state.param.datarate += 1;
                     bt->state.param.datarate += 1;
                 }
                 }
             } else if(event->key == InputKeyDown) {
             } else if(event->key == InputKeyDown) {
-                if(bt->state.param.datarate > BtDateRate1M) {
+                if(bt->state.param.datarate > BtDataRate1M) {
                     bt->state.param.datarate -= 1;
                     bt->state.param.datarate -= 1;
                 }
                 }
             }
             }
-            bt->state.type = BtStatusPacketSetup;
+            bt->state.type = BtStatePacketSetup;
             BtMessage m = {
             BtMessage m = {
-                .type = BtMessageTypeSetupTestPacketTx,
+                .type = BtMessageTypeSetupTestPacketRx,
                 .param.channel = bt->state.param.channel,
                 .param.channel = bt->state.param.channel,
                 .param.datarate = bt->state.param.datarate,
                 .param.datarate = bt->state.param.datarate,
             };
             };
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             return true;
             return true;
         } else if(event->key == InputKeyOk) {
         } else if(event->key == InputKeyOk) {
-            bt->state.type = BtStatusPacketTx;
+            if(bt->state.type == BtStatePacketSetup) {
+                bt->state.type = BtStatePacketStart;
+                osTimerStart(bt->update_param_timer, 200);
+            } else if(bt->state.type == BtStatePacketRunning) {
+                bt->state.type = BtStatePacketSetup;
+                osTimerStop(bt->update_param_timer);
+            }
             BtMessage m = {
             BtMessage m = {
-                .type = BtMessageTypeStartTestPacketTx,
+                .type = BtMessageTypeStartTestPacketRx,
                 .param.channel = bt->state.param.channel,
                 .param.channel = bt->state.param.channel,
                 .param.datarate = bt->state.param.datarate,
                 .param.datarate = bt->state.param.datarate,
             };
             };
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             return true;
             return true;
         } else if(event->key == InputKeyBack) {
         } else if(event->key == InputKeyBack) {
+            if(osTimerIsRunning(bt->update_param_timer)) {
+                osTimerStop(bt->update_param_timer);
+            }
             BtMessage m = {
             BtMessage m = {
-                .type = BtMessageTypeStopTestPacketTx,
+                .type = BtMessageTypeStopTestPacket,
             };
             };
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             furi_check(osMessageQueuePut(bt->message_queue, &m, 0, osWaitForever) == osOK);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);
             view_dispatcher_switch_to_view(bt->view_dispatcher, VIEW_NONE);

+ 14 - 8
applications/bt/bt_views.h

@@ -11,9 +11,9 @@
 #include <gui/view.h>
 #include <gui/view.h>
 
 
 typedef enum {
 typedef enum {
-    BtViewTestToneTx,
+    BtViewTestCarrier,
     BtViewTestPacketTx,
     BtViewTestPacketTx,
-    BtViewTestToneRx,
+    BtViewTestPacketRx,
     BtViewStartApp,
     BtViewStartApp,
 } BtView;
 } BtView;
 
 
@@ -21,28 +21,34 @@ typedef struct {
     BtStateType type;
     BtStateType type;
     BtTestChannel channel;
     BtTestChannel channel;
     BtTestPower power;
     BtTestPower power;
-} BtViewTestToneTxModel;
+    float rssi;
+} BtViewTestCarrierModel;
 
 
 typedef struct {
 typedef struct {
     BtStateType type;
     BtStateType type;
     BtTestChannel channel;
     BtTestChannel channel;
     BtTestDataRate datarate;
     BtTestDataRate datarate;
+    uint16_t packets_sent;
 } BtViewTestPacketTxModel;
 } BtViewTestPacketTxModel;
 
 
 typedef struct {
 typedef struct {
+    BtStateType type;
     BtTestChannel channel;
     BtTestChannel channel;
-} BtViewTestRxModel;
+    BtTestDataRate datarate;
+    float rssi;
+    uint16_t packets_received;
+} BtViewTestPacketRxModel;
 
 
-void bt_view_test_tone_tx_draw(Canvas* canvas, void* model);
+void bt_view_test_carrier_draw(Canvas* canvas, void* model);
 
 
-bool bt_view_test_tone_tx_input(InputEvent* event, void* context);
+bool bt_view_test_carrier_input(InputEvent* event, void* context);
 
 
 void bt_view_test_packet_tx_draw(Canvas* canvas, void* model);
 void bt_view_test_packet_tx_draw(Canvas* canvas, void* model);
 
 
 bool bt_view_test_packet_tx_input(InputEvent* event, void* context);
 bool bt_view_test_packet_tx_input(InputEvent* event, void* context);
 
 
-void bt_view_test_tone_rx_draw(Canvas* canvas, void* model);
+void bt_view_test_packet_rx_draw(Canvas* canvas, void* model);
 
 
-bool bt_view_test_tone_rx_input(InputEvent* event, void* context);
+bool bt_view_test_packet_rx_input(InputEvent* event, void* context);
 
 
 void bt_view_app_draw(Canvas* canvas, void* model);
 void bt_view_app_draw(Canvas* canvas, void* model);

+ 1 - 1
firmware/targets/f5/api-hal/api-hal-bt.c

@@ -118,7 +118,7 @@ float api_hal_bt_get_rssi() {
     uint8_t agc = rssi_raw[2] & 0xFF;
     uint8_t agc = rssi_raw[2] & 0xFF;
     int rssi = (rssi_raw[1] << 8 & 0xFF00) + (rssi_raw[1] & 0xFF);
     int rssi = (rssi_raw[1] << 8 & 0xFF00) + (rssi_raw[1] & 0xFF);
     if(rssi == 0 || agc > 11) {
     if(rssi == 0 || agc > 11) {
-        val = 127;
+        val = -127.0;
     } else {
     } else {
         val = agc * 6.0f - 127.0f;
         val = agc * 6.0f - 127.0f;
         while(rssi > 30) {
         while(rssi > 30) {

+ 1 - 1
firmware/targets/f6/api-hal/api-hal-bt.c

@@ -118,7 +118,7 @@ float api_hal_bt_get_rssi() {
     uint8_t agc = rssi_raw[2] & 0xFF;
     uint8_t agc = rssi_raw[2] & 0xFF;
     int rssi = (rssi_raw[1] << 8 & 0xFF00) + (rssi_raw[1] & 0xFF);
     int rssi = (rssi_raw[1] << 8 & 0xFF00) + (rssi_raw[1] & 0xFF);
     if(rssi == 0 || agc > 11) {
     if(rssi == 0 || agc > 11) {
-        val = 127;
+        val = -127.0;
     } else {
     } else {
         val = agc * 6.0f - 127.0f;
         val = agc * 6.0f - 127.0f;
         while(rssi > 30) {
         while(rssi > 30) {