|
30 | 30 | #include "py/runtime.h"
|
31 | 31 | #include "shared-bindings/bleio/Attribute.h"
|
32 | 32 | #include "shared-bindings/bleio/Characteristic.h"
|
33 |
| -#include "shared-bindings/bleio/Descriptor.h" |
| 33 | +#include "shared-bindings/bleio/Service.h" |
34 | 34 | #include "shared-bindings/bleio/UUID.h"
|
35 | 35 |
|
36 | 36 | //| .. currentmodule:: bleio
|
|
41 | 41 | //| Stores information about a BLE service characteristic and allows reading
|
42 | 42 | //| and writing of the characteristic's value.
|
43 | 43 | //|
|
44 |
| -//| A Characteristic cannot be created directly. A new local Characteristic can be created |
45 |
| -//| and attached to a Service by calling `Service.add_characteristic()`. |
| 44 | +//| There is no regular constructor for a Characteristic. A new local Characteristic can be created |
| 45 | +//| and attached to a Service by calling `Characteristic.add_to_service()`. |
46 | 46 | //| Remote Characteristic objects are created by `Central.discover_remote_services()`
|
47 | 47 | //| or `Peripheral.discover_remote_services()` as part of remote Services.
|
48 | 48 | //|
|
49 | 49 |
|
| 50 | +//| .. method:: add_to_service(service, uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=None) |
| 51 | +//| |
| 52 | +//| Create a new `Characteristic` object, and add it to this Service. |
| 53 | +//| |
| 54 | +//| :param bleio.Service service: The service that will provide this characteristic |
| 55 | +//| :param bleio.UUID uuid: The uuid of the characteristic |
| 56 | +//| :param int properties: The properties of the characteristic, |
| 57 | +//| specified as a bitmask of these values bitwise-or'd together: |
| 58 | +//| `Characteristic.BROADCAST`, `Characteristic.INDICATE`, `Characteristic.NOTIFY`, |
| 59 | +//| `Characteristic.READ`, `Characteristic.WRITE`, `Characteristic.WRITE_NO_RESPONSE`. |
| 60 | +//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which |
| 61 | +//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, |
| 62 | +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, |
| 63 | +//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. |
| 64 | +//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which |
| 65 | +//| security mode is required. Values allowed are the same as ``read_perm``. |
| 66 | +//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is |
| 67 | +//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum |
| 68 | +//| number of data bytes that fit in a single BLE 4.x ATT packet. |
| 69 | +//| :param bool fixed_length: True if the characteristic value is of fixed length. |
| 70 | +//| :param buf initial_value: The initial value for this characteristic. If not given, will be |
| 71 | +//| filled with zeros. |
| 72 | +//| |
| 73 | +//| :return: the new `Characteristic`. |
| 74 | +//| |
| 75 | +STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
| 76 | + // class is arg[0], which we can ignore. |
| 77 | + |
| 78 | + enum { ARG_service, ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm, |
| 79 | + ARG_max_length, ARG_fixed_length, ARG_initial_value }; |
| 80 | + static const mp_arg_t allowed_args[] = { |
| 81 | + { MP_QSTR_service, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 82 | + { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 83 | + { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} }, |
| 84 | + { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, |
| 85 | + { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, |
| 86 | + { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, |
| 87 | + { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, |
| 88 | + { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 89 | + }; |
| 90 | + |
| 91 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 92 | + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 93 | + |
| 94 | + const mp_obj_t service_obj = args[ARG_service].u_obj; |
| 95 | + if (!MP_OBJ_IS_TYPE(service_obj, &bleio_service_type)) { |
| 96 | + mp_raise_ValueError(translate("Expected a Service")); |
| 97 | + } |
| 98 | + |
| 99 | + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; |
| 100 | + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { |
| 101 | + mp_raise_ValueError(translate("Expected a UUID")); |
| 102 | + } |
| 103 | + |
| 104 | + const bleio_characteristic_properties_t properties = args[ARG_properties].u_int; |
| 105 | + if (properties & ~CHAR_PROP_ALL) { |
| 106 | + mp_raise_ValueError(translate("Invalid properties")); |
| 107 | + } |
| 108 | + |
| 109 | + const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; |
| 110 | + common_hal_bleio_attribute_security_mode_check_valid(read_perm); |
| 111 | + |
| 112 | + const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; |
| 113 | + common_hal_bleio_attribute_security_mode_check_valid(write_perm); |
| 114 | + |
| 115 | + const mp_int_t max_length = args[ARG_max_length].u_int; |
| 116 | + const bool fixed_length = args[ARG_fixed_length].u_bool; |
| 117 | + mp_obj_t initial_value = args[ARG_initial_value].u_obj; |
| 118 | + |
| 119 | + // Length will be validated in common_hal. |
| 120 | + mp_buffer_info_t initial_value_bufinfo; |
| 121 | + if (initial_value == mp_const_none) { |
| 122 | + if (fixed_length && max_length > 0) { |
| 123 | + initial_value = mp_obj_new_bytes_of_zeros(max_length); |
| 124 | + } else { |
| 125 | + initial_value = mp_const_empty_bytes; |
| 126 | + } |
| 127 | + } |
| 128 | + mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); |
| 129 | + |
| 130 | + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); |
| 131 | + characteristic->base.type = &bleio_characteristic_type; |
| 132 | + |
| 133 | + // Range checking on max_length arg is done by the common_hal layer, because |
| 134 | + // it may vary depending on underlying BLE implementation. |
| 135 | + common_hal_bleio_characteristic_construct( |
| 136 | + characteristic, MP_OBJ_TO_PTR(service_obj), MP_OBJ_TO_PTR(uuid_obj), |
| 137 | + properties, read_perm, write_perm, |
| 138 | + max_length, fixed_length, &initial_value_bufinfo); |
| 139 | + |
| 140 | + common_hal_bleio_service_add_characteristic(service_obj, characteristic); |
| 141 | + |
| 142 | + return MP_OBJ_FROM_PTR(characteristic); |
| 143 | +} |
| 144 | +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 3, bleio_characteristic_add_to_service); |
| 145 | +STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_characteristic_add_to_service_obj, MP_ROM_PTR(&bleio_characteristic_add_to_service_fun_obj)); |
| 146 | + |
| 147 | + |
| 148 | + |
50 | 149 | //| .. attribute:: properties
|
51 | 150 | //|
|
52 | 151 | //| An int bitmask representing which properties are set, specified as bitwise or'ing of
|
@@ -155,84 +254,6 @@ const mp_obj_property_t bleio_characteristic_service_obj = {
|
155 | 254 | (mp_obj_t)&mp_const_none_obj },
|
156 | 255 | };
|
157 | 256 |
|
158 |
| -//| .. method:: add_descriptor(uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=b'') |
159 |
| -//| |
160 |
| -//| Create a new `Descriptor` object, and add it to this Service. |
161 |
| -//| |
162 |
| -//| :param bleio.UUID uuid: The uuid of the descriptor |
163 |
| -//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which |
164 |
| -//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, |
165 |
| -//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, |
166 |
| -//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`. |
167 |
| -//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which |
168 |
| -//| security mode is required. Values allowed are the same as ``read_perm``. |
169 |
| -//| :param int max_length: Maximum length in bytes of the descriptor value. The maximum allowed is |
170 |
| -//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum |
171 |
| -//| number of data bytes that fit in a single BLE 4.x ATT packet. |
172 |
| -//| :param bool fixed_length: True if the descriptor value is of fixed length. |
173 |
| -//| :param buf initial_value: The initial value for this descriptor. |
174 |
| -//| |
175 |
| -//| :return: the new `Descriptor`. |
176 |
| -//| |
177 |
| -STATIC mp_obj_t bleio_characteristic_add_descriptor(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
178 |
| - bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); |
179 |
| - |
180 |
| - enum { ARG_uuid, ARG_read_perm, ARG_write_perm, |
181 |
| - ARG_max_length, ARG_fixed_length, ARG_initial_value }; |
182 |
| - static const mp_arg_t allowed_args[] = { |
183 |
| - { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
184 |
| - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, |
185 |
| - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} }, |
186 |
| - { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} }, |
187 |
| - { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} }, |
188 |
| - { MP_QSTR_initial_value, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, |
189 |
| - }; |
190 |
| - |
191 |
| - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
192 |
| - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
193 |
| - |
194 |
| - const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; |
195 |
| - |
196 |
| - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { |
197 |
| - mp_raise_ValueError(translate("Expected a UUID")); |
198 |
| - } |
199 |
| - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); |
200 |
| - |
201 |
| - const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int; |
202 |
| - common_hal_bleio_attribute_security_mode_check_valid(read_perm); |
203 |
| - |
204 |
| - const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int; |
205 |
| - common_hal_bleio_attribute_security_mode_check_valid(write_perm); |
206 |
| - |
207 |
| - const mp_int_t max_length = args[ARG_max_length].u_int; |
208 |
| - const bool fixed_length = args[ARG_fixed_length].u_bool; |
209 |
| - mp_obj_t initial_value = args[ARG_initial_value].u_obj; |
210 |
| - |
211 |
| - // Length will be validated in common_hal. |
212 |
| - mp_buffer_info_t initial_value_bufinfo; |
213 |
| - if (initial_value == mp_const_none) { |
214 |
| - if (fixed_length && max_length > 0) { |
215 |
| - initial_value = mp_obj_new_bytes_of_zeros(max_length); |
216 |
| - } else { |
217 |
| - initial_value = mp_const_empty_bytes; |
218 |
| - } |
219 |
| - } |
220 |
| - mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); |
221 |
| - |
222 |
| - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); |
223 |
| - descriptor->base.type = &bleio_descriptor_type; |
224 |
| - |
225 |
| - // Range checking on max_length arg is done by the common_hal layer, because |
226 |
| - // it may vary depending on underlying BLE implementation. |
227 |
| - common_hal_bleio_descriptor_construct( |
228 |
| - descriptor, uuid, read_perm, write_perm, max_length, fixed_length, &initial_value_bufinfo); |
229 |
| - |
230 |
| - common_hal_bleio_characteristic_add_descriptor(self, descriptor); |
231 |
| - |
232 |
| - return MP_OBJ_FROM_PTR(descriptor); |
233 |
| -} |
234 |
| -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_descriptor_obj, 2, bleio_characteristic_add_descriptor); |
235 |
| - |
236 | 257 | //| .. method:: set_cccd(*, notify=False, indicate=False)
|
237 | 258 | //|
|
238 | 259 | //| Set the remote characteristic's CCCD to enable or disable notification and indication.
|
@@ -260,10 +281,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_ch
|
260 | 281 |
|
261 | 282 |
|
262 | 283 | STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
|
263 |
| - { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties) }, |
| 284 | + { MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) }, |
| 285 | + { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties_obj) }, |
264 | 286 | { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) },
|
265 | 287 | { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) },
|
266 |
| - { MP_ROM_QSTR(MP_QSTR_add_descriptor), MP_ROM_PTR(&bleio_characteristic_add_descriptor_obj) }, |
267 | 288 | { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) },
|
268 | 289 |
|
269 | 290 | // Bitmask constants to represent properties
|
|
0 commit comments