client: Add type to write command

This enables setting the write type as optional third parameter:

write <data=xx xx ...> [offset] [type]

The type can be used to force a specific procedure to be used, for
example to force reliable writes one can enter:

> write 00 0 reliable
This commit is contained in:
Luiz Augusto von Dentz 2019-02-11 11:29:21 +02:00
parent aa9f9b193c
commit db15160d5c
2 changed files with 60 additions and 80 deletions

View File

@ -65,7 +65,7 @@ struct desc {
uint16_t handle;
char *uuid;
char **flags;
int value_len;
size_t value_len;
unsigned int max_val_len;
uint8_t *value;
};
@ -78,7 +78,7 @@ struct chrc {
char **flags;
bool notifying;
GList *descs;
int value_len;
size_t value_len;
unsigned int max_val_len;
uint8_t *value;
uint16_t mtu;
@ -669,7 +669,8 @@ static void write_reply(DBusMessage *message, void *user_data)
}
struct write_attribute_data {
struct iovec *iov;
struct iovec iov;
char *type;
uint16_t offset;
};
@ -680,8 +681,8 @@ static void write_setup(DBusMessageIter *iter, void *user_data)
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
&wd->iov->iov_base,
wd->iov->iov_len);
&wd->iov.iov_base,
wd->iov.iov_len);
dbus_message_iter_close_container(iter, &array);
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
@ -691,6 +692,10 @@ static void write_setup(DBusMessageIter *iter, void *user_data)
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&dict);
if (wd->type)
g_dbus_dict_append_entry(&dict, "type", DBUS_TYPE_STRING,
&wd->type);
g_dbus_dict_append_entry(&dict, "offset", DBUS_TYPE_UINT16,
&wd->offset);
@ -715,54 +720,23 @@ static int sock_send(struct io *io, struct iovec *iov, size_t iovlen)
return ret;
}
static void write_attribute(GDBusProxy *proxy, char *val_str, uint16_t offset)
static void write_attribute(GDBusProxy *proxy,
struct write_attribute_data *data)
{
struct iovec iov;
struct write_attribute_data wd;
uint8_t value[MAX_ATTR_VAL_LEN];
char *entry;
unsigned int i;
for (i = 0; (entry = strsep(&val_str, " \t")) != NULL; i++) {
long int val;
char *endptr = NULL;
if (*entry == '\0')
continue;
if (i >= G_N_ELEMENTS(value)) {
bt_shell_printf("Too much data\n");
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
val = strtol(entry, &endptr, 0);
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
bt_shell_printf("Invalid value at index %d\n", i);
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
value[i] = val;
}
iov.iov_base = value;
iov.iov_len = i;
/* Write using the fd if it has been acquired and fit the MTU */
if (proxy == write_io.proxy && (write_io.io && write_io.mtu >= i)) {
if (proxy == write_io.proxy &&
(write_io.io && write_io.mtu >= data->iov.iov_len)) {
bt_shell_printf("Attempting to write fd %d\n",
io_get_fd(write_io.io));
if (sock_send(write_io.io, &iov, 1) < 0) {
if (sock_send(write_io.io, &data->iov, 1) < 0) {
bt_shell_printf("Failed to write: %s", strerror(errno));
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
return;
}
wd.iov = &iov;
wd.offset = offset;
if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
write_reply, &wd, NULL) == FALSE) {
write_reply, data, NULL) == FALSE) {
bt_shell_printf("Failed to write\n");
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
@ -771,19 +745,57 @@ static void write_attribute(GDBusProxy *proxy, char *val_str, uint16_t offset)
g_dbus_proxy_get_path(proxy));
}
static uint8_t *str2bytearray(char *arg, size_t *val_len)
{
uint8_t value[MAX_ATTR_VAL_LEN];
char *entry;
unsigned int i;
for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
long int val;
char *endptr = NULL;
if (*entry == '\0')
continue;
if (i >= G_N_ELEMENTS(value)) {
bt_shell_printf("Too much data\n");
return NULL;
}
val = strtol(entry, &endptr, 0);
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
bt_shell_printf("Invalid value at index %d\n", i);
return NULL;
}
value[i] = val;
}
*val_len = i;
return g_memdup(value, i);
}
void gatt_write_attribute(GDBusProxy *proxy, int argc, char *argv[])
{
const char *iface;
uint16_t offset = 0;
struct write_attribute_data data;
memset(&data, 0, sizeof(data));
iface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(iface, "org.bluez.GattCharacteristic1") ||
!strcmp(iface, "org.bluez.GattDescriptor1")) {
data.iov.iov_base = str2bytearray(argv[1], &data.iov.iov_len);
if (argc > 2)
offset = atoi(argv[2]);
data.offset = atoi(argv[2]);
write_attribute(proxy, argv[1], offset);
if (argc > 3)
data.type = argv[3];
write_attribute(proxy, &data);
return;
}
@ -1952,8 +1964,8 @@ static int parse_value_arg(DBusMessageIter *iter, uint8_t **value, int *len)
return 0;
}
static int write_value(int *dst_len, uint8_t **dst_value, uint8_t *src_val,
int src_len, uint16_t offset, uint16_t max_len)
static int write_value(size_t *dst_len, uint8_t **dst_value, uint8_t *src_val,
size_t src_len, uint16_t offset, uint16_t max_len)
{
if ((offset + src_len) > max_len)
return -EOVERFLOW;
@ -2255,38 +2267,6 @@ static const GDBusMethodTable chrc_methods[] = {
{ }
};
static uint8_t *str2bytearray(char *arg, int *val_len)
{
uint8_t value[MAX_ATTR_VAL_LEN];
char *entry;
unsigned int i;
for (i = 0; (entry = strsep(&arg, " \t")) != NULL; i++) {
long int val;
char *endptr = NULL;
if (*entry == '\0')
continue;
if (i >= G_N_ELEMENTS(value)) {
bt_shell_printf("Too much data\n");
return NULL;
}
val = strtol(entry, &endptr, 0);
if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
bt_shell_printf("Invalid value at index %d\n", i);
return NULL;
}
value[i] = val;
}
*val_len = i;
return g_memdup(value, i);
}
static void chrc_set_value(const char *input, void *user_data)
{
struct chrc *chrc = user_data;

View File

@ -2612,7 +2612,7 @@ static const struct bt_shell_menu gatt_menu = {
{ "attribute-info", "[attribute/UUID]", cmd_attribute_info,
"Select attribute", attribute_generator },
{ "read", "[offset]", cmd_read, "Read attribute value" },
{ "write", "<data=xx xx ...> [offset]", cmd_write,
{ "write", "<data=xx xx ...> [offset] [type]", cmd_write,
"Write attribute value" },
{ "acquire-write", NULL, cmd_acquire_write,
"Acquire Write file descriptor" },