apps/dtm/src/main.c (338 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "os/mynewt.h"
#include <console/console.h>
#include <parse.h>
#include <shell/shell.h>
#include "nimble/ble.h"
#include "nimble/nimble_opt.h"
#include "host/ble_hs.h"
#include "host/ble_dtm.h"
#include <img_mgmt/img_mgmt.h>
#include <bootutil/image.h>
static const struct kv_pair phy_opts[] = {
{ "1M", 0x01 },
{ "2M", 0x02 },
{ "coded", 0x03 },
{ NULL }
};
static const struct kv_pair modulation_index_opts[] = {
{ "standard", 0x00 },
{ "stable", 0x01 },
{ NULL }
};
static int
cmd_rx_test(int argc, char **argv)
{
struct ble_dtm_rx_params params;
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
params.channel = parse_arg_uint8("channel", &rc);
if ((rc != 0) || (params.channel > 39)) {
console_printf("invalid channel\n");
return rc;
}
params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc);
if (rc != 0) {
console_printf("invalid 'phy' parameter\n");
return rc;
}
params.modulation_index = parse_arg_kv_dflt("modulation_index",
modulation_index_opts, 0x00, &rc);
if (rc != 0) {
console_printf("invalid 'modulation_index' parameter\n");
return rc;
}
rc = ble_dtm_rx_start(¶ms);
if (rc) {
console_printf("failed to start RX test\n");
return rc;
}
console_printf("RX test started\n");
return 0;
}
static int
cmd_tx_test(int argc, char **argv)
{
struct ble_dtm_tx_params params;
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
params.channel = parse_arg_uint8("channel", &rc);
if ((rc != 0) || (params.channel > 39)) {
console_printf("invalid channel\n");
return rc;
}
params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc);
if (rc != 0) {
console_printf("invalid 'phy' parameter\n");
return rc;
}
params.payload = parse_arg_uint8("payload", &rc);
if ((rc != 0) || ((params.payload > 7))) {
console_printf("invalid 'payload' parameter\n");
return rc;
}
params.test_data_len = parse_arg_uint8_dflt("data_length", 0, &rc);
if (rc != 0) {
console_printf("invalid 'data_length' parameter\n");
return rc;
}
rc = ble_dtm_tx_start(¶ms);
if (rc) {
console_printf("failed to start TX test\n");
return rc;
}
console_printf("TX test started\n");
return 0;
}
static int
cmd_stop_test(int argc, char **argv)
{
uint16_t num_packets;
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
rc = ble_dtm_stop(&num_packets);
if (rc) {
console_printf("failed to stop test\n");
return rc;
}
console_printf("Test stopped (%u packets)\n", num_packets);
return 0;
}
static int
cmd_tx_power(int argc, char **argv)
{
struct ble_hci_vs_set_tx_pwr_cp cmd;
struct ble_hci_vs_set_tx_pwr_rp rsp;
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
cmd.tx_power = parse_arg_long_bounds_dflt("power",
-127, 127, 127, &rc);
if (rc != 0) {
console_printf("invalid 'power' parameter\n");
return rc;
}
rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd),
&rsp, sizeof(rsp));
if (rc) {
console_printf("failed to set TX power\n");
return rc;
}
console_printf("TX power set to %d dBm\n", rsp.tx_power);
return 0;
}
static int
cmd_set_antenna(int argc, char **argv)
{
struct ble_hci_vs_set_antenna_cp cmd;
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
cmd.antenna = parse_arg_uint8_dflt("antenna", 0, &rc);
if (rc != 0 || ((cmd.antenna > 2))) {
console_printf("invalid 'antenna' parameter\n");
return rc;
}
rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_ANTENNA, &cmd, sizeof(cmd),
NULL, 0);
if (rc) {
console_printf("failed to set antenna\n");
return rc;
}
console_printf("Antenna set to %u\n", cmd.antenna);
return 0;
}
#define BLE_HCI_OCF_VS_TEST_CARRIER (0x0020)
static bool tx_carrier_running = false;
static int
cmd_tx_carrier(int argc, char **argv)
{
uint8_t cmd[2];
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
if (tx_carrier_running) {
console_printf("TX carrier already started\n");
return 0;
}
cmd[0] = 1;
cmd[1] = parse_arg_uint8("channel", &rc);
if ((rc != 0) || (cmd[1] > 39)) {
console_printf("invalid channel\n");
return rc;
}
rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_TEST_CARRIER, &cmd, sizeof(cmd),
NULL, 0);
if (rc) {
console_printf("failed to start TX carrier\n");
return rc;
}
console_printf("TX carrier started\n");
tx_carrier_running = true;
return 0;
}
static int
cmd_stop_carrier(int argc, char **argv)
{
uint8_t cmd[2];
int rc;
rc = parse_arg_all(argc - 1, argv + 1);
if (rc != 0) {
return rc;
}
if (!tx_carrier_running) {
console_printf("TX carrier not started\n");
return 0;
}
cmd[0] = 0;
cmd[1] = 0;
rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_TEST_CARRIER, &cmd, sizeof(cmd),
NULL, 0);
if (rc) {
console_printf("failed to stop TX carrier\n");
return rc;
}
console_printf("TX carrier stopped\n");
tx_carrier_running = false;
return 0;
}
static const struct shell_param cmd_rx_test_params[] = {
{"channel", "RX channel, usage: =[0-39]"},
{"phy", "usage: =[1M|2M], default: 1M"},
{"modulation_index", "usage: =[standard|stable], default=standard"},
{NULL}
};
static const struct shell_cmd_help cmd_rx_test_help = {
.summary = "start DTM RX test",
.usage = NULL,
.params = cmd_rx_test_params,
};
static const struct shell_param cmd_tx_test_params[] = {
{"channel", "RX channel, usage: =[0-39]"},
{"phy", "usage: =[1M|2M], default: 1M"},
{"data_length", "usage: =[0-255], default: 0"},
{"payload", "usage: =[0-7]"},
{NULL}
};
static const struct shell_cmd_help cmd_tx_test_help = {
.summary = "start DTM TX test",
.usage = NULL,
.params = cmd_tx_test_params,
};
static const struct shell_cmd_help cmd_stop_test_help = {
.summary = "stop DTM test",
.usage = NULL,
.params = NULL,
};
static const struct shell_param cmd_tx_power_params[] = {
{"power", "usage: =[-127-127], default: 127"},
{NULL}
};
static const struct shell_cmd_help cmd_tx_power_help = {
.summary = "set TX power",
.usage = NULL,
.params = cmd_tx_power_params,
};
static const struct shell_param cmd_set_antenna_params[] = {
{"antenna", "usage: =[0,1,2], default: 0"},
{NULL}
};
static const struct shell_cmd_help cmd_set_antenna_help = {
.summary = "set active antenna ",
.usage = NULL,
.params = cmd_set_antenna_params,
};
static const struct shell_param cmd_tx_carrier_params[] = {
{"channel", "TX channel, usage: =[0-39]"},
{NULL}
};
static const struct shell_cmd_help cmd_tx_carrier_help = {
.summary = "TX unmodulated carrier",
.usage = NULL,
.params = cmd_tx_carrier_params,
};
static const struct shell_cmd_help cmd_stop_carrier_help = {
.summary = "stop TX unmodulated carrier",
.usage = NULL,
.params = NULL,
};
static const struct shell_cmd dtm_commands[] = {
{
.sc_cmd = "rx-test",
.sc_cmd_func = cmd_rx_test,
.help = &cmd_rx_test_help,
},
{
.sc_cmd = "tx-test",
.sc_cmd_func = cmd_tx_test,
.help = &cmd_tx_test_help,
},
{
.sc_cmd = "stop-test",
.sc_cmd_func = cmd_stop_test,
.help = &cmd_stop_test_help,
},
{
.sc_cmd = "tx-power",
.sc_cmd_func = cmd_tx_power,
.help = &cmd_tx_power_help,
},
{
.sc_cmd = "set-antenna",
.sc_cmd_func = cmd_set_antenna,
.help = &cmd_set_antenna_help,
},
{
.sc_cmd = "tx-carrier",
.sc_cmd_func = cmd_tx_carrier,
.help = &cmd_tx_carrier_help,
},
{
.sc_cmd = "stop-carrier",
.sc_cmd_func = cmd_stop_carrier,
.help = &cmd_stop_carrier_help,
},
{ }
};
static void
on_sync(void)
{
console_printf("Host and controller synced\n");
}
static void
on_reset(int reason)
{
console_printf("Error: Resetting state; reason=%d\n", reason);
}
int
main(void)
{
struct image_version the_version;
char prompt[50];
sysinit();
img_mgmt_read_info(0, &the_version, NULL, NULL);
snprintf(prompt, sizeof(prompt), "dtm_%u.%u.%u",
the_version.iv_major, the_version.iv_minor, the_version.iv_revision);
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = on_reset;
ble_hs_cfg.sync_cb = on_sync;
shell_register(prompt, dtm_commands);
shell_register_default_module(prompt);
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
return 0;
}