Skip to content

extmod/modbluetooth: Make UUID support the buffer protocol. #5236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions examples/bluetooth/ble_advertising.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@
_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)


# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
payload = bytearray()
Expand All @@ -28,8 +34,13 @@ def _append(adv_type, value):

if services:
for uuid in services:
# TODO: Support bluetooth.UUID class.
_append(_ADV_TYPE_UUID16_COMPLETE, struct.pack('<h', uuid))
b = bytes(uuid)
if len(b) == 2:
_append(_ADV_TYPE_UUID16_COMPLETE, b)
elif len(b) == 4:
_append(_ADV_TYPE_UUID32_COMPLETE, b)
elif len(b) == 16:
_append(_ADV_TYPE_UUID128_COMPLETE, b)

# See org.bluetooth.characteristic.gap.appearance.xml
_append(_ADV_TYPE_APPEARANCE, struct.pack('<h', appearance))
Expand Down
2 changes: 1 addition & 1 deletion examples/bluetooth/ble_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __init__(self, ble, name='mpy-temp'):
self._ble.irq(handler=self._irq)
((self._handle,),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
self._connections = set()
self._payload = advertising_payload(name=name, services=[0x181A], appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER)
self._payload = advertising_payload(name=name, services=[_ENV_SENSE_UUID], appearance=_ADV_APPEARANCE_GENERIC_THERMOMETER)
self._advertise()

def _irq(self, event, data):
Expand Down
1 change: 1 addition & 0 deletions examples/bluetooth/ble_uart_peripheral.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(self, ble, name='mpy-uart', rxbuf=100):
self._connections = set()
self._rx_buffer = bytearray()
self._handler = None
# Optionally add services=[_UART_UUID], but this is likely to make the payload too large.
self._payload = advertising_payload(name=name, appearance=_ADV_APPEARANCE_GENERIC_COMPUTER)
self._advertise()

Expand Down
88 changes: 32 additions & 56 deletions extmod/modbluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -135,83 +136,57 @@ 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

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]);
}
}

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
Expand All @@ -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 },
};

// ----------------------------------------------------------------------------
Expand Down
16 changes: 9 additions & 7 deletions extmod/modbluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//////////////////////////////////////////////////////////////
Expand All @@ -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);
Expand Down
19 changes: 12 additions & 7 deletions extmod/modbluetooth_nimble.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -115,23 +116,27 @@ 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);
}
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];
Expand Down
3 changes: 0 additions & 3 deletions py/objstr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1913,9 +1913,6 @@ mp_int_t mp_obj_str_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_u
return 0;
} else {
// can't write to a string
bufinfo->buf = NULL;
bufinfo->len = 0;
bufinfo->typecode = -1;
return 1;
}
}
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy