From d74c8b9425d38fe2dce56e044b128ab5693f5f06 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 6 Aug 2019 22:55:25 -0400 Subject: WIP: more Descriptor work; refactor gattc/gatts read/write --- shared-bindings/bleio/Address.c | 16 ++++++++- shared-bindings/bleio/Attribute.c | 4 +-- shared-bindings/bleio/Characteristic.c | 62 +++++++++++++++++++++++++++++----- shared-bindings/bleio/Characteristic.h | 3 +- shared-bindings/bleio/Descriptor.c | 46 ++++++++++++++++++++----- shared-bindings/bleio/Descriptor.h | 6 ++-- shared-bindings/bleio/Service.c | 3 ++ shared-bindings/bleio/__init__.c | 1 + shared-bindings/bleio/__init__.h | 6 ++++ 9 files changed, 124 insertions(+), 23 deletions(-) (limited to 'shared-bindings/bleio') diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c index d77cfa404..baeb6d7c0 100644 --- a/shared-bindings/bleio/Address.c +++ b/shared-bindings/bleio/Address.c @@ -83,7 +83,21 @@ STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, //| .. attribute:: address_bytes //| -//| The bytes that make up the device address (read-only) +//| The bytes that make up the device address (read-only). +//| +//| Note that the ``bytes`` object returned is in little-endian order: +//| The least significant byte is ``address_bytes[0]``. So the address will +//| appear to be reversed if you print the raw ``bytes`` object. If you print +//| or use `str()` on the :py:class:`~bleio.Attribute` object itself, the address will be printed +//| in the expected order. For example: +//| +//| .. code-block:: pycon +//| +//| >>> import bleio +//| >>> bleio.adapter.address +//|
+//| >>> bleio.adapter.address.address_bytes +//| b'5\xa8\xed\xf5\x1d\xc8' //| STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) { bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c index f640cc05c..ef6b17253 100644 --- a/shared-bindings/bleio/Attribute.c +++ b/shared-bindings/bleio/Attribute.c @@ -37,12 +37,12 @@ //| ========================================================= //| //| Definitions associated with all BLE attributes: characteristics, descriptors, etc. -//| `Attribute` is, notionally, a superclass of `Characteristic` and `Descriptor`, +//| :py:class:`~bleio.Attribute` is, notionally, a superclass of `Characteristic` and `Descriptor`, //| but is not defined as a Python superclass of those classes. //| //| .. class:: Attribute() //| -//| You cannot create an instance of `Attribute`. +//| You cannot create an instance of :py:class:`~bleio.Attribute`. //| STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index 09ed48ef9..45bec6c28 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -30,6 +30,7 @@ #include "py/runtime.h" #include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/UUID.h" //| .. currentmodule:: bleio @@ -41,24 +42,28 @@ //| and writing of the characteristic's value. //| //| -//| .. class:: Characteristic(uuid, *, properties=0, security_mode=`Attribute.OPEN`, descriptors=None) +//| .. class:: Characteristic(uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, descriptors=None) //| //| Create a new Characteristic object identified by the specified UUID. //| //| :param bleio.UUID uuid: The uuid of the characteristic //| :param int properties: bitmask of these values bitwise-or'd together: `BROADCAST`, `INDICATE`, //| `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE` -//| :param int security_mode: one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which +//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, //| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, -//| `Attribute.SIGNED_NO_MITM`, `Attribute.SIGNED_WITH_MITM`. +//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. +//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which +//| security mode is required. Values allowed are the same as `read_perm`. //| :param iterable descriptors: BLE descriptors for this characteristic. //| STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_uuid, ARG_properties, ARG_security_mode, ARG_descriptors }; + enum { ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm, ARG_descriptors }; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0 } }, - { MP_QSTR_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, { MP_QSTR_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; @@ -77,8 +82,11 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t mp_raise_ValueError(translate("Invalid properties")); } - const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; - common_hal_bleio_attribute_security_mode_check_valid(security_mode); + const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(read_perm); + + const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(write_perm); mp_obj_t descriptors = args[ARG_descriptors].u_obj; if (descriptors == mp_const_none) { @@ -88,7 +96,27 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); self->base.type = &bleio_characteristic_type; - common_hal_bleio_characteristic_construct(self, uuid, properties, security_mode, descriptors); + // If descriptors is not an iterable, an exception will be thrown. + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[ARG_descriptors].u_obj, &iter_buf); + +// Copy the descriptors list and validate its items. + mp_obj_t desc_list_obj = mp_obj_new_list(0, NULL); + mp_obj_list_t *desc_list = MP_OBJ_TO_PTR(desc_list_obj); + + mp_obj_t descriptor_obj; + while ((descriptor_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(descriptor_obj, &bleio_descriptor_type)) { + mp_raise_ValueError(translate("descriptors includes an object that is not a Descriptors")); + } + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(descriptor_obj); + if (common_hal_bleio_descriptor_get_characteristic(descriptor) != mp_const_none) { + mp_raise_ValueError(translate("Descriptor is already attached to a Characteristic")); + } + mp_obj_list_append(desc_list_obj, descriptor_obj); + } + + common_hal_bleio_characteristic_construct(self, uuid, properties, read_perm, write_perm, desc_list); return MP_OBJ_FROM_PTR(self); } @@ -182,6 +210,24 @@ const mp_obj_property_t bleio_characteristic_descriptors_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: service (read-only) +//| +//| The Service this Characteristic is a part of. None if not yet assigned to a Service. +//| +STATIC mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_characteristic_get_service(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_service_obj, bleio_characteristic_get_service); + +const mp_obj_property_t bleio_characteristic_service_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_service_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + //| .. method:: set_cccd(*, notify=False, indicate=False) //| //| Set the remote characteristic's CCCD to enable or disable notification and indication. diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h index 379f9b4bf..1d532d748 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -34,12 +34,13 @@ extern const mp_obj_type_t bleio_characteristic_type; -extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t security_mode, mp_obj_t descriptors); +extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_obj_list_t *descriptor_list); extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); +extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index b709f3aa7..1ab8c9ecd 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -42,15 +42,24 @@ //| information about the characteristic. //| -//| .. class:: Descriptor(uuid, security_mode=`Attribute.OPEN`) +//| .. class:: Descriptor(uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`) +//| +//| Create a new descriptor object with the UUID uuid +//| +//| :param bleio.UUID uuid: The uuid of the descriptor +//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which +//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, +//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. +//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which +//| security mode is required. Values allowed are the same as `read_perm`. //| -//| Create a new descriptor object with the UUID uuid and the given value, if any. - STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_uuid, ARG_security_mode }; + enum { ARG_uuid, ARG_read_perm, ARG_write_perm }; static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -62,14 +71,17 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar mp_raise_ValueError(translate("Expected a UUID")); } - const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; - common_hal_bleio_attribute_security_mode_check_valid(security_mode); + const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(read_perm); + + const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; + common_hal_bleio_attribute_security_mode_check_valid(write_perm); bleio_descriptor_obj_t *self = m_new_obj(bleio_descriptor_obj_t); self->base.type = type; bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_arg); - common_hal_bleio_descriptor_construct(self, uuid, security_mode); + common_hal_bleio_descriptor_construct(self, uuid, read_perm, write_perm); return MP_OBJ_FROM_PTR(self); } @@ -93,6 +105,24 @@ const mp_obj_property_t bleio_descriptor_uuid_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. attribute:: characteristic (read-only) +//| +//| The Characteristic this Descriptor is a part of. None if not yet assigned to a Characteristic. +//| +STATIC mp_obj_t bleio_descriptor_get_characteristic(mp_obj_t self_in) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_bleio_descriptor_get_characteristic(self); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_characteristic_obj, bleio_descriptor_get_characteristic); + +const mp_obj_property_t bleio_descriptor_characteristic_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_descriptor_get_characteristic_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) }, diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h index a7daee574..eefce03d1 100644 --- a/shared-bindings/bleio/Descriptor.h +++ b/shared-bindings/bleio/Descriptor.h @@ -34,8 +34,8 @@ extern const mp_obj_type_t bleio_descriptor_type; -extern mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self); -extern mp_obj_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); -extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t security_mode); +extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm); +extern bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self); +extern mp_obj_t common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index b4aeab2bd..6961b0b52 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -96,6 +96,9 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, // The descriptor base UUID doesn't match the characteristic base UUID. mp_raise_ValueError(translate("Characteristic UUID doesn't match Service UUID")); } + if (common_hal_bleio_characteristic_get_service(characteristic) != MP_OBJ_NULL) { + mp_raise_ValueError(translate("Characteristic is already attached to a Service")); + } mp_obj_list_append(char_list_obj, characteristic_obj); } diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 7a6f96436..0009cf113 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -59,6 +59,7 @@ //| //| Address //| Adapter +//| Attribute //| Central //| Characteristic //| CharacteristicBuffer diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h index 626b188a9..6a4c804f5 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -38,9 +38,15 @@ extern const super_adapter_obj_t common_hal_bleio_adapter_obj; +extern void common_hal_bleio_check_connected(uint16_t conn_handle); + extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); extern mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device); extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); +extern mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle); +extern void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +extern void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H -- cgit v1.2.3