diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 3c00d5c1b..1b9888844 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -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) { mp_raise_ValueError("invalid UUID"); } - self->uuid._16 = value; + 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->uuid._128); + mp_bluetooth_parse_uuid_128bit_str(all_args[0], self->data); } 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); switch (op) { case MP_UNARY_OP_HASH: { - if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { - return mp_unary_op(MP_UNARY_OP_HASH, MP_OBJ_NEW_SMALL_INT(self->uuid._16)); - - } 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; + // Use the QSTR hash function. + return MP_OBJ_NEW_SMALL_INT(qstr_compute_hash(self->data, self->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); - - if (self->type == MP_BLUETOOTH_UUID_TYPE_16) { - mp_printf(print, "UUID16(0x%04x)", self->uuid._16); - } 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, "UUID%u(%s", self->type * 8, self->type <= 4 ? "0x" : "'"); + for (int i = 0; i < self->type; ++i) { + if (i == 4 || i == 6 || i == 8 || i == 10) { + mp_printf(print, "-"); } - mp_printf(print, "')"); - } else { - mp_printf(print, "UUID?(%d)", self->type); + mp_printf(print, "%02x", self->data[self->type - 1 - i]); } + if (self->type == MP_BLUETOOTH_UUID_TYPE_128) { + mp_printf(print, "'"); + } + 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 @@ -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) { assert(ringbuf_free(ringbuf) >= uuid->type + 1); ringbuf_put(ringbuf, uuid->type); - switch (uuid->type) { - case MP_BLUETOOTH_UUID_TYPE_16: - 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; + for (int i = 0; i < uuid->type; ++i) { + ringbuf_put(ringbuf, uuid->data[i]); } } @@ -197,21 +185,8 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) assert(ringbuf_avail(ringbuf) >= 1); uuid->type = ringbuf_get(ringbuf); assert(ringbuf_avail(ringbuf) >= uuid->type); - uint16_t h, l; - switch (uuid->type) { - 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; + for (int i = 0; i < uuid->type; ++i) { + uuid->data[i] = ringbuf_get(ringbuf); } } #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, .locals_dict = NULL, .print = bluetooth_uuid_print, + .buffer_p = { .get_buffer = bluetooth_uuid_get_buffer }, }; // ---------------------------------------------------------------------------- diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index f7284a43e..e99641e8f 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -120,14 +120,14 @@ _IRQ_ALL = const(0xffff) // Common UUID type. // 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 { mp_obj_base_t base; uint8_t type; - union { - uint16_t _16; - uint32_t _32; - uint8_t _128[16]; - } uuid; + uint8_t data[16]; } mp_obj_bluetooth_uuid_t; ////////////////////////////////////////////////////////////// @@ -140,8 +140,10 @@ typedef struct { // 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. -// (i.e. the same way they would be printed on a device sticker or in a UI). -// This means that the lower level implementation might need to reorder them (e.g. Nimble works in little-endian) +// (i.e. the same way they would be printed on a device sticker or in a UI), so the user sees +// 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. int mp_bluetooth_init(void); diff --git a/extmod/modbluetooth_nimble.c b/extmod/modbluetooth_nimble.c index 131b73574..c09f1cd2d 100644 --- a/extmod/modbluetooth_nimble.c +++ b/extmod/modbluetooth_nimble.c @@ -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) { if (uuid->type == MP_BLUETOOTH_UUID_TYPE_16) { ble_uuid16_t *result = m_new(ble_uuid16_t, 1); 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; } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_32) { ble_uuid32_t *result = m_new(ble_uuid32_t, 1); 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; } else if (uuid->type == MP_BLUETOOTH_UUID_TYPE_128) { ble_uuid128_t *result = m_new(ble_uuid128_t, 1); 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; } else { 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) { case BLE_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; case BLE_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; case BLE_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; default: assert(false); @@ -131,7 +136,7 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(const ble_uuid_any_t *uuid) { 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) { for (int i = 0; i < 6; ++i) { addr_out[i] = addr_in[5-i];