blob: b9e959f5687985d6f8cc1af6e48bb43e79c90e5e [file] [log] [blame]
/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(net_bt_shell, CONFIG_NET_L2_BT_LOG_LEVEL);
#include <kernel.h>
#include <toolchain.h>
#include <linker/sections.h>
#include <string.h>
#include <errno.h>
#include <shell/shell.h>
#include <shell/shell_uart.h>
#include <misc/printk.h>
#include <net/net_core.h>
#include <net/net_l2.h>
#include <net/net_if.h>
#include <net/bt.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
static int char2hex(const char *c, u8_t *x)
{
if (*c >= '0' && *c <= '9') {
*x = *c - '0';
} else if (*c >= 'a' && *c <= 'f') {
*x = *c - 'a' + 10;
} else if (*c >= 'A' && *c <= 'F') {
*x = *c - 'A' + 10;
} else {
return -EINVAL;
}
return 0;
}
static int str2bt_addr_le(const char *str, const char *type, bt_addr_le_t *addr)
{
int i, j;
u8_t tmp;
if (strlen(str) != 17) {
return -EINVAL;
}
for (i = 5, j = 1; *str != '\0'; str++, j++) {
if (!(j % 3) && (*str != ':')) {
return -EINVAL;
} else if (*str == ':') {
i--;
continue;
}
addr->a.val[i] = addr->a.val[i] << 4;
if (char2hex(str, &tmp) < 0) {
return -EINVAL;
}
addr->a.val[i] |= tmp;
}
if (!strcmp(type, "public") || !strcmp(type, "(public)")) {
addr->type = BT_ADDR_LE_PUBLIC;
} else if (!strcmp(type, "random") || !strcmp(type, "(random)")) {
addr->type = BT_ADDR_LE_RANDOM;
} else {
return -EINVAL;
}
return 0;
}
static int shell_cmd_connect(const struct shell *shell,
size_t argc, char *argv[])
{
int err;
bt_addr_le_t addr;
struct net_if *iface = net_if_get_default();
if (argc < 3) {
shell_help(shell);
return -ENOEXEC;
}
err = str2bt_addr_le(argv[1], argv[2], &addr);
if (err) {
shell_fprintf(shell, SHELL_WARNING,
"Invalid peer address (err %d)\n", err);
return 0;
}
if (net_mgmt(NET_REQUEST_BT_CONNECT, iface, &addr, sizeof(addr))) {
shell_fprintf(shell, SHELL_WARNING,
"Connection failed\n");
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Connection pending\n");
}
return 0;
}
static int shell_cmd_scan(const struct shell *shell,
size_t argc, char *argv[])
{
struct net_if *iface = net_if_get_default();
if (argc < 2) {
shell_help(shell);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_BT_SCAN, iface, argv[1], strlen(argv[1]))) {
shell_fprintf(shell, SHELL_WARNING,
"Scan failed\n");
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Scan in progress\n");
}
return 0;
}
static int shell_cmd_disconnect(const struct shell *shell,
size_t argc, char *argv[])
{
struct net_if *iface = net_if_get_default();
if (net_mgmt(NET_REQUEST_BT_DISCONNECT, iface, NULL, 0)) {
shell_fprintf(shell, SHELL_WARNING,
"Disconnect failed\n");
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Disconnected\n");
}
return 0;
}
static int shell_cmd_advertise(const struct shell *shell,
size_t argc, char *argv[])
{
struct net_if *iface = net_if_get_default();
if (argc < 2) {
shell_help(shell);
return -ENOEXEC;
}
if (net_mgmt(NET_REQUEST_BT_ADVERTISE, iface, argv[1],
strlen(argv[1]))) {
shell_fprintf(shell, SHELL_WARNING,
"Advertise failed\n");
} else {
shell_fprintf(shell, SHELL_NORMAL,
"Advertise in progress\n");
}
return 0;
}
SHELL_STATIC_SUBCMD_SET_CREATE(bt_commands,
SHELL_CMD(advertise, NULL,
"on/off",
shell_cmd_advertise),
SHELL_CMD(connect, NULL,
"<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>",
shell_cmd_connect),
SHELL_CMD(scan, NULL,
"<on/off/active/passive>",
shell_cmd_scan),
SHELL_CMD(disconnect, NULL,
"",
shell_cmd_disconnect),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_REGISTER(net_bt, &bt_commands, "Net Bluetooth commands", NULL);
void net_bt_shell_init(void)
{
}