Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/zephyr/bluetooth/uuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -5249,6 +5249,18 @@ bool bt_uuid_create(struct bt_uuid *uuid, const uint8_t *data, uint8_t data_len)
*/
void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len);

/** @brief Convert string to Bluetooth UUID.
*
* Converts string to Bluetooth UUID.
* UUID can be in any format, 16-bit, 32-bit or 128-bit.
*
* @param str pointer to string to convert
* @param uuid pointer where to put converted UUID
*
* @return true if the string was valid and the UUID was successfully created.
*/
bool bt_str_to_uuid(const char *str, struct bt_uuid *uuid);

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion subsys/bluetooth/host/classic/shell/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

zephyr_library()
zephyr_library_sources(bredr.c)
zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM rfcomm.c)
zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM spp.c)
zephyr_library_sources_ifdef(CONFIG_BT_A2DP a2dp.c)
zephyr_library_sources_ifdef(CONFIG_BT_AVRCP avrcp.c)
if(CONFIG_BT_HFP_HF OR CONFIG_BT_HFP_AG)
Expand Down
253 changes: 253 additions & 0 deletions subsys/bluetooth/host/classic/shell/bredr.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,72 @@
#define SDP_CLIENT_USER_BUF_LEN 512
NET_BUF_POOL_FIXED_DEFINE(sdp_client_pool, CONFIG_BT_MAX_CONN, SDP_CLIENT_USER_BUF_LEN, 8, NULL);

#ifdef CONFIG_BT_RFCOMM
#define RFCOMM_DATA_MTU 48

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"),
};
#endif /* CONFIG_BT_RFCOMM */

static int cmd_auth_pincode(const struct shell *sh, size_t argc, char *argv[])
{
struct bt_conn *conn;
Expand Down Expand Up @@ -1511,6 +1577,178 @@
return -EINVAL;
}

#if defined(CONFIG_BT_RFCOMM)
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)
{
bt_shell_print("Incoming data dlc %p len %u", dlci, buf->len);
}

static void rfcomm_connected(struct bt_rfcomm_dlc *dlci)
{
bt_shell_print("Dlc %p connected", dlci);
}

static void rfcomm_disconnected(struct bt_rfcomm_dlc *dlci)
{
bt_shell_print("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_server *server,
struct bt_rfcomm_dlc **dlc)
{
bt_shell_print("Incoming RFCOMM conn %p", conn);

if (rfcomm_dlc.session) {
bt_shell_error("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 *sh, size_t argc, char *argv[])
{
int ret;

if (rfcomm_server.channel) {
shell_error(sh, "Already registered");
return -ENOEXEC;
}

rfcomm_server.channel = BT_RFCOMM_CHAN_SPP;

ret = bt_rfcomm_server_register(&rfcomm_server);
if (ret < 0) {
shell_error(sh, "Unable to register channel %x", ret);
rfcomm_server.channel = 0U;
return -ENOEXEC;
} else {
shell_print(sh, "RFCOMM channel %u registered",
rfcomm_server.channel);
bt_sdp_register_service(&spp_rec);
}

return 0;
}

static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t channel;
int err;

if (!default_conn) {
shell_error(sh, "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(sh, "Unable to connect to channel %d (err %u)",
channel, err);
} else {
shell_print(sh, "RFCOMM connection pending");
}

return err;
}

static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t buf_data[RFCOMM_DATA_MTU] = { [0 ... (RFCOMM_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(&data_tx_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(sh, "Unable to send: %d", -ret);
net_buf_unref(buf);
return -ENOEXEC;
}
}

return 0;
}

static int cmd_disconnect(const struct shell *sh, size_t argc, char *argv[])
{
int err;

Check warning on line 1705 in subsys/bluetooth/host/classic/shell/bredr.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

UNNECESSARY_ELSE

subsys/bluetooth/host/classic/shell/bredr.c:1705 else is not generally useful after a break or return

err = bt_rfcomm_dlc_disconnect(&rfcomm_dlc);
if (err) {
shell_error(sh, "Unable to disconnect: %u", -err);
}

return err;
}

static int cmd_send_rpn(const struct shell *sh, size_t argc, char *argv[])
{
int err;
struct bt_rfcomm_rpn rpn;

if (!rfcomm_dlc.session) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}

/* Initialize RPN with default values */
memset(&rpn, 0, sizeof(rpn));

/* Set default values for RPN parameters */
rpn.baud_rate = BT_RFCOMM_RPN_BAUD_RATE_9600;
rpn.line_settings = BT_RFCOMM_SET_LINE_SETTINGS(
BT_RFCOMM_RPN_DATA_BITS_8,
BT_RFCOMM_RPN_STOP_BITS_1,
BT_RFCOMM_RPN_PARITY_NONE);
rpn.flow_control = BT_RFCOMM_RPN_FLOW_NONE;
rpn.xon_char = BT_RFCOMM_RPN_XON_CHAR;
rpn.xoff_char = BT_RFCOMM_RPN_XOFF_CHAR;
rpn.param_mask = BT_RFCOMM_RPN_PARAM_MASK_ALL;

shell_print(sh, "Sending RFCOMM RPN command with default settings");

err = bt_rfcomm_send_rpn_cmd(&rfcomm_dlc, &rpn);
if (err < 0) {
shell_error(sh, "Unable to send RPN command: %d", err);
return -ENOEXEC;
}

shell_print(sh, "RFCOMM RPN command sent successfully");
return 0;
}
#endif /* CONFIG_BT_RFCOMM */

#define HELP_NONE "[none]"
#define HELP_ADDR "<address: XX:XX:XX:XX:XX:XX>"
#define HELP_REG \
Expand Down Expand Up @@ -1559,6 +1797,17 @@
SHELL_SUBCMD_SET_END
);

#if defined(CONFIG_BT_RFCOMM)
SHELL_STATIC_SUBCMD_SET_CREATE(rfcomm_cmds,
SHELL_CMD_ARG(register, NULL, HELP_NONE, cmd_register, 1, 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_CMD_ARG(rpn, NULL, "Send RPN command with default settings", cmd_send_rpn, 1, 0),
SHELL_SUBCMD_SET_END
);
#endif /* CONFIG_BT_RFCOMM */

SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds,
SHELL_CMD_ARG(auth-pincode, NULL, "<pincode>", cmd_auth_pincode, 2, 0),
SHELL_CMD_ARG(connect, NULL, "<address>", cmd_connect, 2, 0),
Expand All @@ -1571,6 +1820,10 @@
SHELL_CMD_ARG(iscan, NULL, "<value: on, off> [mode: limited]",
cmd_discoverable, 2, 1),
SHELL_CMD(l2cap, &l2cap_cmds, HELP_NONE, cmd_default_handler),
#if defined(CONFIG_BT_RFCOMM)
SHELL_CMD(rfcomm, &rfcomm_cmds, HELP_NONE, cmd_default_handler),
#endif /* CONFIG_BT_RFCOMM */
SHELL_CMD(rfcomm, &rfcomm_cmds, "Bluetooth RFCOMM shell commands", cmd_default_handler),
SHELL_CMD_ARG(oob, NULL, NULL, cmd_oob, 1, 0),
SHELL_CMD_ARG(pscan, NULL, "<value: on, off>", cmd_connectable, 2, 0),
SHELL_CMD_ARG(sdp-find, NULL, "<HFPAG, HFPHF, A2SRC, A2SNK, PNP>",
Expand Down
Loading
Loading