blob: 6b143d08e6ab349cbbf45c8c02f488719bcbea62 [file] [log] [blame]
/** @file
* @brief Bluetooth GOEP shell module
*
* Provide some Bluetooth shell commands that can be useful to applications.
*/
/*
* Copyright 2024-2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/types.h>
#include <zephyr/sys/byteorder.h>
#include <stdlib.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/l2cap.h>
#include <zephyr/bluetooth/classic/rfcomm.h>
#include <zephyr/bluetooth/classic/sdp.h>
#include <zephyr/bluetooth/classic/goep.h>
#include <zephyr/shell/shell.h>
#include "host/shell/bt.h"
#include "common/bt_shell_private.h"
#define GOEP_MOPL CONFIG_BT_GOEP_RFCOMM_MTU
NET_BUF_POOL_FIXED_DEFINE(tx_pool, CONFIG_BT_MAX_CONN, BT_RFCOMM_BUF_SIZE(GOEP_MOPL),
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
static uint8_t add_head_buffer[GOEP_MOPL];
struct bt_goep_app {
struct bt_goep goep;
struct bt_obex_client client;
struct bt_obex_server server;
struct bt_conn *conn;
struct net_buf *tx_buf;
};
static struct bt_goep_app goep_app;
static struct bt_goep_transport_rfcomm_server rfcomm_server;
static struct bt_goep_transport_l2cap_server l2cap_server;
#define TLV_COUNT 3
#define TLV_BUFFER_SIZE 64
static struct bt_obex_tlv tlvs[TLV_COUNT];
static uint8_t tlv_buffers[TLV_COUNT][TLV_BUFFER_SIZE];
static uint8_t tlv_count;
static struct bt_goep_app *goep_alloc(struct bt_conn *conn)
{
if (goep_app.conn) {
return NULL;
}
goep_app.conn = conn;
return &goep_app;
}
static void goep_free(struct bt_goep_app *goep)
{
goep->conn = NULL;
}
static void goep_transport_connected(struct bt_conn *conn, struct bt_goep *goep)
{
bt_shell_print("GOEP %p transport connected on %p", goep, conn);
}
static void goep_transport_disconnected(struct bt_goep *goep)
{
struct bt_goep_app *g_app = CONTAINER_OF(goep, struct bt_goep_app, goep);
goep_free(g_app);
bt_shell_print("GOEP %p transport disconnected", goep);
}
struct bt_goep_transport_ops goep_transport_ops = {
.connected = goep_transport_connected,
.disconnected = goep_transport_disconnected,
};
static bool goep_parse_tlvs_cb(struct bt_obex_tlv *tlv, void *user_data)
{
bt_shell_print("T %02x L %d", tlv->type, tlv->data_len);
bt_shell_hexdump(tlv->data, tlv->data_len);
return true;
}
static bool goep_parse_headers_cb(struct bt_obex_hdr *hdr, void *user_data)
{
bt_shell_print("HI %02x Len %d", hdr->id, hdr->len);
switch (hdr->id) {
case BT_OBEX_HEADER_ID_APP_PARAM:
case BT_OBEX_HEADER_ID_AUTH_CHALLENGE:
case BT_OBEX_HEADER_ID_AUTH_RSP: {
int err;
err = bt_obex_tlv_parse(hdr->len, hdr->data, goep_parse_tlvs_cb, NULL);
if (err) {
bt_shell_error("Fail to parse OBEX TLV triplet");
}
} break;
default:
bt_shell_hexdump(hdr->data, hdr->len);
break;
}
return true;
}
static int goep_parse_headers(struct net_buf *buf)
{
int err;
if (!buf) {
return 0;
}
err = bt_obex_header_parse(buf, goep_parse_headers_cb, NULL);
if (err) {
bt_shell_print("Fail to parse OBEX Headers");
}
return err;
}
static void goep_server_connect(struct bt_obex_server *server, uint8_t version, uint16_t mopl,
struct net_buf *buf)
{
bt_shell_print("OBEX server %p conn req, version %02x, mopl %04x", server, version, mopl);
goep_parse_headers(buf);
}
static void goep_server_disconnect(struct bt_obex_server *server, struct net_buf *buf)
{
bt_shell_print("OBEX server %p disconn req", server);
goep_parse_headers(buf);
}
static void goep_server_put(struct bt_obex_server *server, bool final, struct net_buf *buf)
{
bt_shell_print("OBEX server %p put req, final %s, data len %d", server,
final ? "true" : "false", buf->len);
goep_parse_headers(buf);
}
static void goep_server_get(struct bt_obex_server *server, bool final, struct net_buf *buf)
{
bt_shell_print("OBEX server %p get req, final %s, data len %d", server,
final ? "true" : "false", buf->len);
goep_parse_headers(buf);
}
static void goep_server_abort(struct bt_obex_server *server, struct net_buf *buf)
{
bt_shell_print("OBEX server %p abort req", server);
goep_parse_headers(buf);
}
static void goep_server_setpath(struct bt_obex_server *server, uint8_t flags, struct net_buf *buf)
{
bt_shell_print("OBEX server %p setpath req, flags %02x, data len %d", server, flags,
buf->len);
goep_parse_headers(buf);
}
static void goep_server_action(struct bt_obex_server *server, bool final, struct net_buf *buf)
{
bt_shell_print("OBEX server %p action req, final %s, data len %d", server,
final ? "true" : "false", buf->len);
goep_parse_headers(buf);
}
struct bt_obex_server_ops goep_server_ops = {
.connect = goep_server_connect,
.disconnect = goep_server_disconnect,
.put = goep_server_put,
.get = goep_server_get,
.abort = goep_server_abort,
.setpath = goep_server_setpath,
.action = goep_server_action,
};
static void goep_client_connect(struct bt_obex_client *client, uint8_t rsp_code, uint8_t version,
uint16_t mopl, struct net_buf *buf)
{
bt_shell_print("OBEX client %p conn rsp, rsp_code %s, version %02x, mopl %04x", client,
bt_obex_rsp_code_to_str(rsp_code), version, mopl);
goep_parse_headers(buf);
}
static void goep_client_disconnect(struct bt_obex_client *client, uint8_t rsp_code,
struct net_buf *buf)
{
bt_shell_print("OBEX client %p disconn rsp, rsp_code %s", client,
bt_obex_rsp_code_to_str(rsp_code));
goep_parse_headers(buf);
}
static void goep_client_put(struct bt_obex_client *client, uint8_t rsp_code, struct net_buf *buf)
{
bt_shell_print("OBEX client %p put rsp, rsp_code %s, data len %d", client,
bt_obex_rsp_code_to_str(rsp_code), buf->len);
goep_parse_headers(buf);
}
static void goep_client_get(struct bt_obex_client *client, uint8_t rsp_code, struct net_buf *buf)
{
bt_shell_print("OBEX client %p get rsp, rsp_code %s, data len %d", client,
bt_obex_rsp_code_to_str(rsp_code), buf->len);
goep_parse_headers(buf);
}
static void goep_client_abort(struct bt_obex_client *client, uint8_t rsp_code,
struct net_buf *buf)
{
bt_shell_print("OBEX client %p abort rsp, rsp_code %s", client,
bt_obex_rsp_code_to_str(rsp_code));
goep_parse_headers(buf);
}
static void goep_client_setpath(struct bt_obex_client *client, uint8_t rsp_code,
struct net_buf *buf)
{
bt_shell_print("OBEX client %p setpath rsp, rsp_code %s", client,
bt_obex_rsp_code_to_str(rsp_code));
goep_parse_headers(buf);
}
static void goep_client_action(struct bt_obex_client *client, uint8_t rsp_code,
struct net_buf *buf)
{
bt_shell_print("OBEX client %p action rsp, rsp_code %s, data len %d", client,
bt_obex_rsp_code_to_str(rsp_code), buf->len);
goep_parse_headers(buf);
}
struct bt_obex_client_ops goep_client_ops = {
.connect = goep_client_connect,
.disconnect = goep_client_disconnect,
.put = goep_client_put,
.get = goep_client_get,
.abort = goep_client_abort,
.setpath = goep_client_setpath,
.action = goep_client_action,
};
static int rfcomm_accept(struct bt_conn *conn, struct bt_goep_transport_rfcomm_server *server,
struct bt_goep **goep)
{
struct bt_goep_app *g_app;
g_app = goep_alloc(conn);
if (!g_app) {
bt_shell_print("Cannot allocate goep instance");
return -ENOMEM;
}
g_app->goep.transport_ops = &goep_transport_ops;
*goep = &g_app->goep;
return 0;
}
static int cmd_register_rfcomm(const struct shell *sh, size_t argc, char *argv[])
{
int err;
uint8_t channel;
if (rfcomm_server.rfcomm.channel) {
shell_error(sh, "RFCOMM has been registered");
return -EBUSY;
}
channel = (uint8_t)strtoul(argv[1], NULL, 16);
rfcomm_server.rfcomm.channel = channel;
rfcomm_server.accept = rfcomm_accept;
err = bt_goep_transport_rfcomm_server_register(&rfcomm_server);
if (err) {
shell_error(sh, "Fail to register RFCOMM server (error %d)", err);
rfcomm_server.rfcomm.channel = 0;
return -ENOEXEC;
}
shell_print(sh, "RFCOMM server (channel %02x) is registered", rfcomm_server.rfcomm.channel);
return 0;
}
static int cmd_connect_rfcomm(const struct shell *sh, size_t argc, char *argv[])
{
int err;
struct bt_goep_app *g_app;
uint8_t channel;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
channel = (uint8_t)strtoul(argv[1], NULL, 16);
if (!channel) {
shell_error(sh, "Invalid channel");
return -ENOEXEC;
}
g_app = goep_alloc(default_conn);
if (!g_app) {
shell_error(sh, "Cannot allocate goep instance");
return -ENOMEM;
}
g_app->goep.transport_ops = &goep_transport_ops;
err = bt_goep_transport_rfcomm_connect(default_conn, &g_app->goep, channel);
if (err) {
goep_free(g_app);
shell_error(sh, "Fail to connect to channel %d (err %d)", channel, err);
} else {
shell_print(sh, "GOEP RFCOMM connection pending");
}
return err;
}
static int cmd_disconnect_rfcomm(const struct shell *sh, size_t argc, char *argv[])
{
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
err = bt_goep_transport_rfcomm_disconnect(&goep_app.goep);
if (err) {
shell_error(sh, "Fail to disconnect to channel (err %d)", err);
} else {
shell_print(sh, "GOEP RFCOMM disconnection pending");
}
return err;
}
static int l2cap_accept(struct bt_conn *conn, struct bt_goep_transport_l2cap_server *server,
struct bt_goep **goep)
{
struct bt_goep_app *g_app;
g_app = goep_alloc(conn);
if (!g_app) {
bt_shell_print("Cannot allocate goep instance");
return -ENOMEM;
}
g_app->goep.transport_ops = &goep_transport_ops;
*goep = &g_app->goep;
return 0;
}
static int cmd_register_l2cap(const struct shell *sh, size_t argc, char *argv[])
{
int err;
uint16_t psm;
if (l2cap_server.l2cap.psm) {
shell_error(sh, "L2CAP server has been registered");
return -EBUSY;
}
psm = (uint16_t)strtoul(argv[1], NULL, 16);
l2cap_server.l2cap.psm = psm;
l2cap_server.accept = l2cap_accept;
err = bt_goep_transport_l2cap_server_register(&l2cap_server);
if (err) {
shell_error(sh, "Fail to register L2CAP server (error %d)", err);
l2cap_server.l2cap.psm = 0;
return -ENOEXEC;
}
shell_print(sh, "L2CAP server (psm %04x) is registered", l2cap_server.l2cap.psm);
return 0;
}
static int cmd_connect_l2cap(const struct shell *sh, size_t argc, char *argv[])
{
int err;
struct bt_goep_app *g_app;
uint16_t psm;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
psm = (uint16_t)strtoul(argv[1], NULL, 16);
if (!psm) {
shell_error(sh, "Invalid psm");
return -ENOEXEC;
}
g_app = goep_alloc(default_conn);
if (!g_app) {
shell_error(sh, "Cannot allocate goep instance");
return -ENOMEM;
}
g_app->goep.transport_ops = &goep_transport_ops;
err = bt_goep_transport_l2cap_connect(default_conn, &g_app->goep, psm);
if (err) {
goep_free(g_app);
shell_error(sh, "Fail to connect to PSM %d (err %d)", psm, err);
} else {
shell_print(sh, "GOEP L2CAP connection pending");
}
return err;
}
static int cmd_disconnect_l2cap(const struct shell *sh, size_t argc, char *argv[])
{
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
err = bt_goep_transport_l2cap_disconnect(&goep_app.goep);
if (err) {
shell_error(sh, "Fail to disconnect L2CAP conn (err %d)", err);
} else {
shell_print(sh, "GOEP L2CAP disconnection pending");
}
return err;
}
static int cmd_add_header_count(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t count;
int err;
count = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_count(goep_app.tx_buf, count);
if (err) {
shell_error(sh, "Fail to add header count");
}
return err;
}
static int cmd_add_header_name(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload;
size_t hex_payload_size;
if (argc > 1) {
hex_payload = argv[1];
hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer,
sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
} else {
len = 0;
}
err = bt_obex_add_header_name(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header name");
}
return err;
}
static int cmd_add_header_type(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_type(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header type");
}
return err;
}
static int cmd_add_header_len(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t len;
int err;
len = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_len(goep_app.tx_buf, len);
if (err) {
shell_error(sh, "Fail to add header len");
}
return err;
}
static int cmd_add_header_time_iso_8601(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_time_iso_8601(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header time_iso_8601");
}
return err;
}
static int cmd_add_header_time(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t t;
int err;
t = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_time(goep_app.tx_buf, t);
if (err) {
shell_error(sh, "Fail to add header time");
}
return err;
}
static int cmd_add_header_description(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_description(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header description");
}
return err;
}
static int cmd_add_header_target(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_target(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header target");
}
return err;
}
static int cmd_add_header_http(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_http(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header http");
}
return err;
}
static int cmd_add_header_body(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_body(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header body");
}
return err;
}
static int cmd_add_header_end_body(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_end_body(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header end_body");
}
return err;
}
static int cmd_add_header_who(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_who(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header who");
}
return err;
}
static int cmd_add_header_conn_id(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t conn_id;
int err;
conn_id = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_conn_id(goep_app.tx_buf, conn_id);
if (err) {
shell_error(sh, "Fail to add header conn_id");
}
return err;
}
static int cmd_add_header_app_param(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
uint8_t tag;
bool last = false;
if (tlv_count >= (uint8_t)ARRAY_SIZE(tlvs)) {
shell_warn(sh, "No space of TLV array, add app_param and clear tlvs");
goto add_header;
}
len = hex2bin(argv[1], strlen(argv[1]), &tag, sizeof(tag));
if (len < 1) {
shell_error(sh, "Length should not be zero");
return -ENOEXEC;
}
len = hex2bin(argv[2], strlen(argv[2]), &tlv_buffers[tlv_count][0], TLV_BUFFER_SIZE);
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
if ((argc > 3) && !strcmp(argv[3], "last")) {
last = true;
}
tlvs[tlv_count].type = tag;
tlvs[tlv_count].data_len = len;
tlvs[tlv_count].data = &tlv_buffers[tlv_count][0];
tlv_count++;
if (!last) {
return 0;
}
add_header:
err = bt_obex_add_header_app_param(goep_app.tx_buf, (size_t)tlv_count, tlvs);
if (err) {
shell_error(sh, "Fail to add header app_param");
}
tlv_count = 0;
return err;
}
static int cmd_add_header_auth_challenge(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
uint8_t tag;
bool last = false;
if (tlv_count >= (uint8_t)ARRAY_SIZE(tlvs)) {
shell_warn(sh, "No space of TLV array, add auth_challenge and clear tlvs");
goto add_header;
}
len = hex2bin(argv[1], strlen(argv[1]), &tag, sizeof(tag));
if (len < 1) {
shell_error(sh, "Length should not be zero");
return -ENOEXEC;
}
len = hex2bin(argv[2], strlen(argv[2]), &tlv_buffers[tlv_count][0], TLV_BUFFER_SIZE);
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
if ((argc > 3) && !strcmp(argv[3], "last")) {
last = true;
}
tlvs[tlv_count].type = tag;
tlvs[tlv_count].data_len = len;
tlvs[tlv_count].data = &tlv_buffers[tlv_count][0];
tlv_count++;
if (!last) {
return 0;
}
add_header:
err = bt_obex_add_header_auth_challenge(goep_app.tx_buf, (size_t)tlv_count, tlvs);
if (err) {
shell_error(sh, "Fail to add header auth_challenge");
}
tlv_count = 0;
return err;
}
static int cmd_add_header_auth_rsp(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
uint8_t tag;
bool last = false;
if (tlv_count >= (uint8_t)ARRAY_SIZE(tlvs)) {
shell_warn(sh, "No space of TLV array, add auth_rsp and clear tlvs");
goto add_header;
}
len = hex2bin(argv[1], strlen(argv[1]), &tag, sizeof(tag));
if (len < 1) {
shell_error(sh, "Length should not be zero");
return -ENOEXEC;
}
len = hex2bin(argv[2], strlen(argv[2]), &tlv_buffers[tlv_count][0], TLV_BUFFER_SIZE);
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
if ((argc > 3) && !strcmp(argv[3], "last")) {
last = true;
}
tlvs[tlv_count].type = tag;
tlvs[tlv_count].data_len = len;
tlvs[tlv_count].data = &tlv_buffers[tlv_count][0];
tlv_count++;
if (!last) {
return 0;
}
add_header:
err = bt_obex_add_header_auth_rsp(goep_app.tx_buf, (size_t)tlv_count, tlvs);
if (err) {
shell_error(sh, "Fail to add header auth_rsp");
}
tlv_count = 0;
return err;
}
static int cmd_add_header_creator_id(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t creator_id;
int err;
creator_id = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_creator_id(goep_app.tx_buf, creator_id);
if (err) {
shell_error(sh, "Fail to add header creator_id");
}
return err;
}
static int cmd_add_header_wan_uuid(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_wan_uuid(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header wan_uuid");
}
return err;
}
static int cmd_add_header_obj_class(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_obj_class(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header obj_class");
}
return err;
}
static int cmd_add_header_session_param(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_session_param(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header session_param");
}
return err;
}
static int cmd_add_header_session_seq_number(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t session_seq_number;
int err;
session_seq_number = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_session_seq_number(goep_app.tx_buf, session_seq_number);
if (err) {
shell_error(sh, "Fail to add header session_seq_number");
}
return err;
}
static int cmd_add_header_action_id(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t action_id;
int err;
action_id = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_action_id(goep_app.tx_buf, action_id);
if (err) {
shell_error(sh, "Fail to add header action_id");
}
return err;
}
static int cmd_add_header_dest_name(const struct shell *sh, size_t argc, char *argv[])
{
size_t len;
int err;
const char *hex_payload = argv[1];
size_t hex_payload_size = strlen(hex_payload);
len = hex2bin(hex_payload, hex_payload_size, add_head_buffer, sizeof(add_head_buffer));
if (len > UINT16_MAX) {
shell_error(sh, "Length exceeds max length (%x > %x)", len, UINT16_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_dest_name(goep_app.tx_buf, (uint16_t)len, add_head_buffer);
if (err) {
shell_error(sh, "Fail to add header dest_name");
}
return err;
}
static int cmd_add_header_perm(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t perm;
int err;
perm = strtoul(argv[1], NULL, 16);
err = bt_obex_add_header_perm(goep_app.tx_buf, perm);
if (err) {
shell_error(sh, "Fail to add header perm");
}
return err;
}
static int cmd_add_header_srm(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t srm;
int err;
srm = strtoul(argv[1], NULL, 16);
if (srm > UINT8_MAX) {
shell_error(sh, "Value exceeds max value (%x > %x)", srm, UINT8_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_srm(goep_app.tx_buf, (uint8_t)srm);
if (err) {
shell_error(sh, "Fail to add header srm");
}
return err;
}
static int cmd_add_header_srm_param(const struct shell *sh, size_t argc, char *argv[])
{
uint32_t srm_param;
int err;
srm_param = strtoul(argv[1], NULL, 16);
if (srm_param > UINT8_MAX) {
shell_error(sh, "Value exceeds max value (%x > %x)", srm_param, UINT8_MAX);
return -ENOEXEC;
}
err = bt_obex_add_header_srm_param(goep_app.tx_buf, (uint8_t)srm_param);
if (err) {
shell_error(sh, "Fail to add header srm_param");
}
return err;
}
static int cmd_goep_client_conn(const struct shell *sh, size_t argc, char *argv[])
{
uint16_t mopl;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
mopl = (uint16_t)strtoul(argv[1], NULL, 16);
goep_app.client.ops = &goep_client_ops;
goep_app.client.obex = &goep_app.goep.obex;
err = bt_obex_connect(&goep_app.client, mopl, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send conn req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_disconn(const struct shell *sh, size_t argc, char *argv[])
{
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
err = bt_obex_disconnect(&goep_app.client, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send disconn req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_put(const struct shell *sh, size_t argc, char *argv[])
{
bool final;
int err = 0;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
final = shell_strtobool(argv[1], 0, &err);
if (err != 0) {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_put(&goep_app.client, final, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send put req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_get(const struct shell *sh, size_t argc, char *argv[])
{
bool final;
int err = 0;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
final = shell_strtobool(argv[1], 0, &err);
if (err != 0) {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_get(&goep_app.client, final, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send get req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_abort(const struct shell *sh, size_t argc, char *argv[])
{
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
err = bt_obex_abort(&goep_app.client, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send abort req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_setpath(const struct shell *sh, size_t argc, char *argv[])
{
int err;
uint8_t flags = BIT(1);
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
for (size_t index = 1; index < argc; index++) {
if (!strcmp(argv[index], "parent")) {
flags |= BIT(0);
} else if (!strcmp(argv[index], "create")) {
flags &= ~BIT(1);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
}
err = bt_obex_setpath(&goep_app.client, flags, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send setpath req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_client_action(const struct shell *sh, size_t argc, char *argv[])
{
bool final;
int err = 0;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
final = shell_strtobool(argv[1], 0, &err);
if (err != 0) {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_action(&goep_app.client, final, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send action req %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_reg(const struct shell *sh, size_t argc, char *argv[])
{
int err;
uint8_t uuid128[BT_UUID_SIZE_128];
struct bt_uuid_128 *u = NULL;
static struct bt_uuid_128 uuid;
if (argc > 1) {
hex2bin(argv[1], strlen(argv[1]), uuid128, sizeof(uuid128));
uuid.uuid.type = BT_UUID_TYPE_128;
sys_memcpy_swap(uuid.val, uuid128, BT_UUID_SIZE_128);
u = &uuid;
}
goep_app.server.ops = &goep_server_ops;
goep_app.server.obex = &goep_app.goep.obex;
err = bt_obex_server_register(&goep_app.server, u);
if (err != 0) {
shell_error(sh, "Fail to register obex server %d", err);
}
return err;
}
static int cmd_goep_server_unreg(const struct shell *sh, size_t argc, char *argv[])
{
int err;
err = bt_obex_server_unregister(&goep_app.server);
if (err != 0) {
shell_error(sh, "Fail to unregister obex server %d", err);
}
return err;
}
static int cmd_goep_server_conn(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
uint16_t mopl;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 4) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[3], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
mopl = (uint16_t)strtoul(argv[2], NULL, 16);
err = bt_obex_connect_rsp(&goep_app.server, rsp_code, mopl, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send conn rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_disconn(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_disconnect_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send disconn rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_put(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_put_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send put rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_get(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_get_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send get rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_abort(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_abort_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send abort rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_setpath(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_setpath_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send setpath rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
static int cmd_goep_server_action(const struct shell *sh, size_t argc, char *argv[])
{
uint8_t rsp_code;
const char *rsp;
int err;
if (!default_conn) {
shell_error(sh, "Not connected");
return -ENOEXEC;
}
if (!goep_app.conn) {
shell_error(sh, "No goep transport connection");
return -ENOEXEC;
}
rsp = argv[1];
if (!strcmp(rsp, "continue")) {
rsp_code = BT_OBEX_RSP_CODE_CONTINUE;
} else if (!strcmp(rsp, "success")) {
rsp_code = BT_OBEX_RSP_CODE_SUCCESS;
} else if (!strcmp(rsp, "error")) {
if (argc < 3) {
shell_error(sh, "[rsp_code] is needed if the rsp is %s", rsp);
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
rsp_code = (uint8_t)strtoul(argv[2], NULL, 16);
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
err = bt_obex_action_rsp(&goep_app.server, rsp_code, goep_app.tx_buf);
if (err) {
shell_error(sh, "Fail to send action rsp %d", err);
} else {
goep_app.tx_buf = NULL;
}
return err;
}
#define HELP_NONE ""
SHELL_STATIC_SUBCMD_SET_CREATE(obex_add_header_cmds,
SHELL_CMD_ARG(count, NULL, "<number of objects (used by Connect)>", cmd_add_header_count, 2,
0),
SHELL_CMD_ARG(name, NULL, "[name of the object (often a file name)]", cmd_add_header_name,
1, 1),
SHELL_CMD_ARG(type, NULL,
"<type of object - e.g. text, html, binary, manufacturer specific>",
cmd_add_header_type, 2, 0),
SHELL_CMD_ARG(len, NULL, "<length of the object in bytes>", cmd_add_header_len, 2, 0),
SHELL_CMD_ARG(time_iso_8601, NULL, "<date/time stamp - ISO 8601 version - preferred>",
cmd_add_header_time_iso_8601, 2, 0),
SHELL_CMD_ARG(time, NULL, "<date/time stamp - 4 byte version (for compatibility only)>",
cmd_add_header_time, 2, 0),
SHELL_CMD_ARG(description, NULL, "<text description of the object>",
cmd_add_header_description, 2, 0),
SHELL_CMD_ARG(target, NULL, "<name of service that operation is targeted to>",
cmd_add_header_target, 2, 0),
SHELL_CMD_ARG(http, NULL, "<an HTTP 1.x header>", cmd_add_header_http, 2, 0),
SHELL_CMD_ARG(body, NULL, "<a chunk of the object body>", cmd_add_header_body, 2, 0),
SHELL_CMD_ARG(end_body, NULL, "<the final chunk of the object body>",
cmd_add_header_end_body, 2, 0),
SHELL_CMD_ARG(who, NULL,
"<identifies the OBEX application, used to tell if talking to a peer>",
cmd_add_header_who, 2, 0),
SHELL_CMD_ARG(conn_id, NULL, "<an identifier used for OBEX connection multiplexing>",
cmd_add_header_conn_id, 2, 0),
SHELL_CMD_ARG(app_param, NULL, "application parameter: <tag> <value> [last]",
cmd_add_header_app_param, 3, 1),
SHELL_CMD_ARG(auth_challenge, NULL, "authentication digest-challenge: <tag> <value> [last]",
cmd_add_header_auth_challenge, 3, 1),
SHELL_CMD_ARG(auth_rsp, NULL, "authentication digest-response: <tag> <value> [last]",
cmd_add_header_auth_rsp, 3, 1),
SHELL_CMD_ARG(creator_id, NULL, "<indicates the creator of an object>",
cmd_add_header_creator_id, 2, 0),
SHELL_CMD_ARG(wan_uuid, NULL, "<uniquely identifies the network client (OBEX server)>",
cmd_add_header_wan_uuid, 2, 0),
SHELL_CMD_ARG(obj_class, NULL, "<OBEX Object class of object>", cmd_add_header_obj_class, 2,
0),
SHELL_CMD_ARG(session_param, NULL, "<parameters used in session commands/responses>",
cmd_add_header_session_param, 2, 0),
SHELL_CMD_ARG(session_seq_number, NULL,
"<sequence number used in each OBEX packet for reliability>",
cmd_add_header_session_seq_number, 2, 0),
SHELL_CMD_ARG(action_id, NULL,
"<specifies the action to be performed (used in ACTION operation)>",
cmd_add_header_action_id, 2, 0),
SHELL_CMD_ARG(dest_name, NULL,
"<the destination object name (used in certain ACTION operations)>",
cmd_add_header_dest_name, 2, 0),
SHELL_CMD_ARG(perm, NULL, "<4-byte bit mask for setting permissions>", cmd_add_header_perm,
2, 0),
SHELL_CMD_ARG(srm, NULL, "<1-byte value to setup Single Response Mode (SRM)>",
cmd_add_header_srm, 2, 0),
SHELL_CMD_ARG(srm_param, NULL, "<Single Response Mode (SRM) Parameter>",
cmd_add_header_srm_param, 2, 0),
SHELL_SUBCMD_SET_END
);
SHELL_STATIC_SUBCMD_SET_CREATE(obex_client_cmds,
SHELL_CMD_ARG(conn, NULL, "<mopl>", cmd_goep_client_conn, 2, 0),
SHELL_CMD_ARG(disconn, NULL, HELP_NONE, cmd_goep_client_disconn, 1, 0),
SHELL_CMD_ARG(put, NULL, "<final: true, false>", cmd_goep_client_put, 2, 0),
SHELL_CMD_ARG(get, NULL, "<final: true, false>", cmd_goep_client_get, 2, 0),
SHELL_CMD_ARG(abort, NULL, HELP_NONE, cmd_goep_client_abort, 1, 0),
SHELL_CMD_ARG(setpath, NULL, "[parent] [create]", cmd_goep_client_setpath, 1, 2),
SHELL_CMD_ARG(action, NULL, "<final: true, false>", cmd_goep_client_action, 2, 0),
SHELL_SUBCMD_SET_END
);
SHELL_STATIC_SUBCMD_SET_CREATE(obex_server_cmds,
SHELL_CMD_ARG(reg, NULL, "[UUID 128]", cmd_goep_server_reg, 1, 1),
SHELL_CMD_ARG(unreg, NULL, HELP_NONE, cmd_goep_server_unreg, 1, 0),
SHELL_CMD_ARG(conn, NULL, "<rsp: continue, success, error> <mopl> [rsp_code]",
cmd_goep_server_conn, 3, 1),
SHELL_CMD_ARG(disconn, NULL, "<rsp: continue, success, error> [rsp_code]",
cmd_goep_server_disconn, 2, 1),
SHELL_CMD_ARG(put, NULL, "<rsp: continue, success, error> [rsp_code]", cmd_goep_server_put,
2, 1),
SHELL_CMD_ARG(get, NULL, "<rsp: continue, success, error> [rsp_code]", cmd_goep_server_get,
2, 1),
SHELL_CMD_ARG(abort, NULL, "<rsp: continue, success, error> [rsp_code]",
cmd_goep_server_abort, 2, 1),
SHELL_CMD_ARG(setpath, NULL, "<rsp: continue, success, error> [rsp_code]",
cmd_goep_server_setpath, 2, 1),
SHELL_CMD_ARG(action, NULL, "<rsp: continue, success, error> [rsp_code]",
cmd_goep_server_action, 2, 1),
SHELL_SUBCMD_SET_END
);
static int cmd_alloc_buf(const struct shell *sh, size_t argc, char **argv)
{
if (goep_app.tx_buf) {
shell_error(sh, "Buf %p is using", goep_app.tx_buf);
return -EBUSY;
}
goep_app.tx_buf = bt_goep_create_pdu(&goep_app.goep, &tx_pool);
if (!goep_app.tx_buf) {
shell_error(sh, "Fail to allocate tx buffer");
return -ENOBUFS;
}
return 0;
}
static int cmd_release_buf(const struct shell *sh, size_t argc, char **argv)
{
if (!goep_app.tx_buf) {
shell_error(sh, "No buf is using");
return -EINVAL;
}
net_buf_unref(goep_app.tx_buf);
goep_app.tx_buf = NULL;
return 0;
}
static int cmd_common(const struct shell *sh, size_t argc, char **argv)
{
if (argc == 1) {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
return -ENOEXEC;
}
SHELL_STATIC_SUBCMD_SET_CREATE(goep_cmds,
SHELL_CMD_ARG(register-rfcomm, NULL, "<channel>", cmd_register_rfcomm, 2, 0),
SHELL_CMD_ARG(connect-rfcomm, NULL, "<channel>", cmd_connect_rfcomm, 2, 0),
SHELL_CMD_ARG(disconnect-rfcomm, NULL, HELP_NONE, cmd_disconnect_rfcomm, 1, 0),
SHELL_CMD_ARG(register-l2cap, NULL, "<psm>", cmd_register_l2cap, 2, 0),
SHELL_CMD_ARG(connect-l2cap, NULL, "<psm>", cmd_connect_l2cap, 2, 0),
SHELL_CMD_ARG(disconnect-l2cap, NULL, HELP_NONE, cmd_disconnect_l2cap, 1, 0),
SHELL_CMD_ARG(alloc-buf, NULL, "Alloc tx buffer", cmd_alloc_buf, 1, 0),
SHELL_CMD_ARG(release-buf, NULL, "Free allocated tx buffer", cmd_release_buf, 1, 0),
SHELL_CMD_ARG(add-header, &obex_add_header_cmds, "Adding header sets", cmd_common, 1, 0),
SHELL_CMD_ARG(client, &obex_client_cmds, "Client sets", cmd_common, 1, 0),
SHELL_CMD_ARG(server, &obex_server_cmds, "Server sets", cmd_common, 1, 0),
SHELL_SUBCMD_SET_END
);
SHELL_CMD_ARG_REGISTER(goep, &goep_cmds, "Bluetooth GOEP shell commands", cmd_common, 1, 1);