sdk-hwV1.3/lichee/xr806/appos/project/common/cmd/cmd_adv.c

249 lines
6.6 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(CONFIG_BLEHOST)
#include "cmd_util.h"
#include "ble/bluetooth/bluetooth.h"
#define ADV_THREAD_STACK_SIZE (2 * 1024)
#define ADV_CREAT_THREAD(THREAD, TASK, ARG) \
{ \
if (OS_ThreadIsValid(&THREAD)) { \
CMD_ERR("adv task is running\n"); \
return CMD_STATUS_FAIL; \
} \
if (OS_ThreadCreate(&THREAD, \
"", \
TASK, \
(void *)ARG, \
OS_THREAD_PRIO_APP, \
ADV_THREAD_STACK_SIZE) != OS_OK) { \
CMD_ERR("adv task create failed\n"); \
return CMD_STATUS_FAIL; \
} \
}
#define ADV_DELETE_THREAD(THREAD) OS_ThreadDelete(&THREAD)
static OS_Thread_t g_adv_start_thread;
static uint8_t g_task_end = 1;
static uint32_t gAdvIntMin, gAdvIntMax;
#if 0
#define ADV_CONN_NAME_EX BT_LE_ADV_PARAM(BT_LE_ADV_OPT_NONE, \
BT_GAP_ADV_FAST_INT_MIN_2, \
0X00B0, NULL) /* 100~110ms */
struct bt_data adv_data[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(0xff, 0x01, 0x00), //manu_type: BT_DATA_MANUFACTURER_DATA
BT_DATA_BYTES(BT_DATA_NAME_COMPLETE, 't', 'e', 's', 't'),
};
#endif
static int adv_start(uint8_t manu_type, uint16_t index, uint32_t chan)
{
int err;
struct bt_data adv_data[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(manu_type, index & 0xFF, (index >> 8) & 0xFF), //manu_type: BT_DATA_MANUFACTURER_DATA
BT_DATA_BYTES(BT_DATA_NAME_COMPLETE, 't', 'e', 's', 't'),
};
struct bt_le_adv_param adv_param[] = {
{
.options = BT_LE_ADV_OPT_CONNECTABLE,
.interval_min = gAdvIntMin > 0 ? gAdvIntMin : BT_GAP_ADV_FAST_INT_MIN_2,
.interval_max = gAdvIntMax > 0 ? gAdvIntMax : 0x00B0,
},
};
if (!(chan & 0x01))
adv_param[0].options |= BT_LE_ADV_OPT_DISABLE_CHAN_37;
if (!(chan & 0x02))
adv_param[0].options |= BT_LE_ADV_OPT_DISABLE_CHAN_38;
if (!(chan & 0x04))
adv_param[0].options |= BT_LE_ADV_OPT_DISABLE_CHAN_39;
err = bt_le_adv_start(adv_param, adv_data, ARRAY_SIZE(adv_data), NULL, 0);
if (err) {
CMD_ERR("Advertising failed to start (err %d)\n", err);
return -1;
}
return 0;
}
static int adv_stop(void)
{
return bt_le_adv_stop();
}
__WEAK void get_tick_adv_start(void)
{
}
static void adv_start_exec(void *cmd)
{
int cnt;
uint32_t index, adv_times, delay;
(void)delay;
#if 0
cnt = cmd_sscanf(cmd, "n=%d", &adv_times);
if (cnt != 1 || adv_times > 0xFFFF) {
CMD_ERR("invalid arg\n");
goto exit;
}
#else
uint32_t interval, channel, manu_type;
cnt = cmd_sscanf(cmd, "int=0x%x chl=0x%x manu_type=0x%x num=%d",
&interval, &channel, &manu_type, &adv_times);
if (cnt != 4 || adv_times > 0xFFFF) {
CMD_ERR("invalid arg\n");
goto exit;
}
gAdvIntMin = interval;
gAdvIntMax = interval;
uint32_t gAdvIntMin_ms = interval * 0.625;
delay = (gAdvIntMin_ms / 2 + 3) > gAdvIntMin_ms ? gAdvIntMin_ms : (gAdvIntMin_ms / 2 + 3);
#endif
CMD_DBG("Advertising times=%d\n", adv_times);
CMD_DBG("Advertising config: interval=0x%x channel=0x%x manu_type=0x%x\n",
interval, channel, manu_type);
g_task_end = 0;
while (!g_task_end) {
for (index = 1; index <= adv_times; index++) {
if (g_task_end)
break;
get_tick_adv_start();
adv_start(manu_type, index, channel);
OS_MSleep(delay);
adv_stop();
OS_MSleep(gAdvIntMin_ms - delay);
}
break;
}
CMD_DBG("Advertising end!\n");
exit:
g_task_end = 1;
ADV_DELETE_THREAD(g_adv_start_thread);
}
static enum cmd_status adv_start_task(char *arg)
{
char *cmd = (char *)arg;
ADV_CREAT_THREAD(g_adv_start_thread, adv_start_exec, cmd);
return CMD_STATUS_OK;
}
static enum cmd_status adv_stop_task(char *arg)
{
char *cmd = (char *)arg;
(void)cmd;
g_task_end = 1;
CMD_DBG("adv task end\n");
return CMD_STATUS_OK;
}
#if 0
static enum cmd_status adv_set_channel_exec(char *cmd)
{
int cnt;
uint32_t chl_map;
cnt = cmd_sscanf(cmd, "c=0x%x", &chl_map);
if (cnt != 1 || chl_map > 0x07) {
CMD_ERR("invalid arg\n");
return CMD_STATUS_FAIL;
}
if (g_task_end)
gAdvChlMap = chl_map;
return CMD_STATUS_OK;
}
static enum cmd_status adv_set_interval_exec(char *cmd)
{
int cnt;
uint32_t adv_min, adv_max;
cnt = cmd_sscanf(cmd, "min=0x%x max=0x%x", &adv_min, &adv_max);
if (cnt != 2) {
CMD_ERR("invalid arg\n");
return CMD_STATUS_FAIL;
}
if (g_task_end) {
gAdvIntMin = adv_min;
gAdvIntMax = adv_max;
}
return CMD_STATUS_OK;
}
static const struct cmd_data g_adv_set_cmds[] = {
{ "channel", adv_set_channel_exec },
{ "interval", adv_set_interval_exec },
};
static enum cmd_status cmd_set_exec(char *cmd)
{
return cmd_exec(cmd, g_adv_set_cmds, cmd_nitems(g_adv_set_cmds));
}
#endif
static const struct cmd_data g_adv_cmds[] = {
#if 0
{ "set", cmd_set_exec },
#endif
{ "start", adv_start_task },
{ "stop", adv_stop_task },
};
enum cmd_status cmd_adv_exec(char *cmd)
{
return cmd_exec(cmd, g_adv_cmds, cmd_nitems(g_adv_cmds));
}
#endif