summaryrefslogtreecommitdiff
path: root/shared-bindings
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2019-12-05 22:45:53 -0500
committerDan Halbert <halbert@halwitz.org>2019-12-05 22:45:53 -0500
commit40434d691934cf7f5792f91ce0288beb568bab85 (patch)
treee2f7d0191685f0b519e98c3e1551626fbbf49585 /shared-bindings
parent1505da784f228d43df41a773cfe504e7e4da330a (diff)
parent15886b1505d854d76e353b9c5261568c7065d2bf (diff)
wip
Diffstat (limited to 'shared-bindings')
-rw-r--r--shared-bindings/_bleio/Adapter.c299
-rw-r--r--shared-bindings/_bleio/Adapter.h28
-rw-r--r--shared-bindings/_bleio/Address.c30
-rw-r--r--shared-bindings/_bleio/Central.c207
-rw-r--r--shared-bindings/_bleio/Characteristic.c37
-rw-r--r--shared-bindings/_bleio/Characteristic.h6
-rw-r--r--shared-bindings/_bleio/CharacteristicBuffer.c8
-rw-r--r--shared-bindings/_bleio/Connection.c216
-rw-r--r--shared-bindings/_bleio/Connection.h (renamed from shared-bindings/_bleio/Central.h)20
-rw-r--r--shared-bindings/_bleio/Descriptor.c13
-rw-r--r--shared-bindings/_bleio/Descriptor.h2
-rw-r--r--shared-bindings/_bleio/Peripheral.c325
-rw-r--r--shared-bindings/_bleio/Peripheral.h48
-rw-r--r--shared-bindings/_bleio/ScanEntry.c74
-rw-r--r--shared-bindings/_bleio/ScanEntry.h3
-rw-r--r--shared-bindings/_bleio/ScanResults.c72
-rw-r--r--shared-bindings/_bleio/ScanResults.h (renamed from shared-bindings/_bleio/Scanner.h)17
-rw-r--r--shared-bindings/_bleio/Scanner.c129
-rw-r--r--shared-bindings/_bleio/Service.c76
-rw-r--r--shared-bindings/_bleio/Service.h14
-rw-r--r--shared-bindings/_bleio/UUID.c51
-rw-r--r--shared-bindings/_bleio/UUID.h5
-rw-r--r--shared-bindings/_bleio/__init__.c88
-rw-r--r--shared-bindings/_bleio/__init__.h40
-rw-r--r--shared-bindings/_pixelbuf/__init__.c4
-rw-r--r--shared-bindings/audiobusio/I2SOut.c5
-rw-r--r--shared-bindings/audioio/__init__.c2
-rw-r--r--shared-bindings/board/__init__.c6
-rw-r--r--shared-bindings/busio/I2C.c4
-rw-r--r--shared-bindings/busio/SPI.c7
-rw-r--r--shared-bindings/busio/UART.c46
-rw-r--r--shared-bindings/busio/UART.h3
-rw-r--r--shared-bindings/microcontroller/Pin.h2
-rw-r--r--shared-bindings/pulseio/PWMOut.c11
-rw-r--r--shared-bindings/rtc/RTC.c23
-rw-r--r--shared-bindings/rtc/__init__.c16
-rw-r--r--shared-bindings/time/__init__.c4
37 files changed, 1056 insertions, 885 deletions
diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c
index 0caca96b8..7e2a5f05b 100644
--- a/shared-bindings/_bleio/Adapter.c
+++ b/shared-bindings/_bleio/Adapter.c
@@ -25,22 +25,45 @@
* THE SOFTWARE.
*/
+#include <string.h>
+
#include "py/objproperty.h"
+#include "py/runtime.h"
#include "shared-bindings/_bleio/Address.h"
#include "shared-bindings/_bleio/Adapter.h"
+#define ADV_INTERVAL_MIN (0.0020f)
+#define ADV_INTERVAL_MIN_STRING "0.0020"
+#define ADV_INTERVAL_MAX (10.24f)
+#define ADV_INTERVAL_MAX_STRING "10.24"
+// 20ms is recommended by Apple
+#define ADV_INTERVAL_DEFAULT (0.1f)
+
+#define INTERVAL_DEFAULT (0.1f)
+#define INTERVAL_MIN (0.0025f)
+#define INTERVAL_MIN_STRING "0.0025"
+#define INTERVAL_MAX (40.959375f)
+#define INTERVAL_MAX_STRING "40.959375"
+#define WINDOW_DEFAULT (0.1f)
+
//| .. currentmodule:: _bleio
//|
-//| :class:`Adapter` --- BLE adapter information
+//| :class:`Adapter` --- BLE adapter
//| ----------------------------------------------------
//|
-//| Get current status of the BLE adapter
+//| The Adapter manages the discovery and connection to other nearby Bluetooth Low Energy devices.
+//| This part of the Bluetooth Low Energy Specification is known as Generic Access Profile (GAP).
//|
-//| Usage::
+//| Discovery of other devices happens during a scanning process that listens for small packets of
+//| information, known as advertisements, that are broadcast unencrypted. The advertising packets
+//| have two different uses. The first is to broadcast a small piece of data to anyone who cares and
+//| and nothing more. These are known as Beacons. The second class of advertisement is to promote
+//| additional functionality available after the devices establish a connection. For example, a
+//| BLE keyboard may advertise that it can provide key information, but not what the key info is.
//|
-//| import _bleio
-//| _bleio.adapter.enabled = True
-//| print(_bleio.adapter.address)
+//| The built-in BLE adapter can do both parts of this process: it can scan for other device
+//| advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming
+//| connections and also initiate connections.
//|
//| .. class:: Adapter()
@@ -49,19 +72,19 @@
//| Use `_bleio.adapter` to access the sole instance available.
//|
-//| .. attribute:: adapter.enabled
+//| .. attribute:: enabled
//|
-//| State of the BLE adapter.
+//| State of the BLE adapter.
//|
STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) {
- return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled());
+ return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_enabled_obj, bleio_adapter_get_enabled);
static mp_obj_t bleio_adapter_set_enabled(mp_obj_t self, mp_obj_t value) {
const bool enabled = mp_obj_is_true(value);
- common_hal_bleio_adapter_set_enabled(enabled);
+ common_hal_bleio_adapter_set_enabled(self, enabled);
return mp_const_none;
}
@@ -74,12 +97,12 @@ const mp_obj_property_t bleio_adapter_enabled_obj = {
(mp_obj_t)&mp_const_none_obj },
};
-//| .. attribute:: adapter.address
+//| .. attribute:: address
//|
-//| MAC address of the BLE adapter. (read-only)
+//| MAC address of the BLE adapter. (read-only)
//|
STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) {
- return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address());
+ return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address);
@@ -91,29 +114,259 @@ const mp_obj_property_t bleio_adapter_address_obj = {
(mp_obj_t)&mp_const_none_obj },
};
-//| .. attribute:: adapter.default_name
+//| .. attribute:: name
+//|
+//| name of the BLE adapter used once connected. Not used in advertisements.
+//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``,
+//| to make it easy to distinguish multiple CircuitPython boards.
+//|
+STATIC mp_obj_t bleio_adapter_get_name(mp_obj_t self) {
+ return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_name(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_name_obj, bleio_adapter_get_name);
+
+
+STATIC mp_obj_t bleio_adapter_set_name(mp_obj_t self, mp_obj_t new_name) {
+ common_hal_bleio_adapter_set_name(self, mp_obj_str_get_str(new_name));
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(bleio_adapter_set_name_obj, bleio_adapter_set_name);
+
+const mp_obj_property_t bleio_adapter_name_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_adapter_get_name_obj,
+ (mp_obj_t)&bleio_adapter_set_name_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
+//| .. method:: start_advertising(data, *, scan_response=None, connectable=True, interval=0.1)
+//|
+//| Starts advertising until `stop_advertising` is called or if connectable, another device
+//| connects to us.
+//|
+//| :param buf data: advertising data packet bytes
+//| :param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed.
+//| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral.
+//| :param float interval: advertising interval, in seconds
+//|
+STATIC mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_interval };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_buffer_info_t data_bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ);
+
+ // Pass an empty buffer if scan_response not provided.
+ mp_buffer_info_t scan_response_bufinfo = { 0 };
+ if (args[ARG_scan_response].u_obj != mp_const_none) {
+ mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ);
+ }
+
+ if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
+ args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT);
+ }
+
+ const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj);
+ if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) {
+ mp_raise_ValueError_varg(translate("interval must be in range %s-%s"),
+ ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING);
+ }
+
+ common_hal_bleio_adapter_start_advertising(self, args[ARG_connectable].u_bool, interval,
+ &data_bufinfo, &scan_response_bufinfo);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_advertising_obj, 2, bleio_adapter_start_advertising);
+
+//| .. method:: stop_advertising()
+//|
+//| Stop sending advertising packets.
+STATIC mp_obj_t bleio_adapter_stop_advertising(mp_obj_t self_in) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_bleio_adapter_stop_advertising(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_advertising_obj, bleio_adapter_stop_advertising);
+
+//| .. method:: start_scan(prefixes=b"", \*, buffer_size=512, extended=False, timeout=None, interval=0.1, window=0.1, minimum_rssi=-80, active=True)
+//|
+//| Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are
+//| filtered and returned separately.
+//|
+//| :param sequence prefixes: Sequence of byte string prefixes to filter advertising packets
+//| with. A packet without an advertising structure that matches one of the prefixes is
+//| ignored. Format is one byte for length (n) and n bytes of prefix and can be repeated.
+//| :param int buffer_size: the maximum number of advertising bytes to buffer.
+//| :param bool extended: When True, support extended advertising packets. Increasing buffer_size is recommended when this is set.
+//| :param float timeout: the scan timeout in seconds. If None, will scan until `stop_scan` is called.
+//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows
+//| Must be in the range 0.0025 - 40.959375 seconds.
+//| :param float window: the duration (in seconds) to scan a single BLE channel.
+//| window must be <= interval.
+//| :param int minimum_rssi: the minimum rssi of entries to return.
+//| :param bool active: retrieve scan responses for scannable advertisements.
+//| :returns: an iterable of `_bleio.ScanEntry` objects
+//| :rtype: iterable
+//|
+STATIC mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_prefixes, ARG_buffer_size, ARG_extended, ARG_timeout, ARG_interval, ARG_window, ARG_minimum_rssi, ARG_active };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_prefixes, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 512} },
+ { MP_QSTR_extended, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_minimum_rssi, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -80} },
+ { MP_QSTR_active, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_float_t timeout = 0;
+ if (args[ARG_timeout].u_obj != mp_const_none) {
+ timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+ }
+
+ if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
+ args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT);
+ }
+
+ if (args[ARG_window].u_obj == MP_OBJ_NULL) {
+ args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT);
+ }
+
+ const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj);
+ if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
+ mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING);
+ }
+
+ const mp_float_t window = mp_obj_float_get(args[ARG_window].u_obj);
+ if (window > interval) {
+ mp_raise_ValueError(translate("window must be <= interval"));
+ }
+
+ mp_buffer_info_t prefix_bufinfo;
+ prefix_bufinfo.len = 0;
+ if (args[ARG_prefixes].u_obj != MP_OBJ_NULL) {
+ mp_get_buffer_raise(args[ARG_prefixes].u_obj, &prefix_bufinfo, MP_BUFFER_READ);
+ if (gc_nbytes(prefix_bufinfo.buf) == 0) {
+ mp_raise_ValueError(translate("Prefix buffer must be on the heap"));
+ }
+ }
+
+ return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, args[ARG_buffer_size].u_int, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter_start_scan);
+
+//| .. method:: stop_scan()
+//|
+//| Stop the current scan.
+STATIC mp_obj_t bleio_adapter_stop_scan(mp_obj_t self_in) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_bleio_adapter_stop_scan(self);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_scan_obj, bleio_adapter_stop_scan);
+
+//| .. attribute:: connected
//|
-//| default_name of the BLE adapter. (read-only)
-//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``,
-//| to make it easy to distinguish multiple CircuitPython boards.
+//| True when the adapter is connected to another device regardless of who initiated the
+//| connection. (read-only)
//|
-STATIC mp_obj_t bleio_adapter_get_default_name(mp_obj_t self) {
- return common_hal_bleio_adapter_get_default_name();
+STATIC mp_obj_t bleio_adapter_get_connected(mp_obj_t self) {
+ return mp_obj_new_bool(common_hal_bleio_adapter_get_connected(self));
}
-MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_default_name_obj, bleio_adapter_get_default_name);
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_connected_obj, bleio_adapter_get_connected);
-const mp_obj_property_t bleio_adapter_default_name_obj = {
+const mp_obj_property_t bleio_adapter_connected_obj = {
.base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_adapter_get_default_name_obj,
+ .proxy = { (mp_obj_t)&bleio_adapter_get_connected_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: connections
+//|
+//| Tuple of active connections including those initiated through
+//| :py:meth:`_bleio.Adapter.connect`. (read-only)
+//|
+STATIC mp_obj_t bleio_adapter_get_connections(mp_obj_t self) {
+ return common_hal_bleio_adapter_get_connections(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_connections_obj, bleio_adapter_get_connections);
+
+const mp_obj_property_t bleio_adapter_connections_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_adapter_get_connections_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
+//| .. method:: connect(address, *, timeout)
+//|
+//| Attempts a connection to the device with the given address.
+//|
+//| :param Address address: The address of the peripheral to connect to
+//| :param float/int timeout: Try to connect for timeout seconds.
+//|
+STATIC mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_address, ARG_timeout };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) {
+ mp_raise_TypeError(translate("Expected an Address"));
+ }
+
+ bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj);
+ mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
+
+ return common_hal_bleio_adapter_connect(self, address, timeout);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_connect_obj, 2, bleio_adapter_connect);
+
+
STATIC const mp_rom_map_elem_t bleio_adapter_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&bleio_adapter_enabled_obj) },
{ MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_adapter_address_obj) },
- { MP_ROM_QSTR(MP_QSTR_default_name), MP_ROM_PTR(&bleio_adapter_default_name_obj) },
+ { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_adapter_name_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_adapter_start_advertising_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_adapter_stop_advertising_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_start_scan), MP_ROM_PTR(&bleio_adapter_start_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop_scan), MP_ROM_PTR(&bleio_adapter_stop_scan_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_adapter_connect_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_adapter_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connections), MP_ROM_PTR(&bleio_adapter_connections_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_adapter_locals_dict, bleio_adapter_locals_dict_table);
diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h
index 932fc9c95..4340d82c1 100644
--- a/shared-bindings/_bleio/Adapter.h
+++ b/shared-bindings/_bleio/Adapter.h
@@ -28,13 +28,33 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
+#include <stdint.h>
+
+#include "common-hal/_bleio/Adapter.h"
+
+#include "py/objstr.h"
#include "shared-module/_bleio/Address.h"
const mp_obj_type_t bleio_adapter_type;
-extern bool common_hal_bleio_adapter_get_enabled(void);
-extern void common_hal_bleio_adapter_set_enabled(bool enabled);
-extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(void);
-extern mp_obj_t common_hal_bleio_adapter_get_default_name(void);
+extern bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self);
+extern void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled);
+extern bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self);
+extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self);
+
+extern mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self);
+extern void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name);
+
+extern uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, float interval, uint8_t *advertising_data, uint16_t advertising_data_len, uint8_t *scan_response_data, uint16_t scan_response_data_len);
+
+extern void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, mp_float_t interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo);
+void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self);
+
+mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t* prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active);
+void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self);
+
+bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self);
+mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self);
+mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c
index cdee02b5d..c31eb604b 100644
--- a/shared-bindings/_bleio/Address.c
+++ b/shared-bindings/_bleio/Address.c
@@ -114,10 +114,11 @@ const mp_obj_property_t bleio_address_address_bytes_obj = {
};
//| .. attribute:: type
-//|
+//|
//| The address type (read-only).
-//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`,
-//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`.
+//|
+//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`, `RANDOM_PRIVATE_RESOLVABLE`,
+//| or `RANDOM_PRIVATE_NON_RESOLVABLE`.
//|
STATIC mp_obj_t bleio_address_get_type(mp_obj_t self_in) {
bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -159,6 +160,28 @@ STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o
}
}
+//| .. method:: __hash__()
+//|
+//| Returns a hash for the Address data.
+//|
+STATIC mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ switch (op) {
+ // Two Addresses are equal if their address bytes and address_type are equal
+ case MP_UNARY_OP_HASH: {
+ mp_obj_t bytes = common_hal_bleio_address_get_address_bytes(MP_OBJ_TO_PTR(self_in));
+ GET_STR_HASH(bytes, h);
+ if (h == 0) {
+ GET_STR_DATA_LEN(bytes, data, len);
+ h = qstr_compute_hash(data, len);
+ }
+ h ^= common_hal_bleio_address_get_type(MP_OBJ_TO_PTR(self_in));
+ return MP_OBJ_NEW_SMALL_INT(h);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t buf_info;
@@ -205,6 +228,7 @@ const mp_obj_type_t bleio_address_type = {
.name = MP_QSTR_Address,
.make_new = bleio_address_make_new,
.print = bleio_address_print,
+ .unary_op = bleio_address_unary_op,
.binary_op = bleio_address_binary_op,
.locals_dict = (mp_obj_dict_t*)&bleio_address_locals_dict
};
diff --git a/shared-bindings/_bleio/Central.c b/shared-bindings/_bleio/Central.c
deleted file mode 100644
index 084f40cd6..000000000
--- a/shared-bindings/_bleio/Central.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Dan Halbert for Adafruit Industries
- * Copyright (c) 2018 Artur Pacholec
- * Copyright (c) 2016 Glenn Ruben Bakke
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include "ble_drv.h"
-#include "py/objarray.h"
-#include "py/objproperty.h"
-#include "py/objstr.h"
-#include "py/runtime.h"
-#include "shared-bindings/_bleio/Adapter.h"
-#include "shared-bindings/_bleio/Address.h"
-#include "shared-bindings/_bleio/Characteristic.h"
-#include "shared-bindings/_bleio/Central.h"
-#include "shared-bindings/_bleio/Service.h"
-
-//| .. currentmodule:: _bleio
-//|
-//| :class:`Central` -- A BLE central device
-//| =========================================================
-//|
-//| Implement a BLE central, which runs locally. Can connect to a given address.
-//|
-//| Usage::
-//|
-//| import _bleio
-//|
-//| scanner = _bleio.Scanner()
-//| entries = scanner.scan(2.5)
-//|
-//| my_entry = None
-//| for entry in entries:
-//| if entry.name is not None and entry.name == 'InterestingPeripheral':
-//| my_entry = entry
-//| break
-//|
-//| if not my_entry:
-//| raise Exception("'InterestingPeripheral' not found")
-//|
-//| central = _bleio.Central()
-//| central.connect(my_entry.address, 10) # timeout after 10 seconds
-//| remote_services = central.discover_remote_services()
-//|
-
-//| .. class:: Central()
-//|
-//| Create a new Central object.
-//|
-STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- mp_arg_check_num(n_args, kw_args, 0, 0, false);
-
- bleio_central_obj_t *self = m_new_obj(bleio_central_obj_t);
- self->base.type = &bleio_central_type;
-
- common_hal_bleio_central_construct(self);
-
- return MP_OBJ_FROM_PTR(self);
-}
-
-//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None)
-//| Attempts a connection to the remote peripheral.
-//|
-//| :param Address address: The address of the peripheral to connect to
-//| :param float/int timeout: Try to connect for timeout seconds.
-//|
-STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
-
- enum { ARG_address, ARG_timeout, ARG_service_uuids_whitelist };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ },
- { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) {
- mp_raise_ValueError(translate("Expected an Address"));
- }
-
- bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj);
- mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
-
- // common_hal_bleio_central_connect() will validate that services is an iterable or None.
- common_hal_bleio_central_connect(self, address, timeout);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_connect_obj, 3, bleio_central_connect);
-
-
-//| .. method:: disconnect()
-//|
-//| Disconnects from the remote peripheral.
-//|
-STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) {
- bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- common_hal_bleio_central_disconnect(self);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect);
-
-//| .. method:: discover_remote_services(service_uuids_whitelist=None)
-//| Do BLE discovery for all services or for the given service UUIDS,
-//| to find their handles and characteristics, and return the discovered services.
-//| `Peripheral.connected` must be True.
-//|
-//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services
-//| provided by the peripheral that you want to use.
-//| The peripheral may provide more services, but services not listed are ignored
-//| and will not be returned.
-//|
-//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow.
-//|
-//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you
-//| you must have already created a :py:class:~`UUID` object for that UUID in order for the
-//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered
-//| for use. (This restriction may be lifted in the future.)
-//|
-//| :return: A tuple of services provided by the remote peripheral.
-//|
-STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- bleio_central_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
-
- enum { ARG_service_uuids_whitelist };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- if (!common_hal_bleio_central_get_connected(self)) {
- mp_raise_ValueError(translate("Not connected"));
- }
-
- return MP_OBJ_FROM_PTR(common_hal_bleio_central_discover_remote_services(
- MP_OBJ_FROM_PTR(self),
- args[ARG_service_uuids_whitelist].u_obj));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_discover_remote_services_obj, 1, bleio_central_discover_remote_services);
-
-//| .. attribute:: connected
-//|
-//| True if connected to a remove peripheral.
-//|
-STATIC mp_obj_t bleio_central_get_connected(mp_obj_t self_in) {
- bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- return mp_obj_new_bool(common_hal_bleio_central_get_connected(self));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_connected_obj, bleio_central_get_connected);
-
-const mp_obj_property_t bleio_central_connected_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_central_get_connected_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = {
- // Methods
- { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) },
- { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) },
- { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_central_discover_remote_services_obj) },
-
- // Properties
- { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_central_connected_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table);
-
-const mp_obj_type_t bleio_central_type = {
- { &mp_type_type },
- .name = MP_QSTR_Central,
- .make_new = bleio_central_make_new,
- .locals_dict = (mp_obj_dict_t*)&bleio_central_locals_dict
-};
diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c
index 198155589..7fcf274da 100644
--- a/shared-bindings/_bleio/Characteristic.c
+++ b/shared-bindings/_bleio/Characteristic.c
@@ -45,8 +45,8 @@
//|
//| There is no regular constructor for a Characteristic. A new local Characteristic can be created
//| and attached to a Service by calling `add_to_service()`.
-//| Remote Characteristic objects are created by `Central.discover_remote_services()`
-//| or `Peripheral.discover_remote_services()` as part of remote Services.
+//| Remote Characteristic objects are created by `Connection.discover_remote_services()`
+//| as part of remote Services.
//|
//| .. 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)
@@ -94,12 +94,12 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_
const mp_obj_t service_obj = args[ARG_service].u_obj;
if (!MP_OBJ_IS_TYPE(service_obj, &bleio_service_type)) {
- mp_raise_ValueError(translate("Expected a Service"));
+ mp_raise_TypeError(translate("Expected a Service"));
}
const mp_obj_t uuid_obj = args[ARG_uuid].u_obj;
if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) {
- mp_raise_ValueError(translate("Expected a UUID"));
+ mp_raise_TypeError(translate("Expected a UUID"));
}
const bleio_characteristic_properties_t properties = args[ARG_properties].u_int;
@@ -134,12 +134,10 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_
// Range checking on max_length arg is done by the common_hal layer, because
// it may vary depending on underlying BLE implementation.
common_hal_bleio_characteristic_construct(
- characteristic, MP_OBJ_TO_PTR(service_obj), MP_OBJ_TO_PTR(uuid_obj),
+ characteristic, MP_OBJ_TO_PTR(service_obj), 0, MP_OBJ_TO_PTR(uuid_obj),
properties, read_perm, write_perm,
max_length, fixed_length, &initial_value_bufinfo);
- common_hal_bleio_service_add_characteristic(service_obj, characteristic);
-
return MP_OBJ_FROM_PTR(characteristic);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_add_to_service_fun_obj, 3, bleio_characteristic_add_to_service);
@@ -170,7 +168,8 @@ const mp_obj_property_t bleio_characteristic_properties_obj = {
//| .. attribute:: uuid
//|
//| The UUID of this characteristic. (read-only)
-//| Will be ``None`` if the 128-bit UUID for this characteristic is not known.
+//|
+//| Will be ``None`` if the 128-bit UUID for this characteristic is not known.
//|
STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) {
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -194,7 +193,9 @@ const mp_obj_property_t bleio_characteristic_uuid_obj = {
STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) {
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return common_hal_bleio_characteristic_get_value(self);
+ uint8_t temp[512];
+ size_t actual_len = common_hal_bleio_characteristic_get_value(self, temp, sizeof(temp));
+ return mp_obj_new_bytearray(actual_len, temp);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value);
@@ -224,8 +225,20 @@ const mp_obj_property_t bleio_characteristic_value_obj = {
STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) {
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
// Return list as a tuple so user won't be able to change it.
- mp_obj_list_t *char_list = common_hal_bleio_characteristic_get_descriptor_list(self);
- return mp_obj_new_tuple(char_list->len, char_list->items);
+ bleio_descriptor_obj_t *descriptors = common_hal_bleio_characteristic_get_descriptor_list(self);
+ bleio_descriptor_obj_t *head = descriptors;
+ size_t len = 0;
+ while (head != NULL) {
+ len++;
+ head = head->next;
+ }
+ mp_obj_tuple_t * t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
+ head = descriptors;
+ for (size_t i = len - 1; i >= 0; i--) {
+ t->items[i] = MP_OBJ_FROM_PTR(head);
+ head = head->next;
+ }
+ return MP_OBJ_FROM_PTR(t);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors);
@@ -282,7 +295,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_ch
STATIC const mp_rom_map_elem_t bleio_characteristic_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_add_to_service), MP_ROM_PTR(&bleio_characteristic_add_to_service_obj) },
- { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties_obj) },
+ { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_properties_obj) },
{ MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_characteristic_uuid_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_characteristic_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_obj) },
diff --git a/shared-bindings/_bleio/Characteristic.h b/shared-bindings/_bleio/Characteristic.h
index a816c6050..c4356fd4b 100644
--- a/shared-bindings/_bleio/Characteristic.h
+++ b/shared-bindings/_bleio/Characteristic.h
@@ -36,12 +36,12 @@
extern const mp_obj_type_t bleio_characteristic_type;
-extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, 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_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo);
-extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self);
+extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, 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_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo);
+extern size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t* buf, size_t len);
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_descriptor_obj_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_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor);
extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c
index 9cc708eb7..e7524da2d 100644
--- a/shared-bindings/_bleio/CharacteristicBuffer.c
+++ b/shared-bindings/_bleio/CharacteristicBuffer.c
@@ -30,13 +30,14 @@
#include "py/runtime.h"
#include "py/stream.h"
+#include "shared-bindings/_bleio/__init__.h"
#include "shared-bindings/_bleio/CharacteristicBuffer.h"
#include "shared-bindings/_bleio/UUID.h"
#include "shared-bindings/util.h"
STATIC void raise_error_if_not_connected(bleio_characteristic_buffer_obj_t *self) {
if (!common_hal_bleio_characteristic_buffer_connected(self)) {
- mp_raise_ValueError(translate("Not connected"));
+ mp_raise_bleio_ConnectionError(translate("Not connected"));
}
}
@@ -83,7 +84,7 @@ STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type,
}
if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) {
- mp_raise_ValueError(translate("Expected a Characteristic"));
+ mp_raise_TypeError(translate("Expected a Characteristic"));
}
bleio_characteristic_buffer_obj_t *self = m_new_obj(bleio_characteristic_buffer_obj_t);
@@ -151,9 +152,6 @@ STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t r
bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
raise_error_if_not_connected(self);
- if (!common_hal_bleio_characteristic_buffer_connected(self)) {
- mp_raise_ValueError(translate("Not connected"));
- }
mp_uint_t ret;
if (request == MP_IOCTL_POLL) {
mp_uint_t flags = arg;
diff --git a/shared-bindings/_bleio/Connection.c b/shared-bindings/_bleio/Connection.c
new file mode 100644
index 000000000..da2fbff28
--- /dev/null
+++ b/shared-bindings/_bleio/Connection.c
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2016 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared-bindings/_bleio/Connection.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "ble_drv.h"
+#include "py/objarray.h"
+#include "py/objproperty.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/__init__.h"
+#include "shared-bindings/_bleio/Adapter.h"
+#include "shared-bindings/_bleio/Address.h"
+#include "shared-bindings/_bleio/Characteristic.h"
+#include "shared-bindings/_bleio/Service.h"
+
+//| .. currentmodule:: _bleio
+//|
+//| :class:`Connection` -- A BLE connection
+//| =========================================================
+//|
+//| A BLE connection to another device. Used to discover and interact with services on the other
+//| device.
+//|
+//| Usage::
+//|
+//| import _bleio
+//|
+//| my_entry = None
+//| for entry in _bleio.adapter.scan(2.5):
+//| if entry.name is not None and entry.name == 'InterestingPeripheral':
+//| my_entry = entry
+//| break
+//|
+//| if not my_entry:
+//| raise Exception("'InterestingPeripheral' not found")
+//|
+//| connection = _bleio.adapter.connect(my_entry.address, timeout=10)
+//|
+
+STATIC void ensure_connected(bleio_connection_obj_t *self) {
+ if (!common_hal_bleio_connection_get_connected(self)) {
+ mp_raise_bleio_ConnectionError(translate("Connection has been disconnected and can no longer be used. Create a new connection."));
+ }
+}
+
+//| .. class:: Connection()
+//|
+//| Connections cannot be made directly. Instead, to initiate a connection use `Adapter.connect`.
+//| Connections may also be made when another device initiates a connection. To use a Connection
+//| created by a peer, read the `Adapter.connections` property.
+//|
+//| .. method:: disconnect()
+//|
+//| Disconnects from the remote peripheral.
+//|
+STATIC mp_obj_t bleio_connection_disconnect(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ ensure_connected(self);
+
+ common_hal_bleio_connection_disconnect(self->connection);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_disconnect_obj, bleio_connection_disconnect);
+
+
+//| .. method:: pair(*, bond=True)
+//|
+//| Pair to the peer to improve security.
+//|
+STATIC mp_obj_t bleio_connection_pair(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_bond };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bond, MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ ensure_connected(self);
+
+ common_hal_bleio_connection_pair(self->connection, args[ARG_bond].u_bool);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_connection_pair_obj, 1, bleio_connection_pair);
+
+//| .. method:: discover_remote_services(service_uuids_whitelist=None)
+//|
+//| Do BLE discovery for all services or for the given service UUIDS,
+//| to find their handles and characteristics, and return the discovered services.
+//| `Connection.connected` must be True.
+//|
+//| :param iterable service_uuids_whitelist:
+//|
+//| an iterable of :py:class:~`UUID` objects for the services provided by the peripheral
+//| that you want to use.
+//|
+//| The peripheral may provide more services, but services not listed are ignored
+//| and will not be returned.
+//|
+//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be
+//| slow.
+//|
+//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you
+//| you must have already created a :py:class:~`UUID` object for that UUID in order for the
+//| service or characteristic to be discovered. Creating the UUID causes the UUID to be
+//| registered for use. (This restriction may be lifted in the future.)
+//|
+//| :return: A tuple of `_bleio.Service` objects provided by the remote peripheral.
+//|
+STATIC mp_obj_t bleio_connection_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_service_uuids_whitelist };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ ensure_connected(self);
+
+ return MP_OBJ_FROM_PTR(common_hal_bleio_connection_discover_remote_services(
+ self,
+ args[ARG_service_uuids_whitelist].u_obj));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_connection_discover_remote_services_obj, 1, bleio_connection_discover_remote_services);
+
+//| .. attribute:: connected
+//|
+//| True if connected to the remote peer.
+//|
+STATIC mp_obj_t bleio_connection_get_connected(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_connection_get_connected(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_connected_obj, bleio_connection_get_connected);
+
+const mp_obj_property_t bleio_connection_connected_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_connection_get_connected_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
+
+//| .. attribute:: paired
+//|
+//| True if paired to the remote peer.
+//|
+STATIC mp_obj_t bleio_connection_get_paired(mp_obj_t self_in) {
+ bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_connection_get_paired(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_paired_obj, bleio_connection_get_paired);
+
+const mp_obj_property_t bleio_connection_paired_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_connection_get_paired_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
+STATIC const mp_rom_map_elem_t bleio_connection_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_connection_pair_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_connection_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_connection_discover_remote_services_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_connection_connected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paired), MP_ROM_PTR(&bleio_connection_paired_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(bleio_connection_locals_dict, bleio_connection_locals_dict_table);
+
+const mp_obj_type_t bleio_connection_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Connection,
+ .locals_dict = (mp_obj_dict_t*)&bleio_connection_locals_dict,
+ .unary_op = mp_generic_unary_op,
+};
diff --git a/shared-bindings/_bleio/Central.h b/shared-bindings/_bleio/Connection.h
index 85d788654..f7eee180f 100644
--- a/shared-bindings/_bleio/Central.h
+++ b/shared-bindings/_bleio/Connection.h
@@ -25,19 +25,19 @@
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
-#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
#include "py/objtuple.h"
-#include "common-hal/_bleio/Central.h"
+#include "common-hal/_bleio/Connection.h"
#include "common-hal/_bleio/Service.h"
-extern const mp_obj_type_t bleio_central_type;
+extern const mp_obj_type_t bleio_connection_type;
-extern void common_hal_bleio_central_construct(bleio_central_obj_t *self);
-extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout);
-extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self);
-extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self);
-extern mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist);
+extern void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond);
+extern void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self);
+extern bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self);
+extern bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self);
+extern mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist);
-#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H
diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c
index 0ab9fe8e9..f7b6b5bbf 100644
--- a/shared-bindings/_bleio/Descriptor.c
+++ b/shared-bindings/_bleio/Descriptor.c
@@ -46,9 +46,8 @@
//|
//| There is no regular constructor for a Descriptor. A new local Descriptor can be created
//| and attached to a Characteristic by calling `add_to_characteristic()`.
-//| Remote Descriptor objects are created by `Central.discover_remote_services()`
-//| or `Peripheral.discover_remote_services()` as part of remote Characteristics
-//| in the remote Services that are discovered.
+//| Remote Descriptor objects are created by `Connection.discover_remote_services()`
+//| as part of remote Characteristics in the remote Services that are discovered.
//|
//| .. classmethod:: add_to_characteristic(characteristic, uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, initial_value=b'')
//|
@@ -90,12 +89,12 @@ STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o
const mp_obj_t characteristic_obj = args[ARG_characteristic].u_obj;
if (!MP_OBJ_IS_TYPE(characteristic_obj, &bleio_characteristic_type)) {
- mp_raise_ValueError(translate("Expected a Characteristic"));
+ mp_raise_TypeError(translate("Expected a Characteristic"));
}
const mp_obj_t uuid_obj = args[ARG_uuid].u_obj;
if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) {
- mp_raise_ValueError(translate("Expected a UUID"));
+ mp_raise_TypeError(translate("Expected a UUID"));
}
const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int;
@@ -180,7 +179,9 @@ const mp_obj_property_t bleio_descriptor_characteristic_obj = {
STATIC mp_obj_t bleio_descriptor_get_value(mp_obj_t self_in) {
bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return common_hal_bleio_descriptor_get_value(self);
+ uint8_t temp[512];
+ size_t actual_len = common_hal_bleio_descriptor_get_value(self, temp, sizeof(temp));
+ return mp_obj_new_bytearray(actual_len, temp);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_value_obj, bleio_descriptor_get_value);
diff --git a/shared-bindings/_bleio/Descriptor.h b/shared-bindings/_bleio/Descriptor.h
index 7544bdb17..273cb1c1e 100644
--- a/shared-bindings/_bleio/Descriptor.h
+++ b/shared-bindings/_bleio/Descriptor.h
@@ -38,7 +38,7 @@ extern const mp_obj_type_t bleio_descriptor_type;
extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo);
extern bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self);
extern bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self);
-extern mp_obj_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self);
+extern size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t* buf, size_t len);
extern void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
diff --git a/shared-bindings/_bleio/Peripheral.c b/shared-bindings/_bleio/Peripheral.c
deleted file mode 100644
index 0bf292744..000000000
--- a/shared-bindings/_bleio/Peripheral.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Dan Halbert for Adafruit Industries
- * Copyright (c) 2018 Artur Pacholec
- * Copyright (c) 2016 Glenn Ruben Bakke
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include "ble_drv.h"
-#include "py/objarray.h"
-#include "py/objproperty.h"
-#include "py/objstr.h"
-#include "py/runtime.h"
-
-#include "shared-bindings/_bleio/Adapter.h"
-#include "shared-bindings/_bleio/Characteristic.h"
-#include "shared-bindings/_bleio/Peripheral.h"
-#include "shared-bindings/_bleio/Service.h"
-#include "shared-bindings/_bleio/UUID.h"
-#include "shared-module/_bleio/ScanEntry.h"
-
-#include "common-hal/_bleio/Peripheral.h"
-
-#define ADV_INTERVAL_MIN (0.0020f)
-#define ADV_INTERVAL_MIN_STRING "0.0020"
-#define ADV_INTERVAL_MAX (10.24f)
-#define ADV_INTERVAL_MAX_STRING "10.24"
-// 20ms is recommended by Apple
-#define ADV_INTERVAL_DEFAULT (0.1f)
-
-//| .. currentmodule:: _bleio
-//|
-//| :class:`Peripheral` -- A BLE peripheral device
-//| =========================================================
-//|
-//| Implement a BLE peripheral which runs locally.
-//| Set up using the supplied services, and then allow advertising to be started and stopped.
-//|
-//| Usage::
-//|
-//| from _bleio import Characteristic, Peripheral, Service
-//| from adafruit_ble.advertising import ServerAdvertisement
-//|
-//| # Create a peripheral and start it up.
-//| peripheral = _bleio.Peripheral()
-//|
-//| # Create a Service and add it to this Peripheral.
-//| service = Service.add_to_peripheral(peripheral, _bleio.UUID(0x180f))
-//|
-//| # Create a Characteristic and add it to the Service.
-//| characteristic = Characteristic.add_to_service(service,
-//| _bleio.UUID(0x2919), properties=Characteristic.READ | Characteristic.NOTIFY)
-//|
-//| adv = ServerAdvertisement(peripheral)
-//| peripheral.start_advertising(adv.advertising_data_bytes, scan_response=adv.scan_response_bytes)
-//|
-//| while not peripheral.connected:
-//| # Wait for connection.
-//| pass
-//|
-//| .. class:: Peripheral(name=None)
-//|
-//| Create a new Peripheral object.
-//|
-//| :param str name: The name used when advertising this peripheral. If name is None,
-//| _bleio.adapter.default_name will be used.
-//|
-STATIC mp_obj_t bleio_peripheral_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_name };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_name, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- bleio_peripheral_obj_t *self = m_new_obj(bleio_peripheral_obj_t);
- self->base.type = &bleio_peripheral_type;
-
- mp_obj_t name = args[ARG_name].u_obj;
- if (name == mp_const_none) {
- name = common_hal_bleio_adapter_get_default_name();
- } else if (!MP_OBJ_IS_STR(name)) {
- mp_raise_ValueError(translate("name must be a string"));
- }
-
- common_hal_bleio_peripheral_construct(self, name);
-
- return MP_OBJ_FROM_PTR(self);
-}
-
-//| .. attribute:: connected (read-only)
-//|
-//| True if connected to a BLE Central device.
-//|
-STATIC mp_obj_t bleio_peripheral_get_connected(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- return mp_obj_new_bool(common_hal_bleio_peripheral_get_connected(self));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_connected_obj, bleio_peripheral_get_connected);
-
-const mp_obj_property_t bleio_peripheral_connected_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_peripheral_get_connected_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. attribute:: services
-//|
-//| A tuple of :py:class:`Service` objects offered by this peripheral. (read-only)
-//|
-STATIC mp_obj_t bleio_peripheral_get_services(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
- // Return list as a tuple so user won't be able to change it.
- mp_obj_list_t *services_list = common_hal_bleio_peripheral_get_services(self);
- return mp_obj_new_tuple(services_list->len, services_list->items);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services);
-
-const mp_obj_property_t bleio_peripheral_services_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_peripheral_get_services_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. attribute:: name
-//|
-//| The peripheral's name, included when advertising. (read-only)
-//|
-STATIC mp_obj_t bleio_peripheral_get_name(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- return common_hal_bleio_peripheral_get_name(self);
-}
-MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_name_obj, bleio_peripheral_get_name);
-
-const mp_obj_property_t bleio_peripheral_name_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_peripheral_get_name_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. method:: start_advertising(data, *, scan_response=None, connectable=True, interval=0.1)
-//|
-//| Starts advertising the peripheral. The peripheral's name and
-//| services are included in the advertisement packets.
-//|
-//| :param buf data: advertising data packet bytes
-//| :param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed.
-//| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral.
-//| :param float interval: advertising interval, in seconds
-//|
-STATIC mp_obj_t bleio_peripheral_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
-
- enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_interval };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
- { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
- { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- mp_buffer_info_t data_bufinfo;
- mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ);
-
- // Pass an empty buffer if scan_response not provided.
- mp_buffer_info_t scan_response_bufinfo = { 0 };
- if (args[ARG_scan_response].u_obj != mp_const_none) {
- mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ);
- }
-
- if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
- args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT);
- }
-
- const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj);
- if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) {
- mp_raise_ValueError_varg(translate("interval must be in range %s-%s"),
- ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING);
- }
-
- common_hal_bleio_peripheral_start_advertising(self, args[ARG_connectable].u_bool, interval,
- &data_bufinfo, &scan_response_bufinfo);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_start_advertising_obj, 2, bleio_peripheral_start_advertising);
-
-//| .. method:: stop_advertising()
-//|
-//| Stop sending advertising packets.
-STATIC mp_obj_t bleio_peripheral_stop_advertising(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- common_hal_bleio_peripheral_stop_advertising(self);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_stop_advertising_obj, bleio_peripheral_stop_advertising);
-
-//| .. method:: disconnect()
-//|
-//| Disconnects from the remote central.
-//| Normally the central initiates a disconnection. Use this only
-//| if necessary for your application.
-//|
-STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- common_hal_bleio_peripheral_disconnect(self);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect);
-
-//| .. method:: discover_remote_services(service_uuids_whitelist=None)
-//| Do BLE discovery for all services or for the given service UUIDS,
-//| to find their handles and characteristics, and return the discovered services.
-//| `Peripheral.connected` must be True.
-//|
-//| :param iterable service_uuids_whitelist: an iterable of :py:class:~`UUID` objects for the services
-//| provided by the peripheral that you want to use.
-//| The peripheral may provide more services, but services not listed are ignored
-//| and will not be returned.
-//|
-//| If service_uuids_whitelist is None, then all services will undergo discovery, which can be slow.
-//|
-//| If the service UUID is 128-bit, or its characteristic UUID's are 128-bit, you
-//| you must have already created a :py:class:~`UUID` object for that UUID in order for the
-//| service or characteristic to be discovered. Creating the UUID causes the UUID to be registered
-//| for use. (This restriction may be lifted in the future.)
-//|
-//| Thought it is unusual for a peripheral to act as a BLE client, it can do so, and
-//| needs to be able to do discovery on its peer (a central).
-//| Examples include a peripheral accessing a central that provides Current Time Service,
-//| Apple Notification Center Service, or Battery Service.
-//|
-//| :return: A tuple of services provided by the remote central.
-//|
-STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
-
- enum { ARG_service_uuids_whitelist };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_service_uuids_whitelist, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- if (!common_hal_bleio_peripheral_get_connected(self)) {
- mp_raise_ValueError(translate("Not connected"));
- }
-
- return MP_OBJ_FROM_PTR(common_hal_bleio_peripheral_discover_remote_services(
- MP_OBJ_FROM_PTR(self),
- args[ARG_service_uuids_whitelist].u_obj));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services);
-
-//| .. method:: pair()
-//|
-//| Request pairing with connected central.
-STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) {
- bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- common_hal_bleio_peripheral_pair(self);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair);
-
-STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = {
- // Methods
- { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) },
- { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_peripheral_stop_advertising_obj) },
- { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_peripheral_disconnect_obj) },
- { MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_peripheral_discover_remote_services_obj) },
- { MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_peripheral_pair_obj) },
-
- // Properties
- { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) },
- { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_peripheral_name_obj) },
- { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(bleio_peripheral_locals_dict, bleio_peripheral_locals_dict_table);
-
-const mp_obj_type_t bleio_peripheral_type = {
- { &mp_type_type },
- .name = MP_QSTR_Peripheral,
- .make_new = bleio_peripheral_make_new,
- .locals_dict = (mp_obj_dict_t*)&bleio_peripheral_locals_dict
-};
diff --git a/shared-bindings/_bleio/Peripheral.h b/shared-bindings/_bleio/Peripheral.h
deleted file mode 100644
index bc56a9338..000000000
--- a/shared-bindings/_bleio/Peripheral.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Dan Halbert for Adafruit Industries
- * Copyright (c) 2018 Artur Pacholec
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H
-#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H
-
-#include "py/objtuple.h"
-#include "common-hal/_bleio/Peripheral.h"
-#include "common-hal/_bleio/Service.h"
-
-extern const mp_obj_type_t bleio_peripheral_type;
-
-extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_t name);
-extern void common_hal_bleio_peripheral_add_service(bleio_peripheral_obj_t *self, bleio_service_obj_t *service);
-extern mp_obj_list_t *common_hal_bleio_peripheral_get_services(bleio_peripheral_obj_t *self);
-extern bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self);
-extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self);
-extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo);
-extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device);
-extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device);
-extern mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist);
-extern void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *device);
-
-#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H
diff --git a/shared-bindings/_bleio/ScanEntry.c b/shared-bindings/_bleio/ScanEntry.c
index bec380d03..d03cd6fb5 100644
--- a/shared-bindings/_bleio/ScanEntry.c
+++ b/shared-bindings/_bleio/ScanEntry.c
@@ -29,6 +29,7 @@
#include <string.h>
#include "py/objproperty.h"
+#include "py/runtime.h"
#include "shared-bindings/_bleio/Address.h"
#include "shared-bindings/_bleio/ScanEntry.h"
#include "shared-bindings/_bleio/UUID.h"
@@ -36,14 +37,43 @@
//| .. currentmodule:: _bleio
//|
-//| :class:`ScanEntry` -- BLE scan response entry
+//| :class:`ScanEntry` -- BLE scan data
//| =========================================================
//|
-//| Encapsulates information about a device that was received as a
-//| response to a BLE scan request. This object may only be created
-//| by a `_bleio.Scanner`: it has no user-visible constructor.
+//| Encapsulates information about a device that was received during scanning. It can be
+//| advertisement or scan response data. This object may only be created by a `_bleio.ScanResults`:
+//| it has no user-visible constructor.
//|
+//| .. class:: ScanEntry()
+//|
+//| Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`.
+//|
+//| .. method:: matches(prefixes, *, all=True)
+//|
+//| Returns True if the ScanEntry matches all prefixes when ``all`` is True. This is stricter
+//| than the scan filtering which accepts any advertisements that match any of the prefixes
+//| where all is False.
+//|
+STATIC mp_obj_t bleio_scanentry_matches(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_prefixes, ARG_all };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_prefixes, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_all, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_prefixes].u_obj, &bufinfo, MP_BUFFER_READ);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_matches(self, bufinfo.buf, bufinfo.len, args[ARG_all].u_bool));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanentry_matches_obj, 2, bleio_scanentry_matches);
+
//| .. attribute:: address
//|
//| The address of the device (read-only), of type `_bleio.Address`.
@@ -95,11 +125,47 @@ const mp_obj_property_t bleio_scanentry_rssi_obj = {
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: connectable
+//|
+//| True if the device can be connected to. (read-only)
+//|
+STATIC mp_obj_t scanentry_get_connectable(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_get_connectable(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_connectable_obj, scanentry_get_connectable);
+
+const mp_obj_property_t bleio_scanentry_connectable_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_scanentry_get_connectable_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
+//| .. attribute:: scan_response
+//|
+//| True if the entry was a scan response. (read-only)
+//|
+STATIC mp_obj_t scanentry_get_scan_response(mp_obj_t self_in) {
+ bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_bleio_scanentry_get_scan_response(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_scan_response_obj, scanentry_get_scan_response);
+
+const mp_obj_property_t bleio_scanentry_scan_response_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_scanentry_get_scan_response_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) },
{ MP_ROM_QSTR(MP_QSTR_advertisement_bytes), MP_ROM_PTR(&bleio_scanentry_advertisement_bytes_obj) },
{ MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connectable), MP_ROM_PTR(&bleio_scanentry_connectable_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan_response), MP_ROM_PTR(&bleio_scanentry_scan_response_obj) },
+ { MP_ROM_QSTR(MP_QSTR_matches), MP_ROM_PTR(&bleio_scanentry_matches_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table);
diff --git a/shared-bindings/_bleio/ScanEntry.h b/shared-bindings/_bleio/ScanEntry.h
index 8af1f050a..9aeaf20d3 100644
--- a/shared-bindings/_bleio/ScanEntry.h
+++ b/shared-bindings/_bleio/ScanEntry.h
@@ -37,5 +37,8 @@ extern const mp_obj_type_t bleio_scanentry_type;
mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self);
mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self);
mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_get_connectable(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_get_scan_response(bleio_scanentry_obj_t *self);
+bool common_hal_bleio_scanentry_matches(bleio_scanentry_obj_t *self, uint8_t* prefixes, size_t prefixes_len, bool all);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H
diff --git a/shared-bindings/_bleio/ScanResults.c b/shared-bindings/_bleio/ScanResults.c
new file mode 100644
index 000000000..dcece3d5d
--- /dev/null
+++ b/shared-bindings/_bleio/ScanResults.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ * Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/_bleio/ScanResults.h"
+
+//| .. currentmodule:: _bleio
+//|
+//| :class:`ScanResults` -- An Iterator over BLE scanning results
+//| ===============================================================
+//|
+//| Iterates over advertising data received while scanning. This object is always created
+//| by a `_bleio.Adapter`: it has no user-visible constructor.
+//|
+STATIC mp_obj_t scanresults_iternext(mp_obj_t self_in) {
+ mp_check_self(MP_OBJ_IS_TYPE(self_in, &bleio_scanresults_type));
+ bleio_scanresults_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t scan_entry = common_hal_bleio_scanresults_next(self);
+ if (scan_entry != mp_const_none) {
+ return scan_entry;
+ }
+ return MP_OBJ_STOP_ITERATION;
+}
+
+//| .. class:: ScanResults()
+//|
+//| Cannot be instantiated directly. Use `_bleio.Adapter.start_scan`.
+//|
+//| .. method:: __iter__()
+//|
+//| Returns itself since it is the iterator.
+//|
+//| .. method:: __next__()
+//|
+//| Returns the next `_bleio.ScanEntry`. Blocks if none have been received and scanning is still
+//| active. Raises `StopIteration` if scanning is finished and no other results are available.
+//|
+
+const mp_obj_type_t bleio_scanresults_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ScanResults,
+ .getiter = mp_identity_getiter,
+ .iternext = scanresults_iternext,
+};
diff --git a/shared-bindings/_bleio/Scanner.h b/shared-bindings/_bleio/ScanResults.h
index cbaa77866..a8c88c215 100644
--- a/shared-bindings/_bleio/Scanner.h
+++ b/shared-bindings/_bleio/ScanResults.h
@@ -5,6 +5,7 @@
*
* Copyright (c) 2019 Dan Halbert for Adafruit Industries
* Copyright (c) 2018 Artur Pacholec
+ * Copyright (c) 2017 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,16 +26,14 @@
* THE SOFTWARE.
*/
-#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H
-#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
-#include "py/objtype.h"
-#include "common-hal/_bleio/Scanner.h"
+#include "py/obj.h"
+#include "shared-module/_bleio/ScanResults.h"
-extern const mp_obj_type_t bleio_scanner_type;
+extern const mp_obj_type_t bleio_scanresults_type;
-extern void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self);
-extern mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window);
-extern void common_hal_bleio_scanner_stop(bleio_scanner_obj_t *self);
+mp_obj_t common_hal_bleio_scanresults_next(bleio_scanresults_obj_t *self);
-#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANRESULTS_H
diff --git a/shared-bindings/_bleio/Scanner.c b/shared-bindings/_bleio/Scanner.c
deleted file mode 100644
index 94cec9752..000000000
--- a/shared-bindings/_bleio/Scanner.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Dan Halbert for Adafruit Industries
- * Copyright (c) 2018 Artur Pacholec
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/objproperty.h"
-#include "py/runtime.h"
-#include "shared-bindings/_bleio/ScanEntry.h"
-#include "shared-bindings/_bleio/Scanner.h"
-
-#define INTERVAL_DEFAULT (0.1f)
-#define INTERVAL_MIN (0.0025f)
-#define INTERVAL_MIN_STRING "0.0025"
-#define INTERVAL_MAX (40.959375f)
-#define INTERVAL_MAX_STRING "40.959375"
-#define WINDOW_DEFAULT (0.1f)
-
-//| .. currentmodule:: _bleio
-//|
-//| :class:`Scanner` -- scan for nearby BLE devices
-//| =========================================================
-//|
-//| Scan for nearby BLE devices.
-//|
-//| Usage::
-//|
-//| import _bleio
-//| scanner = _bleio.Scanner()
-//| entries = scanner.scan(2.5) # Scan for 2.5 seconds
-//|
-
-//| .. class:: Scanner()
-//|
-//| Create a new Scanner object.
-//|
-STATIC mp_obj_t bleio_scanner_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) {
- mp_arg_check_num(n_args, kw_args, 0, 0, false);
-
- bleio_scanner_obj_t *self = m_new_obj(bleio_scanner_obj_t);
- self->base.type = type;
-
- common_hal_bleio_scanner_construct(self);
-
- return MP_OBJ_FROM_PTR(self);
-}
-
-//| .. method:: scan(timeout, \*, interval=0.1, window=0.1)
-//|
-//| Performs a BLE scan.
-//|
-//| :param float timeout: the scan timeout in seconds
-//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows
-//| Must be in the range 0.0025 - 40.959375 seconds.
-//| :param float window: the duration (in seconds) to scan a single BLE channel.
-//| window must be <= interval.
-//| :returns: an iterable of `ScanEntry` objects
-//| :rtype: iterable
-//|
-STATIC mp_obj_t bleio_scanner_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_timeout, ARG_interval, ARG_window };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ },
- { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- };
-
- bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- const mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
-
- if (args[ARG_interval].u_obj == MP_OBJ_NULL) {
- args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT);
- }
-
- if (args[ARG_window].u_obj == MP_OBJ_NULL) {
- args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT);
- }
-
- const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj);
- if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
- mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING);
- }
-
- const mp_float_t window = mp_obj_float_get(args[ARG_window].u_obj);
- if (window > interval) {
- mp_raise_ValueError(translate("window must be <= interval"));
- }
-
- return common_hal_bleio_scanner_scan(self, timeout, interval, window);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanner_scan_obj, 2, bleio_scanner_scan);
-
-
-STATIC const mp_rom_map_elem_t bleio_scanner_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bleio_scanner_scan_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict_table);
-
-const mp_obj_type_t bleio_scanner_type = {
- { &mp_type_type },
- .name = MP_QSTR_Scanner,
- .make_new = bleio_scanner_make_new,
- .locals_dict = (mp_obj_dict_t*)&bleio_scanner_locals_dict
-};
diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c
index da5633f2a..43679393a 100644
--- a/shared-bindings/_bleio/Service.c
+++ b/shared-bindings/_bleio/Service.c
@@ -29,58 +29,42 @@
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared-bindings/_bleio/Characteristic.h"
-#include "shared-bindings/_bleio/Peripheral.h"
#include "shared-bindings/_bleio/Service.h"
#include "shared-bindings/_bleio/UUID.h"
//| .. currentmodule:: _bleio
//|
-//| :class:`Service` -- BLE service
+//| :class:`Service` -- BLE GATT Service
//| =========================================================
//|
//| Stores information about a BLE service and its characteristics.
//|
-//| .. class:: Service
+//| .. class:: Service(uuid, *, secondary=False)
//|
-//| There is no regular constructor for a Service. A new local Service can be created
-//| and attached to a Peripheral by calling `add_to_peripheral()`.
-//| Remote Service objects are created by `Central.discover_remote_services()`
-//| or `Peripheral.discover_remote_services()`.
+//| Create a new Service identified by the specified UUID. It can be accessed by all
+//| connections. This is known as a Service server. Client Service objects are created via
+//| `Connection.discover_remote_services`.
//|
-//| .. classmethod:: add_to_peripheral(peripheral, uuid, *, secondary=False)
+//| To mark the Service as secondary, pass `True` as :py:data:`secondary`.
//|
-//| Create a new Service object, identitied by the specified UUID, and add it
-//| to the given Peripheral.
-//|
-//| To mark the service as secondary, pass `True` as :py:data:`secondary`.
-//|
-//| :param Peripheral peripheral: The peripheral that will provide this service
-//| :param UUID uuid: The uuid of the service
-//| :param bool secondary: If the service is a secondary one
+//| :param UUID uuid: The uuid of the service
+//| :param bool secondary: If the service is a secondary one
//
-//| :return: the new Service
+//| :return: the new Service
//|
-STATIC mp_obj_t bleio_service_add_to_peripheral(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- // class is arg[0], which we can ignore.
-
- enum { ARG_peripheral, ARG_uuid, ARG_secondary };
+STATIC mp_obj_t bleio_service_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_secondary };
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_peripheral, MP_ARG_REQUIRED | MP_ARG_OBJ,},
{ MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_secondary, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- const mp_obj_t peripheral_obj = args[ARG_peripheral].u_obj;
- if (!MP_OBJ_IS_TYPE(peripheral_obj, &bleio_peripheral_type)) {
- mp_raise_ValueError(translate("Expected a Peripheral"));
- }
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mp_obj_t uuid_obj = args[ARG_uuid].u_obj;
if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) {
- mp_raise_ValueError(translate("Expected a UUID"));
+ mp_raise_TypeError(translate("Expected a UUID"));
}
const bool is_secondary = args[ARG_secondary].u_bool;
@@ -88,19 +72,15 @@ STATIC mp_obj_t bleio_service_add_to_peripheral(size_t n_args, const mp_obj_t *p
bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
service->base.type = &bleio_service_type;
- common_hal_bleio_service_construct(
- service, MP_OBJ_TO_PTR(peripheral_obj), MP_OBJ_TO_PTR(uuid_obj), is_secondary);
-
- common_hal_bleio_peripheral_add_service(peripheral_obj, service);
+ common_hal_bleio_service_construct(service, MP_OBJ_TO_PTR(uuid_obj), is_secondary);
return MP_OBJ_FROM_PTR(service);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_service_add_to_peripheral_fun_obj, 3, bleio_service_add_to_peripheral);
-STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(bleio_service_add_to_peripheral_obj, MP_ROM_PTR(&bleio_service_add_to_peripheral_fun_obj));
//| .. attribute:: characteristics
//|
-//| A tuple of :py:class:`Characteristic` designating the characteristics that are offered by this service. (read-only)
+//| A tuple of :py:class:`Characteristic` designating the characteristics that are offered by
+//| this service. (read-only)
//|
STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) {
bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -156,7 +136,8 @@ const mp_obj_property_t bleio_service_secondary_obj = {
//| .. attribute:: uuid
//|
//| The UUID of this service. (read-only)
-//| Will be ``None`` if the 128-bit UUID for this service is not known.
+//|
+//| Will be ``None`` if the 128-bit UUID for this service is not known.
//|
STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) {
bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -175,10 +156,10 @@ const mp_obj_property_t bleio_service_uuid_obj = {
STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_add_to_peripheral), MP_ROM_PTR(&bleio_service_add_to_peripheral_obj) },
{ MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) },
{ MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) },
{ MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remote), MP_ROM_PTR(&bleio_service_remote_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table);
@@ -196,6 +177,25 @@ STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
const mp_obj_type_t bleio_service_type = {
{ &mp_type_type },
.name = MP_QSTR_Service,
+ .make_new = bleio_service_make_new,
.print = bleio_service_print,
.locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict
};
+
+// Helper for classes that store lists of services.
+mp_obj_tuple_t* service_linked_list_to_tuple(bleio_service_obj_t * services) {
+ // Return list as a tuple so user won't be able to change it.
+ bleio_service_obj_t *head = services;
+ size_t len = 0;
+ while (head != NULL) {
+ len++;
+ head = head->next;
+ }
+ mp_obj_tuple_t * t = MP_OBJ_TO_PTR(mp_obj_new_tuple(len, NULL));
+ head = services;
+ for (int32_t i = len - 1; i >= 0; i--) {
+ t->items[i] = MP_OBJ_FROM_PTR(head);
+ head = head->next;
+ }
+ return t;
+}
diff --git a/shared-bindings/_bleio/Service.h b/shared-bindings/_bleio/Service.h
index e061bcffc..273c6bd98 100644
--- a/shared-bindings/_bleio/Service.h
+++ b/shared-bindings/_bleio/Service.h
@@ -28,16 +28,24 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
-#include "common-hal/_bleio/Peripheral.h"
+#include "common-hal/_bleio/Characteristic.h"
+#include "common-hal/_bleio/Connection.h"
#include "common-hal/_bleio/Service.h"
+#include "py/objtuple.h"
+
const mp_obj_type_t bleio_service_type;
-extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_peripheral_obj_t *peripheral, bleio_uuid_obj_t *uuid, bool is_secondary);
+// Private version that doesn't allocate on the heap
+extern uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t * characteristic_list);
+extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary);
+extern void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, bleio_connection_obj_t* connection, bleio_uuid_obj_t *uuid, bool is_secondary);
extern bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self);
extern mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_obj_t *self);
extern bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self);
extern bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self);
-extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic);
+extern void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo);
+
+mp_obj_tuple_t* service_linked_list_to_tuple(bleio_service_obj_t * services);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H
diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c
index 3c0889aad..dd3415902 100644
--- a/shared-bindings/_bleio/UUID.c
+++ b/shared-bindings/_bleio/UUID.c
@@ -156,9 +156,10 @@ STATIC mp_obj_t bleio_uuid_get_uuid128(mp_obj_t self_in) {
bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in);
uint8_t uuid128[16];
- if (!common_hal_bleio_uuid_get_uuid128(self, uuid128)) {
+ if (common_hal_bleio_uuid_get_size(self) != 128) {
mp_raise_AttributeError(translate("not a 128-bit UUID"));
}
+ common_hal_bleio_uuid_get_uuid128(self, uuid128);
return mp_obj_new_bytes(uuid128, 16);
}
@@ -192,10 +193,42 @@ const mp_obj_property_t bleio_uuid_size_obj = {
(mp_obj_t)&mp_const_none_obj},
};
+
+//| .. method:: pack_into(buffer, offset=0)
+//|
+//| Packs the UUID into the given buffer at the given offset.
+//|
+STATIC mp_obj_t bleio_uuid_pack_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+
+ enum { ARG_buffer, ARG_offset };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
+
+ size_t offset = args[ARG_offset].u_int;
+ if (offset + common_hal_bleio_uuid_get_size(self) / 8 > bufinfo.len) {
+ mp_raise_ValueError(translate("Buffer + offset too small %d %d %d"));
+ }
+
+ common_hal_bleio_uuid_pack_into(self, bufinfo.buf + offset);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_uuid_pack_into_obj, 2, bleio_uuid_pack_into);
+
STATIC const mp_rom_map_elem_t bleio_uuid_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_uuid16), MP_ROM_PTR(&bleio_uuid_uuid16_obj) },
{ MP_ROM_QSTR(MP_QSTR_uuid128), MP_ROM_PTR(&bleio_uuid_uuid128_obj) },
{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&bleio_uuid_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pack_into), MP_ROM_PTR(&bleio_uuid_pack_into_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_uuid_locals_dict, bleio_uuid_locals_dict_table);
@@ -231,13 +264,19 @@ STATIC mp_obj_t bleio_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
//|
STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
switch (op) {
- // Two UUID's are equal if their uuid16 values and uuid128 references match.
+ // Two UUID's are equal if their uuid16 values match or their uuid128 values match.
case MP_BINARY_OP_EQUAL:
if (MP_OBJ_IS_TYPE(rhs_in, &bleio_uuid_type)) {
- return mp_obj_new_bool(
- common_hal_bleio_uuid_get_uuid16(lhs_in) == common_hal_bleio_uuid_get_uuid16(rhs_in) &&
- common_hal_bleio_uuid_get_uuid128_reference(lhs_in) ==
- common_hal_bleio_uuid_get_uuid128_reference(rhs_in));
+ if (common_hal_bleio_uuid_get_size(lhs_in) == 16 &&
+ common_hal_bleio_uuid_get_size(rhs_in) == 16) {
+ return mp_obj_new_bool(common_hal_bleio_uuid_get_uuid16(lhs_in) ==
+ common_hal_bleio_uuid_get_uuid16(rhs_in));
+ }
+ uint8_t lhs[16];
+ uint8_t rhs[16];
+ common_hal_bleio_uuid_get_uuid128(lhs_in, lhs);
+ common_hal_bleio_uuid_get_uuid128(rhs_in, rhs);
+ return mp_obj_new_bool(memcmp(lhs, rhs, sizeof(lhs)) == 0);
} else {
return mp_const_false;
}
diff --git a/shared-bindings/_bleio/UUID.h b/shared-bindings/_bleio/UUID.h
index 46ac54ff3..1490737a7 100644
--- a/shared-bindings/_bleio/UUID.h
+++ b/shared-bindings/_bleio/UUID.h
@@ -34,10 +34,11 @@ void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
extern const mp_obj_type_t bleio_uuid_type;
-extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, uint8_t uuid128[]);
+extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[]);
extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self);
extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]);
-extern uint32_t common_hal_bleio_uuid_get_uuid128_reference(bleio_uuid_obj_t *self);
extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self);
+void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf);
+
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_UUID_H
diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c
index f207be8cf..ba2454da4 100644
--- a/shared-bindings/_bleio/__init__.c
+++ b/shared-bindings/_bleio/__init__.c
@@ -26,16 +26,17 @@
* THE SOFTWARE.
*/
+#include "py/objexcept.h"
+#include "py/runtime.h"
#include "shared-bindings/_bleio/__init__.h"
#include "shared-bindings/_bleio/Address.h"
#include "shared-bindings/_bleio/Attribute.h"
-#include "shared-bindings/_bleio/Central.h"
#include "shared-bindings/_bleio/Characteristic.h"
#include "shared-bindings/_bleio/CharacteristicBuffer.h"
+#include "shared-bindings/_bleio/Connection.h"
#include "shared-bindings/_bleio/Descriptor.h"
-#include "shared-bindings/_bleio/Peripheral.h"
#include "shared-bindings/_bleio/ScanEntry.h"
-#include "shared-bindings/_bleio/Scanner.h"
+#include "shared-bindings/_bleio/ScanResults.h"
#include "shared-bindings/_bleio/Service.h"
#include "shared-bindings/_bleio/UUID.h"
@@ -64,43 +65,108 @@
//| Address
//| Adapter
//| Attribute
-//| Central
//| Characteristic
//| CharacteristicBuffer
+//| Connection
//| Descriptor
-//| Peripheral
//| ScanEntry
-//| Scanner
+//| ScanResults
//| Service
//| UUID
//|
//| .. attribute:: adapter
//|
-//| BLE Adapter information, such as enabled state as well as MAC
-//| address.
+//| BLE Adapter used to manage device discovery and connections.
//| This object is the sole instance of `_bleio.Adapter`.
//|
+//| .. class:: BluetoothError(Exception)
+//|
+//| Catch all exception for Bluetooth related errors.
+//|
+MP_DEFINE_BLEIO_EXCEPTION(BluetoothError, Exception)
+
+NORETURN void mp_raise_bleio_BluetoothError(const compressed_string_t* fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_BluetoothError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+//| .. class:: ConnectionError(BluetoothError)
+//|
+//| Raised when a connection is unavailable.
+//|
+MP_DEFINE_BLEIO_EXCEPTION(ConnectionError, bleio_BluetoothError)
+NORETURN void mp_raise_bleio_ConnectionError(const compressed_string_t* fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_ConnectionError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
+//| .. class:: RoleError(BluetoothError)
+//|
+//| Raised when a resource is used as the mismatched role. For example, if a local CCCD is
+//| attempted to be set but they can only be set when remote.
+//|
+MP_DEFINE_BLEIO_EXCEPTION(RoleError, bleio_BluetoothError)
+NORETURN void mp_raise_bleio_RoleError(const compressed_string_t* msg) {
+ mp_raise_msg(&mp_type_bleio_RoleError, msg);
+}
+
+//| .. class:: SecurityError(BluetoothError)
+//|
+//| Raised when a security related error occurs.
+//|
+MP_DEFINE_BLEIO_EXCEPTION(SecurityError, bleio_BluetoothError)
+NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* fmt, ...) {
+ va_list argptr;
+ va_start(argptr,fmt);
+ mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_SecurityError, fmt, argptr);
+ va_end(argptr);
+ nlr_raise(exception);
+}
+
STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = {
+ // Name must be the first entry so that the exception printing below is correct.
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__bleio) },
+ { MP_ROM_QSTR(MP_QSTR_Adapter), MP_ROM_PTR(&bleio_adapter_type) },
{ MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) },
{ MP_ROM_QSTR(MP_QSTR_Attribute), MP_ROM_PTR(&bleio_attribute_type) },
- { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_type) },
+ { MP_ROM_QSTR(MP_QSTR_Connection), MP_ROM_PTR(&bleio_connection_type) },
{ MP_ROM_QSTR(MP_QSTR_Characteristic), MP_ROM_PTR(&bleio_characteristic_type) },
{ MP_ROM_QSTR(MP_QSTR_CharacteristicBuffer), MP_ROM_PTR(&bleio_characteristic_buffer_type) },
{ MP_ROM_QSTR(MP_QSTR_Descriptor), MP_ROM_PTR(&bleio_descriptor_type) },
- { MP_ROM_QSTR(MP_QSTR_Peripheral), MP_ROM_PTR(&bleio_peripheral_type) },
{ MP_ROM_QSTR(MP_QSTR_ScanEntry), MP_ROM_PTR(&bleio_scanentry_type) },
- { MP_ROM_QSTR(MP_QSTR_Scanner), MP_ROM_PTR(&bleio_scanner_type) },
+ { MP_ROM_QSTR(MP_QSTR_ScanResults), MP_ROM_PTR(&bleio_scanresults_type) },
{ MP_ROM_QSTR(MP_QSTR_Service), MP_ROM_PTR(&bleio_service_type) },
{ MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) },
// Properties
{ MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) },
+
+ // Errors
+ { MP_ROM_QSTR(MP_QSTR_BluetoothError), MP_ROM_PTR(&mp_type_bleio_BluetoothError) },
+ { MP_ROM_QSTR(MP_QSTR_ConnectionError), MP_ROM_PTR(&mp_type_bleio_ConnectionError) },
+ { MP_ROM_QSTR(MP_QSTR_RoleError), MP_ROM_PTR(&mp_type_bleio_RoleError) },
+ { MP_ROM_QSTR(MP_QSTR_SecurityError), MP_ROM_PTR(&mp_type_bleio_SecurityError) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table);
+void bleio_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
+ mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS;
+ bool is_subclass = kind & PRINT_EXC_SUBCLASS;
+ if (!is_subclass && (k == PRINT_EXC)) {
+ mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(bleio_module_globals_table[0].value)));
+ mp_print_str(print, ".");
+ }
+ mp_obj_exception_print(print, o_in, kind);
+}
+
const mp_obj_module_t bleio_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&bleio_module_globals,
diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h
index 67379ae2e..5256bdaa0 100644
--- a/shared-bindings/_bleio/__init__.h
+++ b/shared-bindings/_bleio/__init__.h
@@ -36,17 +36,41 @@
#include "common-hal/_bleio/__init__.h"
#include "common-hal/_bleio/Adapter.h"
-extern const super_adapter_obj_t common_hal_bleio_adapter_obj;
+extern bleio_adapter_obj_t common_hal_bleio_adapter_obj;
-extern void common_hal_bleio_check_connected(uint16_t conn_handle);
+void bleio_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind);
-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_service_list(mp_obj_t device);
-extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist);
+#define MP_DEFINE_BLEIO_EXCEPTION(exc_name, base_name) \
+const mp_obj_type_t mp_type_bleio_ ## exc_name = { \
+ { &mp_type_type }, \
+ .name = MP_QSTR_ ## exc_name, \
+ .print = bleio_exception_print, \
+ .make_new = mp_obj_exception_make_new, \
+ .attr = mp_obj_exception_attr, \
+ .parent = &mp_type_ ## base_name, \
+};
-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);
+extern const mp_obj_type_t mp_type_bleio_BluetoothError;
+extern const mp_obj_type_t mp_type_bleio_ConnectionError;
+extern const mp_obj_type_t mp_type_bleio_RoleError;
+extern const mp_obj_type_t mp_type_bleio_SecurityError;
+NORETURN void mp_raise_bleio_BluetoothError(const compressed_string_t* msg, ...);
+NORETURN void mp_raise_bleio_ConnectionError(const compressed_string_t* msg, ...);
+NORETURN void mp_raise_bleio_RoleError(const compressed_string_t* msg);
+NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* msg, ...);
+
+void common_hal_bleio_check_connected(uint16_t conn_handle);
+
+uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device);
+mp_obj_list_t *common_hal_bleio_device_get_remote_service_list(mp_obj_t device);
+void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist);
+
+size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len);
+void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo);
+size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t* buf, size_t len);
+void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response);
+
+void common_hal_bleio_gc_collect(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
diff --git a/shared-bindings/_pixelbuf/__init__.c b/shared-bindings/_pixelbuf/__init__.c
index 48b9f1cef..eb0cb2984 100644
--- a/shared-bindings/_pixelbuf/__init__.c
+++ b/shared-bindings/_pixelbuf/__init__.c
@@ -55,7 +55,7 @@
//| .. class:: ByteOrder()
//|
-//| Classes representing byteorders for circuitpython
+//| Classes representing byteorders for CircuitPython
//| .. attribute:: bpp
@@ -284,7 +284,7 @@ PIXELBUF_BYTEORDER(LBRG, 4, 3, 1, 2, 0, false, true)
//| * **bpp** 4
//| * **has_luminosity** True
//|
-//| Actual format commonly used by DotStar (5 bit luninance value)
+//| Actual format commonly used by DotStar (5 bit luminance value)
PIXELBUF_BYTEORDER(LBGR, 4, 3, 2, 1, 0, false, true)
STATIC const mp_rom_map_elem_t pixelbuf_module_globals_table[] = {
diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c
index 2cd2b6728..8f7382fde 100644
--- a/shared-bindings/audiobusio/I2SOut.c
+++ b/shared-bindings/audiobusio/I2SOut.c
@@ -62,7 +62,7 @@
//| import time
//| import math
//|
-//| # Generate one period of sine wav.
+//| # Generate one period of sine wave.
//| length = 8000 // 440
//| sine_wave = array.array("H", [0] * length)
//| for i in range(length):
@@ -117,7 +117,7 @@ STATIC mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_a
assert_pin(data_obj, false);
const mcu_pin_obj_t *data = MP_OBJ_TO_PTR(data_obj);
- audiobusio_i2sout_obj_t *self = m_new_obj(audiobusio_i2sout_obj_t);
+ audiobusio_i2sout_obj_t *self = m_new_obj_with_finaliser(audiobusio_i2sout_obj_t);
self->base.type = &audiobusio_i2sout_type;
common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, args[ARG_left_justified].u_bool);
@@ -268,6 +268,7 @@ const mp_obj_property_t audiobusio_i2sout_paused_obj = {
STATIC const mp_rom_map_elem_t audiobusio_i2sout_locals_dict_table[] = {
// Methods
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiobusio_i2sout_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiobusio_i2sout_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiobusio_i2sout___exit___obj) },
diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c
index 7fa37d5c5..02a5fe1ee 100644
--- a/shared-bindings/audioio/__init__.c
+++ b/shared-bindings/audioio/__init__.c
@@ -68,7 +68,7 @@
//|
//| For compatibility with CircuitPython 4.x, some builds allow the items in
//| `audiocore` to be imported from `audioio`. This will be removed for all
-//| boards in a future build of CicuitPython.
+//| boards in a future build of CircuitPython.
//|
STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = {
diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c
index 47e2d64bc..3dda59fb8 100644
--- a/shared-bindings/board/__init__.c
+++ b/shared-bindings/board/__init__.c
@@ -93,6 +93,12 @@ MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi);
//|
//| Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton.
//|
+//| The object created uses the default parameter values for `busio.UART`. If you need to set
+//| parameters that are not changeable after creation, such as ``receiver_buffer_size``,
+//| do not use `board.UART()`; instead create a `busio.UART` object explicitly with the
+//| desired parameters.
+//|
+//|
#if BOARD_UART
mp_obj_t board_uart(void) {
mp_obj_t singleton = common_hal_board_get_uart();
diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c
index 3bd89e2e2..50a95beb2 100644
--- a/shared-bindings/busio/I2C.c
+++ b/shared-bindings/busio/I2C.c
@@ -60,6 +60,10 @@
//| :param int frequency: The clock frequency in Hertz
//| :param int timeout: The maximum clock stretching timeut - (used only for bitbangio.I2C; ignored for busio.I2C)
//|
+//| .. note:: On the nRF52840, only one I2C object may be created,
+//| except on the Circuit Playground Bluefruit, which allows two,
+//| one for the onboard accelerometer, and one for offboard use.
+//|
STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t);
self->base.type = &busio_i2c_type;
diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c
index d47bf499a..d1791bef3 100644
--- a/shared-bindings/busio/SPI.c
+++ b/shared-bindings/busio/SPI.c
@@ -154,11 +154,12 @@ STATIC void check_for_deinit(busio_spi_obj_t *self) {
//| within spec for the SAMD21.
//|
//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz,
-//| and 8MHz. 16MHz and 32MHz are also available, but only on the first
-//| `busio.SPI` object you create. Two more ``busio.SPI`` objects can be created, but they are restricted
-//| to 8MHz maximum. This is a hardware restriction: there is only one high-speed SPI peripheral.
+//| and 8MHz.
//| If you pick a a baudrate other than one of these, the nearest lower
//| baudrate will be chosen, with a minimum of 125kHz.
+//| Two SPI objects may be created, except on the Circuit Playground Bluefruit,
+//| which allows only one (to allow for an additional I2C object).
+//|
STATIC mp_obj_t busio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits };
static const mp_arg_t allowed_args[] = {
diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c
index c7eef8c43..7a3b48e89 100644
--- a/shared-bindings/busio/UART.c
+++ b/shared-bindings/busio/UART.c
@@ -57,7 +57,7 @@
//| :param int bits: the number of bits per byte, 7, 8 or 9.
//| :param Parity parity: the parity used for error checking.
//| :param int stop: the number of stop bits, 1 or 2.
-//| :param float timeout: the timeout in seconds to wait for the first character and between subsequent characters. Raises ``ValueError`` if timeout >100 seconds.
+//| :param float timeout: the timeout in seconds to wait for the first character and between subsequent characters when reading. Raises ``ValueError`` if timeout >100 seconds.
//| :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.)
//|
//| *New in CircuitPython 4.0:* ``timeout`` has incompatibly changed units from milliseconds to seconds.
@@ -69,6 +69,12 @@ typedef struct {
extern const busio_uart_parity_obj_t busio_uart_parity_even_obj;
extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj;
+STATIC void validate_timeout(mp_float_t timeout) {
+ if (timeout < (mp_float_t) 0.0f || timeout > (mp_float_t) 100.0f) {
+ mp_raise_ValueError(translate("timeout must be 0.0-100.0 seconds"));
+ }
+}
+
STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// Always initially allocate the UART object within the long-lived heap.
// This is needed to avoid crashes with certain UART implementations which
@@ -116,9 +122,7 @@ STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, co
}
mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj);
- if (timeout > (mp_float_t)100.0) {
- mp_raise_ValueError(translate("timeout >100 (units are now seconds, not msecs)"));
- }
+ validate_timeout(timeout);
common_hal_busio_uart_construct(self, tx, rx,
args[ARG_baudrate].u_int, bits, parity, stop, timeout,
@@ -286,6 +290,35 @@ const mp_obj_property_t busio_uart_in_waiting_obj = {
(mp_obj_t)&mp_const_none_obj},
};
+//| .. attribute:: timeout
+//|
+//| The current timeout, in seconds (float).
+//|
+STATIC mp_obj_t busio_uart_obj_get_timeout(mp_obj_t self_in) {
+ busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_float(common_hal_busio_uart_get_timeout(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_timeout_obj, busio_uart_obj_get_timeout);
+
+STATIC mp_obj_t busio_uart_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout) {
+ busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ mp_float_t timeout_float = mp_obj_get_float(timeout);
+ validate_timeout(timeout_float);
+ common_hal_busio_uart_set_timeout(self, timeout_float);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(busio_uart_set_timeout_obj, busio_uart_obj_set_timeout);
+
+
+const mp_obj_property_t busio_uart_timeout_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&busio_uart_get_timeout_obj,
+ (mp_obj_t)&busio_uart_set_timeout_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
//| .. method:: reset_input_buffer()
//|
//| Discard any unread characters in the input buffer.
@@ -355,8 +388,9 @@ STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&busio_uart_reset_input_buffer_obj) },
// Properties
- { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
- { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) },
+ { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&busio_uart_baudrate_obj) },
+ { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&busio_uart_in_waiting_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&busio_uart_timeout_obj) },
// Nested Enum-like Classes.
{ MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) },
diff --git a/shared-bindings/busio/UART.h b/shared-bindings/busio/UART.h
index 776a996be..cfd2c800c 100644
--- a/shared-bindings/busio/UART.h
+++ b/shared-bindings/busio/UART.h
@@ -57,7 +57,8 @@ extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self,
extern uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self);
extern void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate);
-
+extern mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self);
+extern void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout);
extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self);
extern void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self);
diff --git a/shared-bindings/microcontroller/Pin.h b/shared-bindings/microcontroller/Pin.h
index ed831b258..2d15dd5c5 100644
--- a/shared-bindings/microcontroller/Pin.h
+++ b/shared-bindings/microcontroller/Pin.h
@@ -37,5 +37,7 @@ void assert_pin(mp_obj_t obj, bool none_ok);
void assert_pin_free(const mcu_pin_obj_t* pin);
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin);
+void common_hal_never_reset_pin(const mcu_pin_obj_t* pin);
+void common_hal_reset_pin(const mcu_pin_obj_t* pin);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PIN_H
diff --git a/shared-bindings/pulseio/PWMOut.c b/shared-bindings/pulseio/PWMOut.c
index 40981e0a8..53b88c61a 100644
--- a/shared-bindings/pulseio/PWMOut.c
+++ b/shared-bindings/pulseio/PWMOut.c
@@ -162,6 +162,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pwmout___exit___obj, 4, 4, pu
//| 16 bit value that dictates how much of one cycle is high (1) versus low
//| (0). 0xffff will always be high, 0 will always be low and 0x7fff will
//| be half high and then half low.
+//|
+//| Depending on how PWM is implemented on a specific board, the internal
+//| representation for duty cycle might have less than 16 bits of resolution.
+//| Reading this property will return the value from the internal representation,
+//| so it may differ from the value set.
STATIC mp_obj_t pulseio_pwmout_obj_get_duty_cycle(mp_obj_t self_in) {
pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
@@ -193,6 +198,12 @@ const mp_obj_property_t pulseio_pwmout_duty_cycle_obj = {
//| 32 bit value that dictates the PWM frequency in Hertz (cycles per
//| second). Only writeable when constructed with ``variable_frequency=True``.
//|
+//| Depending on how PWM is implemented on a specific board, the internal value
+//| for the PWM's duty cycle may need to be recalculated when the frequency
+//| changes. In these cases, the duty cycle is automatically recalculated
+//| from the original duty cycle value. This should happen without any need
+//| to manually re-set the duty cycle.
+//|
STATIC mp_obj_t pulseio_pwmout_obj_get_frequency(mp_obj_t self_in) {
pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
diff --git a/shared-bindings/rtc/RTC.c b/shared-bindings/rtc/RTC.c
index 17dccdb03..3ff09a4ec 100644
--- a/shared-bindings/rtc/RTC.c
+++ b/shared-bindings/rtc/RTC.c
@@ -57,7 +57,23 @@ STATIC mp_obj_t rtc_rtc_make_new(const mp_obj_type_t *type, size_t n_args, const
//| .. attribute:: datetime
//|
-//| The date and time of the RTC.
+//| The current date and time of the RTC as a `time.struct_time`.
+//|
+//| This must be set to the current date and time whenever the board loses power::
+//|
+//| import rtc
+//| import time
+//|
+//| r = rtc.RTC()
+//| r.datetime = rtctime.struct_time((2019, 5, 29, 15, 14, 15, 0, -1, -1))
+//|
+//|
+//| Once set, the RTC will automatically update this value as time passes. You can read this
+//| property to get a snapshot of the current time::
+//|
+//| current_time = r.datetime
+//| print(current_time)
+//| # struct_time(tm_year=2019, tm_month=5, ...)
//|
STATIC mp_obj_t rtc_rtc_obj_get_datetime(mp_obj_t self_in) {
timeutils_struct_time_t tm;
@@ -83,9 +99,10 @@ const mp_obj_property_t rtc_rtc_datetime_obj = {
//| .. attribute:: calibration
//|
-//| The RTC calibration value.
+//| The RTC calibration value as an `int`.
+//|
//| A positive value speeds up the clock and a negative value slows it down.
-//| Range and value is hardware specific, but one step is often approx. 1 ppm.
+//| Range and value is hardware specific, but one step is often approximately 1 ppm.
//|
STATIC mp_obj_t rtc_rtc_obj_get_calibration(mp_obj_t self_in) {
int calibration = common_hal_rtc_get_calibration();
diff --git a/shared-bindings/rtc/__init__.c b/shared-bindings/rtc/__init__.c
index ac67a7131..22eda9b66 100644
--- a/shared-bindings/rtc/__init__.c
+++ b/shared-bindings/rtc/__init__.c
@@ -36,12 +36,13 @@
//|
//| .. module:: rtc
//| :synopsis: Real Time Clock
-//| :platform: SAMD21
+//| :platform: SAMD21, SAMD51, nRF52
//|
-//| The `rtc` module provides support for a Real Time Clock.
-//| It also backs the `time.time()` and `time.localtime()` functions using the onboard RTC if present.
+//| The `rtc` module provides support for a Real Time Clock. You can access and manage the
+//| RTC using :class:`rtc.RTC`. It also backs the :func:`time.time` and :func:`time.localtime`
+//| functions using the onboard RTC if present.
//|
-//| Libraries
+//| Classes
//|
//| .. toctree::
//| :maxdepth: 3
@@ -63,10 +64,9 @@ mp_obj_t rtc_get_time_source_time(void) {
//| .. function:: set_time_source(rtc)
//|
-//| Sets the rtc time source used by time.localtime().
-//| The default is `rtc.RTC()`.
-//|
-//| Example usage::
+//| Sets the RTC time source used by :func:`time.localtime`.
+//| The default is :class:`rtc.RTC`, but it's useful to use this to override the
+//| time source for testing purposes. For example::
//|
//| import rtc
//| import time
diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c
index 2654de09a..b3e4604b5 100644
--- a/shared-bindings/time/__init__.c
+++ b/shared-bindings/time/__init__.c
@@ -85,9 +85,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
#if MICROPY_PY_COLLECTIONS
mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
if (n_args != 1 || (kw_args != NULL && kw_args->used > 0)) {
- mp_raise_TypeError(translate("time.struct_time() takes exactly 1 argument"));
+ return namedtuple_make_new(type, n_args, args, kw_args);
}
- if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple) || ((mp_obj_tuple_t*) MP_OBJ_TO_PTR(args[0]))->len != 9) {
+ if (mp_obj_get_type(args[0])->getiter != mp_obj_tuple_getiter || ((mp_obj_tuple_t*) MP_OBJ_TO_PTR(args[0]))->len != 9) {
mp_raise_TypeError(translate("time.struct_time() takes a 9-sequence"));
}