extmod/modbluetooth: Make UUID support the buffer protocol.
Internally change the representation of UUIDs to LE uint8* to simplify this. This allows UUIDs to be easily used in BLE payloads (such as advertising). Ref: #5186
This commit is contained in:
parent
f1d91908fa
commit
56fc3edf98
@ -122,10 +122,11 @@ STATIC mp_obj_t bluetooth_uuid_make_new(const mp_obj_type_t *type, size_t n_args
|
|||||||
if (value > 65535) {
|
if (value > 65535) {
|
||||||
mp_raise_ValueError("invalid UUID");
|
mp_raise_ValueError("invalid UUID");
|
||||||
}
|
}
|
||||||
self->uuid._16 = value;
|
self->data[0] = value & 0xff;
|
||||||
|
self->data[1] = (value >> 8) & 0xff;
|
||||||
} else {
|
} else {
|
||||||
self->type = MP_BLUETOOTH_UUID_TYPE_128;
|
self->type = MP_BLUETOOTH_UUID_TYPE_128;
|
||||||
mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->uuid._128);
|
mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@ -135,41 +136,39 @@ STATIC mp_obj_t bluetooth_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
|||||||
mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case MP_UNARY_OP_HASH: {
|
case MP_UNARY_OP_HASH: {
|
||||||
if (self->type == MP_BLUETOOTH_UUID_TYPE_16) {
|
// Use the QSTR hash function.
|
||||||
return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._16));
|
return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->data, self->type));
|
||||||
|
|
||||||
} else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) {
|
|
||||||
return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._32));
|
|
||||||
|
|
||||||
} else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) {
|
|
||||||
return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->uuid._128, sizeof(self->uuid._128)));
|
|
||||||
}
|
|
||||||
return MP_OBJ_NULL;
|
|
||||||
}
|
}
|
||||||
default: return MP_OBJ_NULL; // op not supported
|
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) {
|
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_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
mp_printf(print, "UUID%u(%s", self->type * 8, self->type <= 4 ? "0x" : "'");
|
||||||
if (self->type == MP_BLUETOOTH_UUID_TYPE_16) {
|
for (int i = 0; i < self->type; ++i) {
|
||||||
mp_printf(print, "UUID16(0x%04x)", self->uuid._16);
|
if (i == 4 || i == 6 || i == 8 || i == 10) {
|
||||||
} else if (self->type == MP_BLUETOOTH_UUID_TYPE_32) {
|
|
||||||
mp_printf(print, "UUID32(0x%08x)", self->uuid._32);
|
|
||||||
} else if (self->type == MP_BLUETOOTH_UUID_TYPE_128) {
|
|
||||||
mp_printf(print, "UUID128('");
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
|
||||||
mp_printf(print, "%02x", self->uuid._128[15-i]);
|
|
||||||
if (i == 3 || i == 5 || i == 7 || i == 9) {
|
|
||||||
mp_printf(print, "-");
|
mp_printf(print, "-");
|
||||||
}
|
}
|
||||||
|
mp_printf(print, "%02x", self->data[self->type - 1 - i]);
|
||||||
}
|
}
|
||||||
mp_printf(print, "')");
|
if (self->type == MP_BLUETOOTH_UUID_TYPE_128) {
|
||||||
} else {
|
mp_printf(print, "'");
|
||||||
mp_printf(print, "UUID?(%d)", self->type);
|
|
||||||
}
|
}
|
||||||
|
mp_printf(print, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
|
||||||
|
mp_obj_bluetooth_uuid_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
|
||||||
|
if (flags != MP_BUFFER_READ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufinfo->buf = self->data;
|
||||||
|
bufinfo->len = self->type;
|
||||||
|
bufinfo->typecode = 'B';
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
@ -177,19 +176,8 @@ STATIC void bluetooth_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_p
|
|||||||
STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
||||||
assert(ringbuf_free(ringbuf) >= uuid->type + 1);
|
assert(ringbuf_free(ringbuf) >= uuid->type + 1);
|
||||||
ringbuf_put(ringbuf, uuid->type);
|
ringbuf_put(ringbuf, uuid->type);
|
||||||
switch (uuid->type) {
|
for (int i = 0; i < uuid->type; ++i) {
|
||||||
case MP_BLUETOOTH_UUID_TYPE_16:
|
ringbuf_put(ringbuf, uuid->data[i]);
|
||||||
ringbuf_put16(ringbuf, uuid->uuid._16);
|
|
||||||
break;
|
|
||||||
case MP_BLUETOOTH_UUID_TYPE_32:
|
|
||||||
ringbuf_put16(ringbuf, uuid->uuid._32 >> 16);
|
|
||||||
ringbuf_put16(ringbuf, uuid->uuid._32 & 0xffff);
|
|
||||||
break;
|
|
||||||
case MP_BLUETOOTH_UUID_TYPE_128:
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
|
||||||
ringbuf_put(ringbuf, uuid->uuid._128[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,21 +185,8 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid)
|
|||||||
assert(ringbuf_avail(ringbuf) >= 1);
|
assert(ringbuf_avail(ringbuf) >= 1);
|
||||||
uuid->type = ringbuf_get(ringbuf);
|
uuid->type = ringbuf_get(ringbuf);
|
||||||
assert(ringbuf_avail(ringbuf) >= uuid->type);
|
assert(ringbuf_avail(ringbuf) >= uuid->type);
|
||||||
uint16_t h, l;
|
for (int i = 0; i < uuid->type; ++i) {
|
||||||
switch (uuid->type) {
|
uuid->data[i] = ringbuf_get(ringbuf);
|
||||||
case MP_BLUETOOTH_UUID_TYPE_16:
|
|
||||||
uuid->uuid._16 = ringbuf_get16(ringbuf);
|
|
||||||
break;
|
|
||||||
case MP_BLUETOOTH_UUID_TYPE_32:
|
|
||||||
h = ringbuf_get16(ringbuf);
|
|
||||||
l = ringbuf_get16(ringbuf);
|
|
||||||
uuid->uuid._32 = (h << 16) | l;
|
|
||||||
break;
|
|
||||||
case MP_BLUETOOTH_UUID_TYPE_128:
|
|
||||||
for (int i = 0; i < 16; ++i) {
|
|
||||||
uuid->uuid._128[i] = ringbuf_get(ringbuf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
@ -223,6 +198,7 @@ STATIC const mp_obj_type_t bluetooth_uuid_type = {
|
|||||||
.unary_op = bluetooth_uuid_unary_op,
|
.unary_op = bluetooth_uuid_unary_op,
|
||||||
.locals_dict = NULL,
|
.locals_dict = NULL,
|
||||||
.print = bluetooth_uuid_print,
|
.print = bluetooth_uuid_print,
|
||||||
|
.buffer_p = { .get_buffer = bluetooth_uuid_get_buffer },
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -120,14 +120,14 @@ _IRQ_ALL = const(0xffff)
|
|||||||
|
|
||||||
// Common UUID type.
|
// Common UUID type.
|
||||||
// Ports are expected to map this to their own internal UUID types.
|
// Ports are expected to map this to their own internal UUID types.
|
||||||
|
// Internally the UUID data is little-endian, but the user should only
|
||||||
|
// ever see this if they use the buffer protocol, e.g. in order to
|
||||||
|
// construct an advertising payload (which needs to be in LE).
|
||||||
|
// Both the constructor and the print function work in BE.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
union {
|
uint8_t data[16];
|
||||||
uint16_t _16;
|
|
||||||
uint32_t _32;
|
|
||||||
uint8_t _128[16];
|
|
||||||
} uuid;
|
|
||||||
} mp_obj_bluetooth_uuid_t;
|
} mp_obj_bluetooth_uuid_t;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
@ -140,8 +140,10 @@ typedef struct {
|
|||||||
// Any method returning an int returns errno on failure, otherwise zero.
|
// Any method returning an int returns errno on failure, otherwise zero.
|
||||||
|
|
||||||
// Note: All methods dealing with addresses (as 6-byte uint8 pointers) are in big-endian format.
|
// Note: All methods dealing with addresses (as 6-byte uint8 pointers) are in big-endian format.
|
||||||
// (i.e. the same way they would be printed on a device sticker or in a UI).
|
// (i.e. the same way they would be printed on a device sticker or in a UI), so the user sees
|
||||||
// This means that the lower level implementation might need to reorder them (e.g. Nimble works in little-endian)
|
// addresses in a way that looks like what they'd expect.
|
||||||
|
// This means that the lower level implementation will likely need to reorder them (e.g. Nimble
|
||||||
|
// works in little-endian, as does BLE itself).
|
||||||
|
|
||||||
// Enables the Bluetooth stack.
|
// Enables the Bluetooth stack.
|
||||||
int mp_bluetooth_init(void);
|
int mp_bluetooth_init(void);
|
||||||
|
@ -87,21 +87,22 @@ STATIC int ble_hs_err_to_errno(int err) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: modbluetooth UUIDs store their data in LE.
|
||||||
STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) {
|
STATIC ble_uuid_t* create_nimble_uuid(const mp_obj_bluetooth_uuid_t *uuid) {
|
||||||
if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) {
|
if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) {
|
||||||
ble_uuid16_t *result = m_new(ble_uuid16_t, 1);
|
ble_uuid16_t *result = m_new(ble_uuid16_t, 1);
|
||||||
result->u.type = BLE_UUID_TYPE_16;
|
result->u.type = BLE_UUID_TYPE_16;
|
||||||
result->value = uuid->uuid._16;
|
result->value = (uuid->data[1] << 8) | uuid->data[0];
|
||||||
return (ble_uuid_t*)result;
|
return (ble_uuid_t*)result;
|
||||||
} else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_32) {
|
} else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_32) {
|
||||||
ble_uuid32_t *result = m_new(ble_uuid32_t, 1);
|
ble_uuid32_t *result = m_new(ble_uuid32_t, 1);
|
||||||
result->u.type = BLE_UUID_TYPE_32;
|
result->u.type = BLE_UUID_TYPE_32;
|
||||||
result->value = uuid->uuid._32;
|
result->value = (uuid->data[1] << 24) | (uuid->data[1] << 16) | (uuid->data[1] << 8) | uuid->data[0];
|
||||||
return (ble_uuid_t*)result;
|
return (ble_uuid_t*)result;
|
||||||
} else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_128) {
|
} else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_128) {
|
||||||
ble_uuid128_t *result = m_new(ble_uuid128_t, 1);
|
ble_uuid128_t *result = m_new(ble_uuid128_t, 1);
|
||||||
result->u.type = BLE_UUID_TYPE_128;
|
result->u.type = BLE_UUID_TYPE_128;
|
||||||
memcpy(result->value, uuid->uuid._128, 16);
|
memcpy(result->value, uuid->data, 16);
|
||||||
return (ble_uuid_t*)result;
|
return (ble_uuid_t*)result;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -115,15 +116,19 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) {
|
|||||||
switch (uuid->u.type) {
|
switch (uuid->u.type) {
|
||||||
case BLE_UUID_TYPE_16:
|
case BLE_UUID_TYPE_16:
|
||||||
result.type = MP_BLUETOOTH_UUID_TYPE_16;
|
result.type = MP_BLUETOOTH_UUID_TYPE_16;
|
||||||
result.uuid._16 = uuid->u16.value;
|
result.data[0] = uuid->u16.value & 0xff;
|
||||||
|
result.data[1] = (uuid->u16.value << 8) & 0xff;
|
||||||
break;
|
break;
|
||||||
case BLE_UUID_TYPE_32:
|
case BLE_UUID_TYPE_32:
|
||||||
result.type = MP_BLUETOOTH_UUID_TYPE_32;
|
result.type = MP_BLUETOOTH_UUID_TYPE_32;
|
||||||
result.uuid._32 = uuid->u32.value;
|
result.data[0] = uuid->u32.value & 0xff;
|
||||||
|
result.data[1] = (uuid->u32.value << 8) & 0xff;
|
||||||
|
result.data[2] = (uuid->u32.value << 16) & 0xff;
|
||||||
|
result.data[3] = (uuid->u32.value << 24) & 0xff;
|
||||||
break;
|
break;
|
||||||
case BLE_UUID_TYPE_128:
|
case BLE_UUID_TYPE_128:
|
||||||
result.type = MP_BLUETOOTH_UUID_TYPE_128;
|
result.type = MP_BLUETOOTH_UUID_TYPE_128;
|
||||||
memcpy(result.uuid._128, uuid->u128.value, 16);
|
memcpy(result.data, uuid->u128.value, 16);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -131,7 +136,7 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// modbluetooth (and the layers above it) work in BE addresses, Nimble works in LE.
|
// modbluetooth (and the layers above it) work in BE for addresses, Nimble works in LE.
|
||||||
STATIC void reverse_addr_byte_order(uint8_t *addr_out, const uint8_t *addr_in) {
|
STATIC void reverse_addr_byte_order(uint8_t *addr_out, const uint8_t *addr_in) {
|
||||||
for (int i = 0; i < 6; ++i) {
|
for (int i = 0; i < 6; ++i) {
|
||||||
addr_out[i] = addr_in[5-i];
|
addr_out[i] = addr_in[5-i];
|
||||||
|
Loading…
Reference in New Issue
Block a user