zephyr/subsys/bluetooth/shell/rfcomm.c
Carlos Stuart 75f77db432 include: misc: util.h: Rename min/max to MIN/MAX
There are issues using lowercase min and max macros when compiling a C++
application with a third-party toolchain such as GNU ARM Embedded when
using some STL headers i.e. <chrono>.

This is because there are actual C++ functions called min and max
defined in some of the STL headers and these macros interfere with them.
By changing the macros to UPPERCASE, which is consistent with almost all
other pre-processor macros this naming conflict is avoided.

All files that use these macros have been updated.

Signed-off-by: Carlos Stuart <carlosstuart1970@gmail.com>
2019-02-14 22:16:03 -05:00

260 lines
5.5 KiB
C

/** @file
* @brief Bluetooth RFCOMM shell module
*
* Provide some Bluetooth shell commands that can be useful to applications.
*/
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <misc/byteorder.h>
#include <zephyr.h>
#include <settings/settings.h>
#include <bluetooth/hci.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sdp.h>
#include <shell/shell.h>
#include "bt.h"
#define DATA_MTU 48
NET_BUF_POOL_DEFINE(pool, 1, DATA_MTU, BT_BUF_USER_DATA_MIN, NULL);
static struct bt_sdp_attribute spp_attrs[] = {
BT_SDP_NEW_SERVICE,
BT_SDP_LIST(
BT_SDP_ATTR_SVCLASS_ID_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROTO_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
},
)
},
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM)
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
BT_SDP_ARRAY_8(BT_RFCOMM_CHAN_SPP)
},
)
},
)
),
BT_SDP_LIST(
BT_SDP_ATTR_PROFILE_DESC_LIST,
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
BT_SDP_DATA_ELEM_LIST(
{
BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
},
{
BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
BT_SDP_ARRAY_16(0x0102)
},
)
},
)
),
BT_SDP_SERVICE_NAME("Serial Port"),
};
static struct bt_sdp_record spp_rec = BT_SDP_RECORD(spp_attrs);
static void rfcomm_recv(struct bt_rfcomm_dlc *dlci, struct net_buf *buf)
{
shell_print(ctx_shell, "Incoming data dlc %p len %u", dlci, buf->len);
}
static void rfcomm_connected(struct bt_rfcomm_dlc *dlci)
{
shell_print(ctx_shell, "Dlc %p connected", dlci);
}
static void rfcomm_disconnected(struct bt_rfcomm_dlc *dlci)
{
shell_print(ctx_shell, "Dlc %p disconnected", dlci);
}
static struct bt_rfcomm_dlc_ops rfcomm_ops = {
.recv = rfcomm_recv,
.connected = rfcomm_connected,
.disconnected = rfcomm_disconnected,
};
static struct bt_rfcomm_dlc rfcomm_dlc = {
.ops = &rfcomm_ops,
.mtu = 30,
};
static int rfcomm_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc)
{
shell_print(ctx_shell, "Incoming RFCOMM conn %p", conn);
if (rfcomm_dlc.session) {
shell_error(ctx_shell, "No channels available");
return -ENOMEM;
}
*dlc = &rfcomm_dlc;
return 0;
}
struct bt_rfcomm_server rfcomm_server = {
.accept = &rfcomm_accept,
};
static int cmd_register(const struct shell *shell, size_t argc, char *argv[])
{
int ret;
if (rfcomm_server.channel) {
shell_error(shell, "Already registered");
return -ENOEXEC;
}
rfcomm_server.channel = BT_RFCOMM_CHAN_SPP;
ret = bt_rfcomm_server_register(&rfcomm_server);
if (ret < 0) {
shell_error(shell, "Unable to register channel %x", ret);
rfcomm_server.channel = 0;
return -ENOEXEC;
} else {
shell_print(shell, "RFCOMM channel %u registered",
rfcomm_server.channel);
bt_sdp_register_service(&spp_rec);
}
return 0;
}
static int cmd_connect(const struct shell *shell, size_t argc, char *argv[])
{
u8_t channel;
int err;
if (!default_conn) {
shell_error(shell, "Not connected");
return -ENOEXEC;
}
channel = strtoul(argv[1], NULL, 16);
err = bt_rfcomm_dlc_connect(default_conn, &rfcomm_dlc, channel);
if (err < 0) {
shell_error(shell, "Unable to connect to channel %d (err %u)",
channel, err);
} else {
shell_print(shell, "RFCOMM connection pending");
}
return err;
}
static int cmd_send(const struct shell *shell, size_t argc, char *argv[])
{
u8_t buf_data[DATA_MTU] = { [0 ... (DATA_MTU - 1)] = 0xff };
int ret, len, count = 1;
struct net_buf *buf;
if (argc > 1) {
count = strtoul(argv[1], NULL, 10);
}
while (count--) {
buf = bt_rfcomm_create_pdu(&pool);
/* Should reserve one byte in tail for FCS */
len = MIN(rfcomm_dlc.mtu, net_buf_tailroom(buf) - 1);
net_buf_add_mem(buf, buf_data, len);
ret = bt_rfcomm_dlc_send(&rfcomm_dlc, buf);
if (ret < 0) {
shell_error(shell, "Unable to send: %d", -ret);
net_buf_unref(buf);
return -ENOEXEC;
}
}
return 0;
}
static int cmd_disconnect(const struct shell *shell, size_t argc, char *argv[])
{
int err;
err = bt_rfcomm_dlc_disconnect(&rfcomm_dlc);
if (err) {
shell_error(shell, "Unable to disconnect: %u", -err);
}
return err;
}
#define HELP_NONE "[none]"
#define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
SHELL_CREATE_STATIC_SUBCMD_SET(rfcomm_cmds) {
SHELL_CMD_ARG(register, NULL, "<channel>", cmd_register, 2, 0),
SHELL_CMD_ARG(connect, NULL, "<channel>", cmd_connect, 2, 0),
SHELL_CMD_ARG(disconnect, NULL, HELP_NONE, cmd_disconnect, 1, 0),
SHELL_CMD_ARG(send, NULL, "<number of packets>", cmd_send, 2, 0),
SHELL_SUBCMD_SET_END
};
static int cmd_rfcomm(const struct shell *shell, size_t argc, char **argv)
{
if (argc == 1) {
shell_help(shell);
/* shell returns 1 when help is printed */
return 1;
}
shell_error(shell, "%s unknown parameter: %s", argv[0], argv[1]);
return -ENOEXEC;
}
SHELL_CMD_ARG_REGISTER(rfcomm, &rfcomm_cmds, "Bluetooth RFCOMM shell commands",
cmd_rfcomm, 1, 1);