extmod/modbluetooth: Create UUID from bytes and allow comparison ops.

This allows construction of UUID objects from advertising data payloads and
matching against known UUIDs.
pull/1/head
Jim Mussared 2019-11-12 15:29:24 +11:00 committed by Damien George
parent 1530fda9cf
commit d19c6d0519
1 changed files with 60 additions and 33 deletions

View File

@ -79,37 +79,6 @@ STATIC mp_obj_t bluetooth_handle_errno(int err) {
// UUID object
// ----------------------------------------------------------------------------
// Parse string UUIDs, which are expected to be 128-bit UUIDs.
STATIC void mp_bluetooth_parse_uuid_128bit_str(mp_obj_t obj, uint8_t *uuid) {
size_t str_len;
const char *str_data = mp_obj_str_get_data(obj, &str_len);
int uuid_i = 32;
for (int i = 0; i < str_len; i++) {
char c = str_data[i];
if (c == '-') {
continue;
}
if (!unichar_isxdigit(c)) {
mp_raise_ValueError("invalid char in UUID");
}
c = unichar_xdigit_value(c);
uuid_i--;
if (uuid_i < 0) {
mp_raise_ValueError("UUID too long");
}
if (uuid_i % 2 == 0) {
// lower nibble
uuid[uuid_i/2] |= c;
} else {
// upper nibble
uuid[uuid_i/2] = c << 4;
}
}
if (uuid_i > 0) {
mp_raise_ValueError("UUID too short");
}
}
STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@ -125,8 +94,41 @@ STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args
self->data[0] = value & 0xff;
self->data[1] = (value >> 8) & 0xff;
} else {
self->type = MP_BLUETOOTH_UUID_TYPE_128;
mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->data);
mp_buffer_info_t uuid_bufinfo = {0};
mp_get_buffer_raise(all_args[0], &uuid_bufinfo, MP_BUFFER_READ);
if (uuid_bufinfo.len == 2 || uuid_bufinfo.len == 4 || uuid_bufinfo.len == 16) {
// Bytes data -- infer UUID type from length and copy data.
self->type = uuid_bufinfo.len;
memcpy(self->data, uuid_bufinfo.buf, self->type);
} else {
// Assume UUID string (e.g. '6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
self->type = MP_BLUETOOTH_UUID_TYPE_128;
int uuid_i = 32;
for (int i = 0; i < uuid_bufinfo.len; i++) {
char c = ((char*)uuid_bufinfo.buf)[i];
if (c == '-') {
continue;
}
if (!unichar_isxdigit(c)) {
mp_raise_ValueError("invalid char in UUID");
}
c = unichar_xdigit_value(c);
uuid_i--;
if (uuid_i < 0) {
mp_raise_ValueError("UUID too long");
}
if (uuid_i % 2 == 0) {
// lower nibble
self->data[uuid_i/2] |= c;
} else {
// upper nibble
self->data[uuid_i/2] = c << 4;
}
}
if (uuid_i > 0) {
mp_raise_ValueError("UUID too short");
}
}
}
return self;
@ -143,6 +145,30 @@ STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
STATIC mp_obj_t bluetooth_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
if (!mp_obj_is_type(rhs_in, &bluetooth_uuid_type)) {
return MP_OBJ_NULL;
}
mp_obj_bluetooth_uuid_t *lhs = MP_OBJ_TO_PTR(lhs_in);
mp_obj_bluetooth_uuid_t *rhs = MP_OBJ_TO_PTR(rhs_in);
switch (op) {
case MP_BINARY_OP_EQUAL:
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
if (lhs->type == rhs->type) {
return mp_obj_new_bool(mp_seq_cmp_bytes(op, lhs->data, lhs->type, rhs->data, rhs->type));
} else {
return mp_binary_op(op, MP_OBJ_NEW_SMALL_INT(lhs->type), MP_OBJ_NEW_SMALL_INT(rhs->type));
}
default:
return MP_OBJ_NULL; // op not supported
}
}
STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "UUID%u(%s", self->type * 8, self->type <= 4 ? "0x" : "'");
@ -196,6 +222,7 @@ STATIC const mp_obj_type_t bluetooth_uuid_type = {
.name = MP_QSTR_UUID,
.make_new = bluetooth_uuid_make_new,
.unary_op = bluetooth_uuid_unary_op,
.binary_op = bluetooth_uuid_binary_op,
.locals_dict = NULL,
.print = bluetooth_uuid_print,
.buffer_p = { .get_buffer = bluetooth_uuid_get_buffer },