Skip to content

Commit

Permalink
Merge pull request IanHarvey#169 from OnBeep/support-empty-wr-value
Browse files Browse the repository at this point in the history
Support empty values in "wr" and "wrr" commands IanHarvey#169

The GATT protocol supports empty values (length=0) for variable length characteristics, and some devices require empty values in some circumstances.

Trying to set an empty value to a GATT characteristic with code like

    handle.write(bytes(''))

results in failure, with the following output when I set `Debugging = True` in `btle.py`:

    Sent:  wr 95

    Got: 'rsp=$err code=$badparam\n'

With this PR, the `handle.write(bytes(''))` succeeds with the expected behavior on the airwaves and on the GATT server.

* 'support-empty-wr-value' of https://github.com/OnBeep/bluepy:
  bluepy-helper: document "wr" and "wrr" optional quotes
  bluepy-helper: support unquoted hex strings, too
  bluepy-helper: teach "wr" and "wrr" commands to take quoted data strings
  bluepy-helper: have gatt_attr_data_from_string return -1 on error rather than 0
  • Loading branch information
mickiebyrd committed Dec 4, 2017
2 parents 5c84171 + 4425051 commit ead0017
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 8 deletions.
6 changes: 3 additions & 3 deletions bluepy/bluepy-helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ static void cmd_char_write_common(int argcp, char **argvp, int with_response)
}

plen = gatt_attr_data_from_string(argvp[2], &value);
if (plen == 0) {
if (plen == (size_t)-1) {
resp_error(err_BAD_PARAM);
return;
}
Expand Down Expand Up @@ -1665,9 +1665,9 @@ static struct {
"Characteristics Value/Descriptor Read by handle" },
{ "rdu", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
"Characteristics Value/Descriptor Read by UUID" },
{ "wrr", cmd_char_write_rsp, "<handle> <new value>",
{ "wrr", cmd_char_write_rsp, "<handle> [<new value>|'<new value>']",
"Characteristic Value Write (Write Request)" },
{ "wr", cmd_char_write, "<handle> <new value>",
{ "wr", cmd_char_write, "<handle> [<new value>|'<new value>']",
"Characteristic Value Write (No response)" },
{ "secu", cmd_sec_level, "[low | medium | high]",
"Set security level. Default: low" },
Expand Down
2 changes: 1 addition & 1 deletion bluepy/btle.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ def writeCharacteristic(self, handle, val, withResponse=False):
# Without response, a value too long for one packet will be truncated,
# but with response, it will be sent as a queued write
cmd = "wrr" if withResponse else "wr"
self._writeCmd("%s %X %s\n" % (cmd, handle, binascii.b2a_hex(val).decode('utf-8')))
self._writeCmd("%s %X '%s'\n" % (cmd, handle, binascii.b2a_hex(val).decode('utf-8')))
return self._getResp('wr')

def setSecurityLevel(self, level):
Expand Down
22 changes: 18 additions & 4 deletions bluez-5.47/attrib/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,26 @@ GIOChannel *gatt_connect(const char *src, const char *dst,
size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
{
char tmp[3];
size_t size, i;
size_t size, len, i;
int is_quoted = 0;

size = strlen(str) / 2;
*data = g_try_malloc0(size);
if (str[0] == '\'')
is_quoted = 1;

len = strlen(str);

if (is_quoted) {
if (str[len - 1] != '\'')
return (size_t)-1;

str = str + 1;
len = len - 2;
}

size = len / 2;
*data = g_try_malloc0(len == 0 ? 1 : size);
if (*data == NULL)
return 0;
return (size_t)-1;

tmp[2] = '\0';
for (i = 0; i < size; i++) {
Expand Down

0 comments on commit ead0017

Please sign in to comment.