summaryrefslogtreecommitdiff
path: root/shared-bindings
diff options
context:
space:
mode:
authorsommersoft <sommersoft@gmail.com>2019-08-19 21:23:27 -0500
committersommersoft <sommersoft@gmail.com>2019-08-19 21:23:27 -0500
commit1b2996a75ea4ba6d6d8b20cebb749d5f18a83049 (patch)
tree1e4cfe0343280227f36d5fcbbc4e45983cb6c0f0 /shared-bindings
parent17190ae63e8a5fb43c99ca7f1f91bf684bdbc16e (diff)
parent0ddfbb0c20432458cc8020ab5ad7538e6813b60b (diff)
Merge branch 'master' of https://github.com/adafruit/circuitpython into mixer_voice
Diffstat (limited to 'shared-bindings')
-rw-r--r--shared-bindings/_stage/__init__.c18
-rw-r--r--shared-bindings/audiobusio/I2SOut.c9
-rw-r--r--shared-bindings/audiocore/Mixer.c2
-rw-r--r--shared-bindings/audiocore/RawSample.c5
-rw-r--r--shared-bindings/audiocore/WaveFile.c28
-rw-r--r--shared-bindings/audiocore/WaveFile.h2
-rw-r--r--shared-bindings/audioio/AudioOut.c7
-rw-r--r--shared-bindings/audiopwmio/PWMAudioOut.c294
-rw-r--r--shared-bindings/audiopwmio/PWMAudioOut.h49
-rw-r--r--shared-bindings/audiopwmio/__init__.c71
-rw-r--r--shared-bindings/audiopwmio/__init__.h34
-rw-r--r--shared-bindings/bleio/Adapter.c36
-rw-r--r--shared-bindings/bleio/Adapter.h3
-rw-r--r--shared-bindings/bleio/Address.c47
-rw-r--r--shared-bindings/bleio/Attribute.c94
-rw-r--r--shared-bindings/bleio/Attribute.h38
-rw-r--r--shared-bindings/bleio/Central.c98
-rw-r--r--shared-bindings/bleio/Central.h5
-rw-r--r--shared-bindings/bleio/Characteristic.c265
-rw-r--r--shared-bindings/bleio/Characteristic.h4
-rw-r--r--shared-bindings/bleio/Descriptor.c145
-rw-r--r--shared-bindings/bleio/Descriptor.h27
-rw-r--r--shared-bindings/bleio/Peripheral.c102
-rw-r--r--shared-bindings/bleio/Peripheral.h5
-rw-r--r--shared-bindings/bleio/Service.c25
-rw-r--r--shared-bindings/bleio/Service.h1
-rw-r--r--shared-bindings/bleio/__init__.c38
-rw-r--r--shared-bindings/bleio/__init__.h16
-rw-r--r--shared-bindings/displayio/FourWire.c4
-rw-r--r--shared-bindings/displayio/I2CDisplay.c4
-rw-r--r--shared-bindings/displayio/ParallelBus.c4
-rw-r--r--shared-bindings/displayio/TileGrid.c7
-rw-r--r--shared-bindings/displayio/TileGrid.h3
-rw-r--r--shared-bindings/i2cslave/I2CSlave.c6
-rw-r--r--shared-bindings/time/__init__.c35
35 files changed, 1133 insertions, 398 deletions
diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c
index 9f3f89462..6096f6b6d 100644
--- a/shared-bindings/_stage/__init__.c
+++ b/shared-bindings/_stage/__init__.c
@@ -50,7 +50,7 @@
//| Layer
//| Text
//|
-//| .. function:: render(x0, y0, x1, y1, layers, buffer, display)
+//| .. function:: render(x0, y0, x1, y1, layers, buffer, display[, scale])
//|
//| Render and send to the display a fragment of the screen.
//|
@@ -61,6 +61,7 @@
//| :param list layers: A list of the :py:class:`~_stage.Layer` objects.
//| :param bytearray buffer: A buffer to use for rendering.
//| :param ~displayio.Display display: The display to use.
+//| :param int scale: How many times should the image be scaled up.
//|
//| There are also no sanity checks, outside of the basic overflow
//| checking. The caller is responsible for making the passed parameters
@@ -89,11 +90,13 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) {
mp_raise_TypeError(translate("argument num/types mismatch"));
}
displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display);
+ uint8_t scale = 1;
+ if (n_args >= 8) {
+ scale = mp_obj_get_int(args[7]);
+ }
while (!displayio_display_begin_transaction(display)) {
-#ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP ;
-#endif
+ RUN_BACKGROUND_TASKS;
}
displayio_area_t area;
area.x1 = x0;
@@ -101,12 +104,15 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) {
area.x2 = x1;
area.y2 = y1;
displayio_display_set_region_to_update(display, &area);
- render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display);
+
+ display->send(display->bus, true, &display->write_ram_command, 1);
+ render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size,
+ display, scale);
displayio_display_end_transaction(display);
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 8, stage_render);
STATIC const mp_rom_map_elem_t stage_module_globals_table[] = {
diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c
index 980f11392..9bce9c760 100644
--- a/shared-bindings/audiobusio/I2SOut.c
+++ b/shared-bindings/audiobusio/I2SOut.c
@@ -56,7 +56,7 @@
//| using `UDA1334 Breakout <https://www.adafruit.com/product/3678>`_::
//|
//| import audiobusio
-//| import audioio
+//| import audiocore
//| import board
//| import array
//| import time
@@ -68,7 +68,7 @@
//| for i in range(length):
//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
//|
-//| sine_wave = audiobusio.RawSample(sine_wave, sample_rate=8000)
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
//| i2s = audiobusio.I2SOut(board.D1, board.D0, board.D9)
//| i2s.play(sine_wave, loop=True)
//| time.sleep(1)
@@ -78,12 +78,13 @@
//|
//| import board
//| import audioio
+//| import audiocore
//| import audiobusio
//| import digitalio
//|
//|
//| f = open("cplay-5.1-16bit-16khz.wav", "rb")
-//| wav = audioio.WaveFile(f)
+//| wav = audiocore.WaveFile(f)
//|
//| a = audiobusio.I2SOut(board.D1, board.D0, board.D9)
//|
@@ -163,7 +164,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_i2sout___exit___obj, 4, 4,
//| Plays the sample once when loop=False and continuously when loop=True.
//| Does not block. Use `playing` to block.
//|
-//| Sample must be an `audioio.WaveFile` or `audioio.RawSample`.
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`.
//|
//| The sample itself should consist of 8 bit or 16 bit samples.
//|
diff --git a/shared-bindings/audiocore/Mixer.c b/shared-bindings/audiocore/Mixer.c
index 66babdd08..035c47cb0 100644
--- a/shared-bindings/audiocore/Mixer.c
+++ b/shared-bindings/audiocore/Mixer.c
@@ -38,7 +38,7 @@
#include "shared-bindings/util.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: audioio
+//| .. currentmodule:: audiocore
//|
//| :class:`Mixer` -- Mixes one or more audio samples together
//| ===========================================================
diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c
index 912b48bfb..07f8c683f 100644
--- a/shared-bindings/audiocore/RawSample.c
+++ b/shared-bindings/audiocore/RawSample.c
@@ -35,7 +35,7 @@
#include "shared-bindings/audiocore/RawSample.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: audioio
+//| .. currentmodule:: audiocore
//|
//| :class:`RawSample` -- A raw audio sample buffer
//| ========================================================
@@ -55,6 +55,7 @@
//|
//| Simple 8ksps 440 Hz sin wave::
//|
+//| import audiocore
//| import audioio
//| import board
//| import array
@@ -68,7 +69,7 @@
//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15))
//|
//| dac = audioio.AudioOut(board.SPEAKER)
-//| sine_wave = audioio.RawSample(sine_wave)
+//| sine_wave = audiocore.RawSample(sine_wave)
//| dac.play(sine_wave, loop=True)
//| time.sleep(1)
//| dac.stop()
diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c
index 4c1993b7c..1b3a94ff3 100644
--- a/shared-bindings/audiocore/WaveFile.c
+++ b/shared-bindings/audiocore/WaveFile.c
@@ -33,23 +33,27 @@
#include "shared-bindings/util.h"
#include "supervisor/shared/translate.h"
-//| .. currentmodule:: audioio
+//| .. currentmodule:: audiocore
//|
//| :class:`WaveFile` -- Load a wave file for audio playback
//| ========================================================
//|
//| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must
-//| be 8 bit unsigned or 16 bit signed.
+//| be 8 bit unsigned or 16 bit signed. If a buffer is provided, it will be used instead of allocating
+//| an internal buffer.
//|
-//| .. class:: WaveFile(file)
+//| .. class:: WaveFile(file[, buffer])
//|
//| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`.
//|
//| :param typing.BinaryIO file: Already opened wave file
+//| :param bytearray buffer: Optional pre-allocated buffer, that will be split in half and used for double-buffering of the data. If not provided, two 512 byte buffers are allocated internally.
+//|
//|
//| Playing a wave file from flash::
//|
//| import board
+//| import audiocore
//| import audioio
//| import digitalio
//|
@@ -58,7 +62,7 @@
//| speaker_enable.switch_to_output(value=True)
//|
//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
-//| wav = audioio.WaveFile(data)
+//| wav = audiocore.WaveFile(data)
//| a = audioio.AudioOut(board.A0)
//|
//| print("playing")
@@ -68,15 +72,23 @@
//| print("stopped")
//|
STATIC mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
- mp_arg_check_num(n_args, kw_args, 1, 1, false);
+ mp_arg_check_num(n_args, kw_args, 1, 2, false);
audioio_wavefile_obj_t *self = m_new_obj(audioio_wavefile_obj_t);
self->base.type = &audioio_wavefile_type;
- if (MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) {
- common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0]));
- } else {
+ if (!MP_OBJ_IS_TYPE(args[0], &mp_type_fileio)) {
mp_raise_TypeError(translate("file must be a file opened in byte mode"));
}
+ uint8_t *buffer = NULL;
+ size_t buffer_size = 0;
+ if (n_args >= 2) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+ buffer = bufinfo.buf;
+ buffer_size = bufinfo.len;
+ }
+ common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(args[0]),
+ buffer, buffer_size);
return MP_OBJ_FROM_PTR(self);
}
diff --git a/shared-bindings/audiocore/WaveFile.h b/shared-bindings/audiocore/WaveFile.h
index d2572318b..f4a172319 100644
--- a/shared-bindings/audiocore/WaveFile.h
+++ b/shared-bindings/audiocore/WaveFile.h
@@ -35,7 +35,7 @@
extern const mp_obj_type_t audioio_wavefile_type;
void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self,
- pyb_file_obj_t* file);
+ pyb_file_obj_t* file, uint8_t *buffer, size_t buffer_size);
void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self);
bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self);
diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c
index 79df66f7d..af2fce48e 100644
--- a/shared-bindings/audioio/AudioOut.c
+++ b/shared-bindings/audioio/AudioOut.c
@@ -55,6 +55,7 @@
//|
//| Simple 8ksps 440 Hz sin wave::
//|
+//| import audiocore
//| import audioio
//| import board
//| import array
@@ -68,7 +69,7 @@
//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
//|
//| dac = audioio.AudioOut(board.SPEAKER)
-//| sine_wave = audioio.RawSample(sine_wave, sample_rate=8000)
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
//| dac.play(sine_wave, loop=True)
//| time.sleep(1)
//| dac.stop()
@@ -84,7 +85,7 @@
//| speaker_enable.switch_to_output(value=True)
//|
//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
-//| wav = audioio.WaveFile(data)
+//| wav = audiocore.WaveFile(data)
//| a = audioio.AudioOut(board.A0)
//|
//| print("playing")
@@ -162,7 +163,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_audioout___exit___obj, 4, 4,
//| Plays the sample once when loop=False and continuously when loop=True.
//| Does not block. Use `playing` to block.
//|
-//| Sample must be an `audioio.WaveFile` or `audioio.RawSample`.
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`.
//|
//| The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
//| resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit
diff --git a/shared-bindings/audiopwmio/PWMAudioOut.c b/shared-bindings/audiopwmio/PWMAudioOut.c
new file mode 100644
index 000000000..92543d112
--- /dev/null
+++ b/shared-bindings/audiopwmio/PWMAudioOut.c
@@ -0,0 +1,294 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * 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 <stdint.h>
+
+#include "lib/utils/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiopwmio/PWMAudioOut.h"
+#include "shared-bindings/audiocore/RawSample.h"
+#include "shared-bindings/util.h"
+#include "supervisor/shared/translate.h"
+
+//| .. currentmodule:: audiopwmio
+//|
+//| :class:`PWMAudioOut` -- Output an analog audio signal
+//| ========================================================
+//|
+//| AudioOut can be used to output an analog audio signal on a given pin.
+//|
+//| .. class:: PWMAudioOut(left_channel, *, right_channel=None, quiescent_value=0x8000)
+//|
+//| Create a PWMAudioOut object associated with the given pin(s). This allows you to
+//| play audio signals out on the given pin(s). In contrast to mod:`audioio`,
+//| the pin(s) specified are digital pins, and are driven with a device-dependent PWM
+//| signal.
+//|
+//| :param ~microcontroller.Pin left_channel: The pin to output the left channel to
+//| :param ~microcontroller.Pin right_channel: The pin to output the right channel to
+//| :param int quiescent_value: The output value when no signal is present. Samples should start
+//| and end with this value to prevent audible popping.
+//|
+//| Simple 8ksps 440 Hz sin wave::
+//|
+//| import audiocore
+//| import audiopwmio
+//| import board
+//| import array
+//| import time
+//| import math
+//|
+//| # Generate one period of sine wav.
+//| length = 8000 // 440
+//| sine_wave = array.array("H", [0] * length)
+//| for i in range(length):
+//| sine_wave[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
+//|
+//| dac = audiopwmio.PWMAudioOut(board.SPEAKER)
+//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000)
+//| dac.play(sine_wave, loop=True)
+//| time.sleep(1)
+//| dac.stop()
+//|
+//| Playing a wave file from flash::
+//|
+//| import board
+//| import audiocore
+//| import audiopwmio
+//| import digitalio
+//|
+//| # Required for CircuitPlayground Express
+//| speaker_enable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
+//| speaker_enable.switch_to_output(value=True)
+//|
+//| data = open("cplay-5.1-16bit-16khz.wav", "rb")
+//| wav = audiocore.WaveFile(data)
+//| a = audiopwmio.PWMAudioOut(board.SPEAKER)
+//|
+//| print("playing")
+//| a.play(wav)
+//| while a.playing:
+//| pass
+//| print("stopped")
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_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_left_channel, ARG_right_channel, ARG_quiescent_value };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_left_channel, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_right_channel, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = mp_const_none} },
+ { MP_QSTR_quiescent_value, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x8000} },
+ };
+ 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);
+
+ mp_obj_t left_channel_obj = args[ARG_left_channel].u_obj;
+ assert_pin(left_channel_obj, false);
+ const mcu_pin_obj_t *left_channel_pin = MP_OBJ_TO_PTR(left_channel_obj);
+
+ mp_obj_t right_channel_obj = args[ARG_right_channel].u_obj;
+ const mcu_pin_obj_t *right_channel_pin = NULL;
+ if (right_channel_obj != mp_const_none) {
+ assert_pin(right_channel_obj, false);
+ right_channel_pin = MP_OBJ_TO_PTR(right_channel_obj);
+ }
+
+ // create AudioOut object from the given pin
+ audiopwmio_pwmaudioout_obj_t *self = m_new_obj(audiopwmio_pwmaudioout_obj_t);
+ self->base.type = &audiopwmio_pwmaudioout_type;
+ common_hal_audiopwmio_pwmaudioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| .. method:: deinit()
+//|
+//| Deinitialises the PWMAudioOut and releases any hardware resources for reuse.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_deinit(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_audiopwmio_pwmaudioout_deinit(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_deinit_obj, audiopwmio_pwmaudioout_deinit);
+
+STATIC void check_for_deinit(audiopwmio_pwmaudioout_obj_t *self) {
+ if (common_hal_audiopwmio_pwmaudioout_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+//| .. method:: __enter__()
+//|
+//| No-op used by Context Managers.
+//|
+// Provided by context manager helper.
+
+//| .. method:: __exit__()
+//|
+//| Automatically deinitializes the hardware when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_audiopwmio_pwmaudioout_deinit(args[0]);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiopwmio_pwmaudioout___exit___obj, 4, 4, audiopwmio_pwmaudioout_obj___exit__);
+
+
+//| .. method:: play(sample, *, loop=False)
+//|
+//| Plays the sample once when loop=False and continuously when loop=True.
+//| Does not block. Use `playing` to block.
+//|
+//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, or `audiocore.Mixer`.
+//|
+//| The sample itself should consist of 16 bit samples. Microcontrollers with a lower output
+//| resolution will use the highest order bits to output. For example, the SAMD21 has a 10 bit
+//| DAC that ignores the lowest 6 bits when playing 16 bit samples.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_sample, ARG_loop };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED },
+ { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
+ };
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ check_for_deinit(self);
+ 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_obj_t sample = args[ARG_sample].u_obj;
+ common_hal_audiopwmio_pwmaudioout_play(self, sample, args[ARG_loop].u_bool);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(audiopwmio_pwmaudioout_play_obj, 1, audiopwmio_pwmaudioout_obj_play);
+
+//| .. method:: stop()
+//|
+//| Stops playback and resets to the start of the sample.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_stop(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ common_hal_audiopwmio_pwmaudioout_stop(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_stop_obj, audiopwmio_pwmaudioout_obj_stop);
+
+//| .. attribute:: playing
+//|
+//| True when an audio sample is being output even if `paused`. (read-only)
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_get_playing(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiopwmio_pwmaudioout_get_playing(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_get_playing_obj, audiopwmio_pwmaudioout_obj_get_playing);
+
+const mp_obj_property_t audiopwmio_pwmaudioout_playing_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&audiopwmio_pwmaudioout_get_playing_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+//| .. method:: pause()
+//|
+//| Stops playback temporarily while remembering the position. Use `resume` to resume playback.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_pause(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (!common_hal_audiopwmio_pwmaudioout_get_playing(self)) {
+ mp_raise_RuntimeError(translate("Not playing"));
+ }
+ common_hal_audiopwmio_pwmaudioout_pause(self);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_pause_obj, audiopwmio_pwmaudioout_obj_pause);
+
+//| .. method:: resume()
+//|
+//| Resumes sample playback after :py:func:`pause`.
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_resume(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ if (common_hal_audiopwmio_pwmaudioout_get_paused(self)) {
+ common_hal_audiopwmio_pwmaudioout_resume(self);
+ }
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_resume_obj, audiopwmio_pwmaudioout_obj_resume);
+
+//| .. attribute:: paused
+//|
+//| True when playback is paused. (read-only)
+//|
+STATIC mp_obj_t audiopwmio_pwmaudioout_obj_get_paused(mp_obj_t self_in) {
+ audiopwmio_pwmaudioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+ return mp_obj_new_bool(common_hal_audiopwmio_pwmaudioout_get_paused(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_pwmaudioout_get_paused_obj, audiopwmio_pwmaudioout_obj_get_paused);
+
+const mp_obj_property_t audiopwmio_pwmaudioout_paused_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&audiopwmio_pwmaudioout_get_paused_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj},
+};
+
+STATIC const mp_rom_map_elem_t audiopwmio_pwmaudioout_locals_dict_table[] = {
+ // Methods
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiopwmio_pwmaudioout_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiopwmio_pwmaudioout___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiopwmio_pwmaudioout_play_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiopwmio_pwmaudioout_stop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiopwmio_pwmaudioout_pause_obj) },
+ { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiopwmio_pwmaudioout_resume_obj) },
+
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiopwmio_pwmaudioout_playing_obj) },
+ { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiopwmio_pwmaudioout_paused_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(audiopwmio_pwmaudioout_locals_dict, audiopwmio_pwmaudioout_locals_dict_table);
+
+const mp_obj_type_t audiopwmio_pwmaudioout_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_PWMAudioOut,
+ .make_new = audiopwmio_pwmaudioout_make_new,
+ .locals_dict = (mp_obj_dict_t*)&audiopwmio_pwmaudioout_locals_dict,
+};
diff --git a/shared-bindings/audiopwmio/PWMAudioOut.h b/shared-bindings/audiopwmio/PWMAudioOut.h
new file mode 100644
index 000000000..22afc70d3
--- /dev/null
+++ b/shared-bindings/audiopwmio/PWMAudioOut.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * 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_AUDIOPWMIO_AUDIOOUT_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H
+
+#include "common-hal/audiopwmio/PWMAudioOut.h"
+#include "common-hal/microcontroller/Pin.h"
+#include "shared-bindings/audiocore/RawSample.h"
+
+extern const mp_obj_type_t audiopwmio_pwmaudioout_type;
+
+// left_channel will always be non-NULL but right_channel may be for mono output.
+void common_hal_audiopwmio_pwmaudioout_construct(audiopwmio_pwmaudioout_obj_t* self,
+ const mcu_pin_obj_t* left_channel, const mcu_pin_obj_t* right_channel, uint16_t default_value);
+
+void common_hal_audiopwmio_pwmaudioout_deinit(audiopwmio_pwmaudioout_obj_t* self);
+bool common_hal_audiopwmio_pwmaudioout_deinited(audiopwmio_pwmaudioout_obj_t* self);
+void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t* self, mp_obj_t sample, bool loop);
+void common_hal_audiopwmio_pwmaudioout_stop(audiopwmio_pwmaudioout_obj_t* self);
+bool common_hal_audiopwmio_pwmaudioout_get_playing(audiopwmio_pwmaudioout_obj_t* self);
+void common_hal_audiopwmio_pwmaudioout_pause(audiopwmio_pwmaudioout_obj_t* self);
+void common_hal_audiopwmio_pwmaudioout_resume(audiopwmio_pwmaudioout_obj_t* self);
+bool common_hal_audiopwmio_pwmaudioout_get_paused(audiopwmio_pwmaudioout_obj_t* self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO_AUDIOOUT_H
diff --git a/shared-bindings/audiopwmio/__init__.c b/shared-bindings/audiopwmio/__init__.c
new file mode 100644
index 000000000..8a2b202b3
--- /dev/null
+++ b/shared-bindings/audiopwmio/__init__.c
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * 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 <stdint.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/audiopwmio/__init__.h"
+#include "shared-bindings/audiopwmio/PWMAudioOut.h"
+
+//| :mod:`audiopwmio` --- Support for audio input and output
+//| ========================================================
+//|
+//| .. module:: audiopwmio
+//| :synopsis: Support for audio output via digital PWM
+//| :platform: NRF52
+//|
+//| The `audiopwmio` module contains classes to provide access to audio IO.
+//|
+//| Libraries
+//|
+//| .. toctree::
+//| :maxdepth: 3
+//|
+//| PWMAudioOut
+//|
+//| All classes change hardware state and should be deinitialized when they
+//| are no longer needed if the program continues after use. To do so, either
+//| call :py:meth:`!deinit` or use a context manager. See
+//| :ref:`lifetime-and-contextmanagers` for more info.
+//|
+//| Since CircuitPython 5, `Mixer`, `RawSample` and `WaveFile` are moved
+//| to :mod:`audiocore`.
+//|
+
+STATIC const mp_rom_map_elem_t audiopwmio_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiopwmio) },
+ { MP_ROM_QSTR(MP_QSTR_PWMAudioOut), MP_ROM_PTR(&audiopwmio_pwmaudioout_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(audiopwmio_module_globals, audiopwmio_module_globals_table);
+
+const mp_obj_module_t audiopwmio_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&audiopwmio_module_globals,
+};
diff --git a/shared-bindings/audiopwmio/__init__.h b/shared-bindings/audiopwmio/__init__.h
new file mode 100644
index 000000000..e4b7067d1
--- /dev/null
+++ b/shared-bindings/audiopwmio/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ *
+ * 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_AUDIOIO___INIT___H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H
+
+#include "py/obj.h"
+
+// Nothing now.
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H
diff --git a/shared-bindings/bleio/Adapter.c b/shared-bindings/bleio/Adapter.c
index 7b8df5103..2bb7f3465 100644
--- a/shared-bindings/bleio/Adapter.c
+++ b/shared-bindings/bleio/Adapter.c
@@ -53,12 +53,6 @@
//|
//| State of the BLE adapter.
//|
-
-//| .. attribute:: adapter.address
-//|
-//| MAC address of the BLE adapter. (read-only)
-//|
-
STATIC mp_obj_t bleio_adapter_get_enabled(mp_obj_t self) {
return mp_obj_new_bool(common_hal_bleio_adapter_get_enabled());
}
@@ -80,13 +74,13 @@ const mp_obj_property_t bleio_adapter_enabled_obj = {
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: adapter.address
+//|
+//| MAC address of the BLE adapter. (read-only)
+//|
STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) {
- mp_obj_t obj = bleio_address_type.make_new(&bleio_address_type, 1, 0, mp_const_none);
- bleio_address_obj_t *address = MP_OBJ_TO_PTR(obj);
-
- common_hal_bleio_adapter_get_address(address);
+ return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_address());
- return obj;
}
MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_address_obj, bleio_adapter_get_address);
@@ -97,9 +91,29 @@ const mp_obj_property_t bleio_adapter_address_obj = {
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: adapter.default_name
+//|
+//| 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.
+//|
+STATIC mp_obj_t bleio_adapter_get_default_name(mp_obj_t self) {
+ return common_hal_bleio_adapter_get_default_name();
+
+}
+MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_get_default_name_obj, bleio_adapter_get_default_name);
+
+const mp_obj_property_t bleio_adapter_default_name_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_adapter_get_default_name_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
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) },
};
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 de9d1d6db..72382616c 100644
--- a/shared-bindings/bleio/Adapter.h
+++ b/shared-bindings/bleio/Adapter.h
@@ -34,6 +34,7 @@ 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 void common_hal_bleio_adapter_get_address(bleio_address_obj_t *address);
+extern bleio_address_obj_t *common_hal_bleio_adapter_get_address(void);
+extern mp_obj_t common_hal_bleio_adapter_get_default_name(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADAPTER_H
diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c
index 37f01042c..baeb6d7c0 100644
--- a/shared-bindings/bleio/Address.c
+++ b/shared-bindings/bleio/Address.c
@@ -83,7 +83,21 @@ STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args,
//| .. attribute:: address_bytes
//|
-//| The bytes that make up the device address (read-only)
+//| The bytes that make up the device address (read-only).
+//|
+//| Note that the ``bytes`` object returned is in little-endian order:
+//| The least significant byte is ``address_bytes[0]``. So the address will
+//| appear to be reversed if you print the raw ``bytes`` object. If you print
+//| or use `str()` on the :py:class:`~bleio.Attribute` object itself, the address will be printed
+//| in the expected order. For example:
+//|
+//| .. code-block:: pycon
+//|
+//| >>> import bleio
+//| >>> bleio.adapter.address
+//| <Address c8:1d:f5:ed:a8:35>
+//| >>> bleio.adapter.address.address_bytes
+//| b'5\xa8\xed\xf5\x1d\xc8'
//|
STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) {
bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -147,18 +161,13 @@ STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o
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);
- if (kind == PRINT_STR) {
- mp_buffer_info_t buf_info;
- mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self);
- mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ);
-
- const uint8_t *buf = (uint8_t *) buf_info.buf;
- mp_printf(print,
- "%02x:%02x:%02x:%02x:%02x:%02x",
- buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
- } else {
- mp_printf(print, "<Address>");
- }
+ mp_buffer_info_t buf_info;
+ mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self);
+ mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ);
+
+ const uint8_t *buf = (uint8_t *) buf_info.buf;
+ mp_printf(print, "<Address %02x:%02x:%02x:%02x:%02x:%02x>",
+ buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]);
}
//| .. data:: PUBLIC
@@ -179,13 +188,13 @@ STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
//| A randomly generated address that changes on every connection.
//|
STATIC const mp_rom_map_elem_t bleio_address_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) },
- { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) },
+ { MP_ROM_QSTR(MP_QSTR_address_bytes), MP_ROM_PTR(&bleio_address_address_bytes_obj) },
+ { MP_ROM_QSTR(MP_QSTR_type), MP_ROM_PTR(&bleio_address_type_obj) },
// These match the BLE_GAP_ADDR_TYPES values used by the nRF library.
- { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_OBJ_NEW_SMALL_INT(0) },
- { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_OBJ_NEW_SMALL_INT(1) },
- { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(2) },
- { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_OBJ_NEW_SMALL_INT(3) },
+ { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_INT(0) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_INT(1) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_INT(2) },
+ { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_INT(3) },
};
diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c
new file mode 100644
index 000000000..2cc9ef6d0
--- /dev/null
+++ b/shared-bindings/bleio/Attribute.c
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * 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/Characteristic.h"
+#include "shared-bindings/bleio/UUID.h"
+
+//
+
+//| .. currentmodule:: bleio
+//|
+//| :class:`Attribute` -- BLE Attribute
+//| =========================================================
+//|
+//| Definitions associated with all BLE attributes: characteristics, descriptors, etc.
+//| :py:class:`~bleio.Attribute` is, notionally, a superclass of
+//| :py:class:`~Characteristic` and :py:class:`~Descriptor`,
+//| but is not defined as a Python superclass of those classes.
+//|
+//| .. class:: Attribute()
+//|
+//| You cannot create an instance of :py:class:`~bleio.Attribute`.
+//|
+
+STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = {
+
+//| .. data:: NO_ACCESS
+//|
+//| security mode: access not allowed
+//|
+//| .. data:: OPEN
+//|
+//| security_mode: no security (link is not encrypted)
+//|
+//| .. data:: ENCRYPT_NO_MITM
+//|
+//| security_mode: unauthenticated encryption, without man-in-the-middle protection
+//|
+//| .. data:: ENCRYPT_WITH_MITM
+//|
+//| security_mode: authenticated encryption, with man-in-the-middle protection
+//|
+//| .. data:: LESC_ENCRYPT_WITH_MITM
+//|
+//| security_mode: LESC encryption, with man-in-the-middle protection
+//|
+//| .. data:: SIGNED_NO_MITM
+//|
+//| security_mode: unauthenticated data signing, without man-in-the-middle protection
+//|
+//| .. data:: SIGNED_WITH_MITM
+//|
+//| security_mode: authenticated data signing, without man-in-the-middle protection
+//|
+ { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SECURITY_MODE_NO_ACCESS) },
+ { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SECURITY_MODE_OPEN) },
+ { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SECURITY_MODE_ENC_NO_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_ENC_WITH_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SECURITY_MODE_LESC_ENC_WITH_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_NO_MITM) },
+ { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SECURITY_MODE_SIGNED_WITH_MITM) },
+
+};
+STATIC MP_DEFINE_CONST_DICT(bleio_attribute_locals_dict, bleio_attribute_locals_dict_table);
+
+const mp_obj_type_t bleio_attribute_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Attribute,
+ .locals_dict = (mp_obj_dict_t*)&bleio_attribute_locals_dict,
+};
diff --git a/shared-bindings/bleio/Attribute.h b/shared-bindings/bleio/Attribute.h
new file mode 100644
index 000000000..06a6eb5a9
--- /dev/null
+++ b/shared-bindings/bleio/Attribute.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Dan Halbert for Adafruit Industries
+ *
+ * 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_ATTRIBUTE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H
+
+#include "py/obj.h"
+
+#include "shared-module/bleio/Attribute.h"
+
+extern const mp_obj_type_t bleio_attribute_type;
+
+extern void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ATTRIBUTE_H
diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c
index fc00bce5c..1fc455d8d 100644
--- a/shared-bindings/bleio/Central.c
+++ b/shared-bindings/bleio/Central.c
@@ -56,12 +56,16 @@
//|
//| my_entry = None
//| for entry in entries:
-//| if entry.name is not None and entry.name == 'MyPeripheral':
+//| if entry.name is not None and entry.name == 'InterestingPeripheral':
//| my_entry = entry
//| break
//|
-//| central = bleio.Central(my_entry.address)
-//| central.connect(10.0) # timeout after 10 seconds
+//| 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()
@@ -79,24 +83,11 @@ STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args,
return MP_OBJ_FROM_PTR(self);
}
-//| .. method:: connect(address, timeout, *, service_uuids=None)
-//| Attempts a connection to the remote peripheral. If the connection is successful,
-//| Do BLE discovery for the listed services, to find their handles and characteristics.
-//| The attribute `remote_services` will contain a list of all discovered services.
+//| .. method:: connect(address, timeout, *, service_uuids_whitelist=None)
+//| Attempts a connection to the remote peripheral.
//|
//| :param bleio.Address address: The address of the peripheral to connect to
//| :param float/int timeout: Try to connect for timeout seconds.
-//| :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.
-//| If a service in service_uuids is not found during discovery, it will not
-//| appear in `remote_services`.
-//|
-//| 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. (This restriction may be lifted in the future.)
//|
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]);
@@ -105,7 +96,6 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args
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_QSTR_service_uuids_whitelist, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -119,7 +109,7 @@ STATIC mp_obj_t bleio_central_connect(mp_uint_t n_args, const mp_obj_t *pos_args
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, args[ARG_service_uuids_whitelist].u_obj);
+ common_hal_bleio_central_connect(self, address, timeout);
return mp_const_none;
}
@@ -139,6 +129,46 @@ STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) {
}
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.
@@ -157,36 +187,14 @@ const mp_obj_property_t bleio_central_connected_obj = {
(mp_obj_t)&mp_const_none_obj },
};
-
-//| .. attribute:: remote_services (read-only)
-//|
-//| A tuple of services provided by the remote peripheral.
-//| If the Central is not connected, an empty tuple will be returned.
-//|
-STATIC mp_obj_t bleio_central_get_remote_services(mp_obj_t self_in) {
- bleio_central_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 *service_list = common_hal_bleio_central_get_remote_services(self);
- return mp_obj_new_tuple(service_list->len, service_list->items);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_remote_services_obj, bleio_central_get_remote_services);
-
-const mp_obj_property_t bleio_central_remote_services_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_central_get_remote_services_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_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) },
- { MP_ROM_QSTR(MP_QSTR_remote_services), MP_ROM_PTR(&bleio_central_remote_services_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_central_locals_dict, bleio_central_locals_dict_table);
diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h
index 0e84037f9..cbc437087 100644
--- a/shared-bindings/bleio/Central.h
+++ b/shared-bindings/bleio/Central.h
@@ -28,15 +28,16 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
+#include "py/objtuple.h"
#include "common-hal/bleio/Central.h"
#include "common-hal/bleio/Service.h"
extern const mp_obj_type_t bleio_central_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, mp_obj_t service_uuids);
+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_list_t *common_hal_bleio_central_get_remote_services(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);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H
diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c
index 3bf0476ab..4894ad114 100644
--- a/shared-bindings/bleio/Characteristic.c
+++ b/shared-bindings/bleio/Characteristic.c
@@ -28,7 +28,9 @@
#include "py/objproperty.h"
#include "py/runtime.h"
+#include "shared-bindings/bleio/Attribute.h"
#include "shared-bindings/bleio/Characteristic.h"
+#include "shared-bindings/bleio/Descriptor.h"
#include "shared-bindings/bleio/UUID.h"
//| .. currentmodule:: bleio
@@ -40,30 +42,36 @@
//| and writing of the characteristic's value.
//|
//|
-//| .. class:: Characteristic(uuid, *, broadcast=False, indicate=False, notify=False, read=False, write=False, write_no_response=False)
+//| .. class:: Characteristic(uuid, *, properties=0, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`, max_length=20, fixed_length=False, descriptors=None)
//|
//| Create a new Characteristic object identified by the specified UUID.
//|
//| :param bleio.UUID uuid: The uuid of the characteristic
-//| :param bool broadcast: Allowed in advertising packets
-//| :param bool indicate: Server will indicate to the client when the value is set and wait for a response
-//| :param bool notify: Server will notify the client when the value is set
-//| :param bool read: Clients may read this characteristic
-//| :param bool write: Clients may write this characteristic; a response will be sent back
-//| :param bool write_no_response: Clients may write this characteristic; no response will be sent back
+//| :param int properties: bitmask of these values bitwise-or'd together: `BROADCAST`, `INDICATE`,
+//| `NOTIFY`, `READ`, `WRITE`, `WRITE_NO_RESPONSE`
+//| :param int read_perm: Specifies whether the characteristic can be read by a client, and if so, which
+//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+//| :param int write_perm: Specifies whether the characteristic can be written by a client, and if so, which
+//| security mode is required. Values allowed are the same as ``read_perm``.
+//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is
+//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+//| number of data bytes that fit in a single BLE 4.x ATT packet.
+//| :param bool fixed_length: True if the characteristic value is of fixed length.
+//| :param iterable descriptors: BLE descriptors for this characteristic.
//|
STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum {
- ARG_uuid, ARG_broadcast, ARG_indicate, ARG_notify, ARG_read, ARG_write, ARG_write_no_response,
- };
+ enum { ARG_uuid, ARG_properties, ARG_read_perm, ARG_write_perm,
+ ARG_max_length, ARG_fixed_length, ARG_descriptors };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_broadcast, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_indicate, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_notify, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_read, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_write, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_write_no_response, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN} },
+ { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} },
+ { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -76,129 +84,69 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t
}
bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj);
- bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t);
- self->base.type = &bleio_characteristic_type;
-
- bleio_characteristic_properties_t properties;
-
- properties.broadcast = args[ARG_broadcast].u_bool;
- properties.indicate = args[ARG_indicate].u_bool;
- properties.notify = args[ARG_notify].u_bool;
- properties.read = args[ARG_read].u_bool;
- properties.write = args[ARG_write].u_bool;
- properties.write_no_response = args[ARG_write_no_response].u_bool;
-
- // Initialize, with an empty descriptor list.
- common_hal_bleio_characteristic_construct(self, uuid, properties, mp_obj_new_list(0, NULL));
-
- return MP_OBJ_FROM_PTR(self);
-}
-
-//| .. attribute:: broadcast
-//|
-//| A `bool` specifying if the characteristic allows broadcasting its value. (read-only)
-//|
-STATIC mp_obj_t bleio_characteristic_get_broadcast(mp_obj_t self_in) {
- bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).broadcast);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_broadcast_obj, bleio_characteristic_get_broadcast);
-
-const mp_obj_property_t bleio_characteristic_broadcast_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_broadcast_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. attribute:: indicate
-//|
-//| A `bool` specifying if the characteristic allows indicating its value. (read-only)
-//|
-STATIC mp_obj_t bleio_characteristic_get_indicate(mp_obj_t self_in) {
- bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).indicate);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_indicate_obj, bleio_characteristic_get_indicate);
-
-
-const mp_obj_property_t bleio_characteristic_indicate_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_indicate_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. attribute:: notify
-//|
-//| A `bool` specifying if the characteristic allows notifying its value. (read-only)
-//|
-STATIC mp_obj_t bleio_characteristic_get_notify(mp_obj_t self_in) {
- bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ const bleio_characteristic_properties_t properties = args[ARG_properties].u_int;
+ if (properties & ~CHAR_PROP_ALL) {
+ mp_raise_ValueError(translate("Invalid properties"));
+ }
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).notify);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_notify_obj, bleio_characteristic_get_notify);
+ const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(read_perm);
-const mp_obj_property_t bleio_characteristic_notify_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_notify_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
+ const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(write_perm);
-//| .. attribute:: read
-//|
-//| A `bool` specifying if the characteristic allows reading its value. (read-only)
-//|
-STATIC mp_obj_t bleio_characteristic_get_read(mp_obj_t self_in) {
- bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t descriptors = args[ARG_descriptors].u_obj;
+ if (descriptors == mp_const_none) {
+ descriptors = mp_const_empty_tuple;
+ }
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).read);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_read_obj, bleio_characteristic_get_read);
+ bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t);
+ self->base.type = &bleio_characteristic_type;
-const mp_obj_property_t bleio_characteristic_read_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_read_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
+ // Copy the descriptors list and validate its items.
+ mp_obj_t desc_list_obj = mp_obj_new_list(0, NULL);
+ mp_obj_list_t *desc_list = MP_OBJ_TO_PTR(desc_list_obj);
+
+ // If descriptors is not an iterable, an exception will be thrown.
+ mp_obj_iter_buf_t iter_buf;
+ mp_obj_t descriptors_iter = mp_getiter(descriptors, &iter_buf);
+
+ mp_obj_t descriptor_obj;
+ while ((descriptor_obj = mp_iternext(descriptors_iter)) != MP_OBJ_STOP_ITERATION) {
+ if (!MP_OBJ_IS_TYPE(descriptor_obj, &bleio_descriptor_type)) {
+ mp_raise_ValueError(translate("descriptors includes an object that is not a Descriptors"));
+ }
+ bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(descriptor_obj);
+ if (common_hal_bleio_descriptor_get_characteristic(descriptor) != MP_OBJ_NULL) {
+ mp_raise_ValueError(translate("Descriptor is already attached to a Characteristic"));
+ }
+ mp_obj_list_append(desc_list_obj, descriptor_obj);
+ }
-//| .. attribute:: write
-//|
-//| A `bool` specifying if the characteristic allows writing to its value. (read-only)
-//|
-STATIC mp_obj_t bleio_characteristic_get_write(mp_obj_t self_in) {
- bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ // 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(self, uuid, properties,
+ read_perm, write_perm,
+ args[ARG_max_length].u_int, args[ARG_fixed_length].u_bool,
+ desc_list);
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write);
+ return MP_OBJ_FROM_PTR(self);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_obj, bleio_characteristic_get_write);
-const mp_obj_property_t bleio_characteristic_write_obj = {
- .base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_write_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj },
-};
-
-//| .. attribute:: write_no_response
+//| .. attribute:: properties
//|
-//| A `bool` specifying if the characteristic allows writing to its value without response. (read-only)
+//| An int bitmask representing which properties are set.
//|
-STATIC mp_obj_t bleio_characteristic_get_write_no_response(mp_obj_t self_in) {
+STATIC mp_obj_t bleio_characteristic_get_properties(mp_obj_t self_in) {
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write_no_response);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_get_properties(self));
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_no_response_obj, bleio_characteristic_get_write_no_response);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_properties_obj, bleio_characteristic_get_properties);
-const mp_obj_property_t bleio_characteristic_write_no_response_obj = {
+const mp_obj_property_t bleio_characteristic_properties_obj = {
.base.type = &mp_type_property,
- .proxy = { (mp_obj_t)&bleio_characteristic_get_write_no_response_obj,
+ .proxy = { (mp_obj_t)&bleio_characteristic_get_properties_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj },
};
@@ -225,9 +173,7 @@ const mp_obj_property_t bleio_characteristic_uuid_obj = {
//| .. attribute:: value
//|
-//| The value of this characteristic. The value can be written to if the `write` property allows it.
-//| If the `read` property allows it, the value can be read. If the `notify` property is set, writing
-//| to the value will generate a BLE notification.
+//| The value of this characteristic.
//|
STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) {
bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -274,6 +220,24 @@ const mp_obj_property_t bleio_characteristic_descriptors_obj = {
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: service (read-only)
+//|
+//| The Service this Characteristic is a part of. None if not yet assigned to a Service.
+//|
+STATIC mp_obj_t bleio_characteristic_get_service(mp_obj_t self_in) {
+ bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_bleio_characteristic_get_service(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_service_obj, bleio_characteristic_get_service);
+
+const mp_obj_property_t bleio_characteristic_service_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_characteristic_get_service_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
//| .. method:: set_cccd(*, notify=False, indicate=False)
//|
//| Set the remote characteristic's CCCD to enable or disable notification and indication.
@@ -301,16 +265,43 @@ 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_broadcast), MP_ROM_PTR(&bleio_characteristic_broadcast_obj) },
- { MP_ROM_QSTR(MP_QSTR_descriptors), MP_ROM_PTR(&bleio_characteristic_descriptors_obj) },
- { MP_ROM_QSTR(MP_QSTR_indicate), MP_ROM_PTR(&bleio_characteristic_indicate_obj) },
- { MP_ROM_QSTR(MP_QSTR_notify), MP_ROM_PTR(&bleio_characteristic_notify_obj) },
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&bleio_characteristic_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_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_write), MP_ROM_PTR(&bleio_characteristic_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_write_no_response), MP_ROM_PTR(&bleio_characteristic_write_no_response_obj) },
+ { MP_ROM_QSTR(MP_QSTR_properties), MP_ROM_PTR(&bleio_characteristic_get_properties) },
+ { MP_ROM_QSTR(MP_QSTR_set_cccd), MP_ROM_PTR(&bleio_characteristic_set_cccd_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) },
+
+ // Bitmask constants to represent properties
+//| .. data:: BROADCAST
+//|
+//| property: allowed in advertising packets
+//|
+//| .. data:: INDICATE
+//|
+//| property: server will indicate to the client when the value is set and wait for a response
+//|
+//| .. data:: NOTIFY
+//|
+//| property: server will notify the client when the value is set
+//|
+//| .. data:: READ
+//|
+//| property: clients may read this characteristic
+//|
+//| .. data:: WRITE
+//|
+//| property: clients may write this characteristic; a response will be sent back
+//|
+//| .. data:: WRITE_NO_RESPONSE
+//|
+//| property: clients may write this characteristic; no response will be sent back
+//|
+ { MP_ROM_QSTR(MP_QSTR_BROADCAST), MP_ROM_INT(CHAR_PROP_BROADCAST) },
+ { MP_ROM_QSTR(MP_QSTR_INDICATE), MP_ROM_INT(CHAR_PROP_INDICATE) },
+ { MP_ROM_QSTR(MP_QSTR_NOTIFY), MP_ROM_INT(CHAR_PROP_NOTIFY) },
+ { MP_ROM_QSTR(MP_QSTR_READ), MP_ROM_INT(CHAR_PROP_READ) },
+ { MP_ROM_QSTR(MP_QSTR_WRITE), MP_ROM_INT(CHAR_PROP_WRITE) },
+ { MP_ROM_QSTR(MP_QSTR_WRITE_NO_RESPONSE), MP_ROM_INT(CHAR_PROP_WRITE_NO_RESPONSE) },
+
};
STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table);
@@ -330,5 +321,5 @@ const mp_obj_type_t bleio_characteristic_type = {
.name = MP_QSTR_Characteristic,
.make_new = bleio_characteristic_make_new,
.print = bleio_characteristic_print,
- .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict
+ .locals_dict = (mp_obj_dict_t*)&bleio_characteristic_locals_dict,
};
diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h
index d450c42b4..87942c8e9 100644
--- a/shared-bindings/bleio/Characteristic.h
+++ b/shared-bindings/bleio/Characteristic.h
@@ -28,17 +28,19 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
+#include "shared-bindings/bleio/Attribute.h"
#include "shared-module/bleio/Characteristic.h"
#include "common-hal/bleio/Characteristic.h"
extern const mp_obj_type_t bleio_characteristic_type;
-extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, mp_obj_list_t *descriptor_list);
+extern void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_obj_list_t *descriptor_list);
extern mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self);
extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo);
extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self);
extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self);
extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self);
+extern bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self);
extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H
diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c
index f2e5aa01d..d7c2a85c7 100644
--- a/shared-bindings/bleio/Descriptor.c
+++ b/shared-bindings/bleio/Descriptor.c
@@ -28,6 +28,7 @@
#include "py/objproperty.h"
#include "py/runtime.h"
+#include "shared-bindings/bleio/Attribute.h"
#include "shared-bindings/bleio/Descriptor.h"
#include "shared-bindings/bleio/UUID.h"
@@ -41,23 +42,30 @@
//| information about the characteristic.
//|
-//| .. class:: Descriptor(uuid)
+//| .. class:: Descriptor(uuid, *, read_perm=`Attribute.OPEN`, write_perm=`Attribute.OPEN`)
//|
-//| Create a new descriptor object with the UUID uuid.
-
-//| .. attribute:: handle
-//|
-//| The descriptor handle. (read-only)
-//|
-
-//| .. attribute:: uuid
+//| Create a new descriptor object with the UUID uuid
//|
-//| The descriptor uuid. (read-only)
+//| :param bleio.UUID uuid: The uuid of the descriptor
+//| :param int read_perm: Specifies whether the descriptor can be read by a client, and if so, which
+//| security mode is required. Must be one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`,
+//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`,
+//| `Attribute.SIGNED_NO_MITM`, or `Attribute.SIGNED_WITH_MITM`.
+//| :param int write_perm: Specifies whether the descriptor can be written by a client, and if so, which
+//| security mode is required. Values allowed are the same as ``read_perm``.
+//| :param int max_length: Maximum length in bytes of the characteristic value. The maximum allowed is
+//| is 512, or possibly 510 if ``fixed_length`` is False. The default, 20, is the maximum
+//| number of data bytes that fit in a single BLE 4.x ATT packet.
+//| :param bool fixed_length: True if the characteristic value is of fixed length.
//|
STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_uuid };
+ enum { ARG_uuid, ARG_read_perm, ARG_write_perm, ARG_max_length, ARG_fixed_length };
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN } },
+ { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SECURITY_MODE_OPEN } },
+ { MP_QSTR_max_length, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 20} },
+ { MP_QSTR_fixed_length, MP_ARG_KW_ONLY| MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -69,28 +77,28 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar
mp_raise_ValueError(translate("Expected a UUID"));
}
+ const bleio_attribute_security_mode_t read_perm = args[ARG_read_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(read_perm);
+
+ const bleio_attribute_security_mode_t write_perm = args[ARG_write_perm].u_int;
+ common_hal_bleio_attribute_security_mode_check_valid(write_perm);
+
bleio_descriptor_obj_t *self = m_new_obj(bleio_descriptor_obj_t);
self->base.type = type;
bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_arg);
- common_hal_bleio_descriptor_construct(self, uuid);
-
- return MP_OBJ_FROM_PTR(self);
-}
-STATIC mp_obj_t bleio_descriptor_get_handle(mp_obj_t self_in) {
- bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ // 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_descriptor_construct(self, uuid, read_perm, write_perm,
+ args[ARG_max_length].u_int, args[ARG_fixed_length].u_bool);
- return mp_obj_new_int(common_hal_bleio_descriptor_get_handle(self));
+ return MP_OBJ_FROM_PTR(self);
}
-MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_handle_obj, bleio_descriptor_get_handle);
-
-const mp_obj_property_t bleio_descriptor_handle_obj = {
- .base.type = &mp_type_property,
- .proxy = {(mp_obj_t)&bleio_descriptor_get_handle_obj,
- (mp_obj_t)&mp_const_none_obj,
- (mp_obj_t)&mp_const_none_obj},
-};
+//| .. attribute:: uuid
+//|
+//| The descriptor uuid. (read-only)
+//|
STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) {
bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -106,56 +114,59 @@ const mp_obj_property_t bleio_descriptor_uuid_obj = {
(mp_obj_t)&mp_const_none_obj},
};
-STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = {
- // Properties
- { MP_ROM_QSTR(MP_QSTR_handle), MP_ROM_PTR(&bleio_descriptor_handle_obj) },
- { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) },
-
- // Static variables
- { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_EXTENDED_PROPERTIES),
- MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES) },
-
- { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_USER_DESCRIPTION),
- MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION) },
-
- { MP_ROM_QSTR(MP_QSTR_CLIENT_CHARACTERISTIC_CONFIGURATION),
- MP_ROM_INT(DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION) },
-
- { MP_ROM_QSTR(MP_QSTR_SERVER_CHARACTERISTIC_CONFIGURATION),
- MP_ROM_INT(DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION) },
-
- { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_PRESENTATION_FORMAT),
- MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT) },
+//| .. attribute:: characteristic (read-only)
+//|
+//| The Characteristic this Descriptor is a part of. None if not yet assigned to a Characteristic.
+//|
+STATIC mp_obj_t bleio_descriptor_get_characteristic(mp_obj_t self_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
- { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_AGGREGATE_FORMAT),
- MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT) },
+ return common_hal_bleio_descriptor_get_characteristic(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_characteristic_obj, bleio_descriptor_get_characteristic);
- { MP_ROM_QSTR(MP_QSTR_VALID_RANGE),
- MP_ROM_INT(DESCRIPTOR_UUID_VALID_RANGE) },
+const mp_obj_property_t bleio_descriptor_characteristic_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_descriptor_get_characteristic_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
- { MP_ROM_QSTR(MP_QSTR_EXTERNAL_REPORT_REFERENCE),
- MP_ROM_INT(DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE) },
+//| .. attribute:: value
+//|
+//| The value of this descriptor.
+//|
+STATIC mp_obj_t bleio_descriptor_get_value(mp_obj_t self_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
- { MP_ROM_QSTR(MP_QSTR_REPORT_REFERENCE),
- MP_ROM_INT(DESCRIPTOR_UUID_REPORT_REFERENCE) },
+ return common_hal_bleio_descriptor_get_value(self);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_value_obj, bleio_descriptor_get_value);
- { MP_ROM_QSTR(MP_QSTR_NUMBER_OF_DIGITALS),
- MP_ROM_INT(DESCRIPTOR_UUID_NUMBER_OF_DIGITALS) },
+STATIC mp_obj_t bleio_descriptor_set_value(mp_obj_t self_in, mp_obj_t value_in) {
+ bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in);
- { MP_ROM_QSTR(MP_QSTR_VALUE_TRIGGER_SETTING),
- MP_ROM_INT(DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING) },
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(value_in, &bufinfo, MP_BUFFER_READ);
- { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_CONFIGURATION),
- MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION) },
+ common_hal_bleio_descriptor_set_value(self, &bufinfo);
- { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_MEASUREMENT ),
- MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT) },
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_descriptor_set_value_obj, bleio_descriptor_set_value);
- { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_TRIGGER_SETTING),
- MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING) },
+const mp_obj_property_t bleio_descriptor_value_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_descriptor_get_value_obj,
+ (mp_obj_t)&bleio_descriptor_set_value_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
- { MP_ROM_QSTR(MP_QSTR_TIME_TRIGGER_SETTING),
- MP_ROM_INT(DESCRIPTOR_UUID_TIME_TRIGGER_SETTING) },
+STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_descriptor_uuid_obj) },
+ { MP_ROM_QSTR(MP_QSTR_characteristic), MP_ROM_PTR(&bleio_descriptor_characteristic_obj) },
+ { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&bleio_descriptor_value_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_descriptor_locals_dict, bleio_descriptor_locals_dict_table);
diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h
index fd11ea08c..430c0d0b6 100644
--- a/shared-bindings/bleio/Descriptor.h
+++ b/shared-bindings/bleio/Descriptor.h
@@ -28,31 +28,16 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H
+#include "shared-module/bleio/Attribute.h"
#include "common-hal/bleio/Descriptor.h"
#include "common-hal/bleio/UUID.h"
-enum {
- DESCRIPTOR_UUID_CHARACTERISTIC_EXTENDED_PROPERTIES = 0x2900,
- DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION = 0x2901,
- DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION = 0x2902,
- DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION = 0x2903,
- DESCRIPTOR_UUID_CHARACTERISTIC_PRESENTATION_FORMAT = 0x2904,
- DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT = 0x2905,
- DESCRIPTOR_UUID_VALID_RANGE = 0x2906,
- DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE = 0x2907,
- DESCRIPTOR_UUID_REPORT_REFERENCE = 0x2908,
- DESCRIPTOR_UUID_NUMBER_OF_DIGITALS = 0x2909,
- DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING = 0x290A,
- DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION = 0x290B,
- DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT = 0x290C,
- DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING = 0x290D,
- DESCRIPTOR_UUID_TIME_TRIGGER_SETTING = 0x290E,
-};
-
extern const mp_obj_type_t bleio_descriptor_type;
-extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid);
-extern mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self);
-extern mp_obj_t common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self);
+extern void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length);
+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 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
index 570896d27..630e6ed36 100644
--- a/shared-bindings/bleio/Peripheral.c
+++ b/shared-bindings/bleio/Peripheral.c
@@ -44,8 +44,6 @@
#include "common-hal/bleio/Peripheral.h"
-static const char default_name[] = "CIRCUITPY";
-
#define ADV_INTERVAL_DEFAULT (1.0f)
#define ADV_INTERVAL_MIN (0.0020f)
#define ADV_INTERVAL_MIN_STRING "0.0020"
@@ -80,14 +78,14 @@ static const char default_name[] = "CIRCUITPY";
//| # Wait for connection.
//| pass
//|
-//| .. class:: Peripheral(services=(), \*, name='CIRCUITPY')
+//| .. class:: Peripheral(services=(), \*, name=None)
//|
//| Create a new Peripheral object.
//|
//| :param iterable services: the Service objects representing services available from this peripheral, if any.
//| A non-connectable peripheral will have no services.
-//| :param str name: The name used when advertising this peripheral. Use ``None`` when a name is not needed,
-//| such as when the peripheral is a beacon
+//| :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_services, ARG_name };
@@ -107,33 +105,30 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar
self->base.type = &bleio_peripheral_type;
// Copy the services list and validate its items.
- mp_obj_t service_list_obj = mp_obj_new_list(0, NULL);
- mp_obj_list_t *service_list = MP_OBJ_FROM_PTR(service_list_obj);
+ mp_obj_t services_list_obj = mp_obj_new_list(0, NULL);
+ mp_obj_list_t *services_list = MP_OBJ_FROM_PTR(services_list_obj);
mp_obj_t service;
while ((service = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if (!MP_OBJ_IS_TYPE(service, &bleio_service_type)) {
mp_raise_ValueError(translate("non-Service found in services"));
}
- mp_obj_list_append(service_list, service);
+ mp_obj_list_append(services_list, service);
}
- const mp_obj_t name = args[ARG_name].u_obj;
- mp_obj_t name_str;
+ mp_obj_t name = args[ARG_name].u_obj;
if (name == MP_OBJ_NULL || name == mp_const_none) {
- name_str = mp_obj_new_str(default_name, strlen(default_name));
- } else if (MP_OBJ_IS_STR(name)) {
- name_str = name;
- } else {
+ 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, service_list, name_str);
+ common_hal_bleio_peripheral_construct(self, services_list, name);
return MP_OBJ_FROM_PTR(self);
}
-//| .. attribute:: connected
+//| .. attribute:: connected (read-only)
//|
//| True if connected to a BLE Central device.
//|
@@ -158,8 +153,8 @@ const mp_obj_property_t bleio_peripheral_connected_obj = {
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 *service_list = common_hal_bleio_peripheral_get_service_list(self);
- return mp_obj_new_tuple(service_list->len, service_list->items);
+ 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);
@@ -265,16 +260,75 @@ STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) {
}
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_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) },
+ { 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);
diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h
index 846250a5f..597b65ce2 100644
--- a/shared-bindings/bleio/Peripheral.h
+++ b/shared-bindings/bleio/Peripheral.h
@@ -28,16 +28,19 @@
#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"
extern const mp_obj_type_t bleio_peripheral_type;
extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name);
-extern mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self);
+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/Service.c b/shared-bindings/bleio/Service.c
index db0606991..6961b0b52 100644
--- a/shared-bindings/bleio/Service.c
+++ b/shared-bindings/bleio/Service.c
@@ -43,12 +43,16 @@
//| .. class:: Service(uuid, characteristics, *, secondary=False)
//|
//| Create a new Service object identified by the specified UUID.
+//|
//| To mark the service as secondary, pass `True` as :py:data:`secondary`.
//|
//| :param bleio.UUID uuid: The uuid of the service
//| :param iterable characteristics: the Characteristic objects for this service
//| :param bool secondary: If the service is a secondary one
//|
+//| A Service may be remote (:py:data:`remote` is ``True``), but a remote Service
+//| cannot be constructed directly. It is created by `Central.discover_remote_services()`
+//| or `Peripheral.discover_remote_services()`.
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_characteristics, ARG_secondary };
@@ -92,6 +96,9 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args,
// The descriptor base UUID doesn't match the characteristic base UUID.
mp_raise_ValueError(translate("Characteristic UUID doesn't match Service UUID"));
}
+ if (common_hal_bleio_characteristic_get_service(characteristic) != MP_OBJ_NULL) {
+ mp_raise_ValueError(translate("Characteristic is already attached to a Service"));
+ }
mp_obj_list_append(char_list_obj, characteristic_obj);
}
@@ -119,6 +126,24 @@ const mp_obj_property_t bleio_service_characteristics_obj = {
(mp_obj_t)&mp_const_none_obj },
};
+//| .. attribute:: remote
+//|
+//| True if this is a service provided by a remote device. (read-only)
+//|
+STATIC mp_obj_t bleio_service_get_remote(mp_obj_t self_in) {
+ bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return mp_obj_new_bool(common_hal_bleio_service_get_is_remote(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_remote_obj, bleio_service_get_remote);
+
+const mp_obj_property_t bleio_service_remote_obj = {
+ .base.type = &mp_type_property,
+ .proxy = { (mp_obj_t)&bleio_service_get_remote_obj,
+ (mp_obj_t)&mp_const_none_obj,
+ (mp_obj_t)&mp_const_none_obj },
+};
+
//| .. attribute:: secondary
//|
//| True if this is a secondary service. (read-only)
diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h
index f646c81a9..716c2e8a9 100644
--- a/shared-bindings/bleio/Service.h
+++ b/shared-bindings/bleio/Service.h
@@ -35,6 +35,7 @@ const mp_obj_type_t bleio_service_type;
extern void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, mp_obj_list_t *characteristic_list, 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_all_characteristics(bleio_service_obj_t *self);
diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c
index ba3bae6c7..739f461a5 100644
--- a/shared-bindings/bleio/__init__.c
+++ b/shared-bindings/bleio/__init__.c
@@ -28,24 +28,30 @@
#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/Descriptor.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/Service.h"
#include "shared-bindings/bleio/UUID.h"
-//| :mod:`bleio` --- Bluetooth Low Energy functionality
+//| :mod:`bleio` --- Bluetooth Low Energy (BLE) communication
//| ================================================================
//|
//| .. module:: bleio
//| :synopsis: Bluetooth Low Energy functionality
//| :platform: nRF
//|
-//| The `bleio` module contains methods for managing the BLE adapter.
+//| The `bleio` module provides necessary low-level functionality for communicating
+//| using Bluetooth Low Energy (BLE). We recommend you use `bleio` in conjunction
+//| with the `adafruit_ble <https://circuitpython.readthedocs.io/projects/ble/en/latest/>`_
+//| CircuitPython library, which builds on `bleio`, and
+//| provides higher-level convenience functionality, including predefined beacons, clients,
+//| servers.
//|
//| Libraries
//|
@@ -54,6 +60,7 @@
//|
//| Address
//| Adapter
+//| Attribute
//| Central
//| Characteristic
//| CharacteristicBuffer
@@ -72,20 +79,21 @@
//|
STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) },
- { MP_ROM_QSTR(MP_QSTR_Address), MP_ROM_PTR(&bleio_address_type) },
- { MP_ROM_QSTR(MP_QSTR_Central), MP_ROM_PTR(&bleio_central_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_Service), MP_ROM_PTR(&bleio_service_type) },
- { MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&bleio_uuid_type) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bleio) },
+ { 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_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_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) },
+ { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table);
diff --git a/shared-bindings/bleio/__init__.h b/shared-bindings/bleio/__init__.h
index 4aa6dd45b..6a4c804f5 100644
--- a/shared-bindings/bleio/__init__.h
+++ b/shared-bindings/bleio/__init__.h
@@ -29,8 +29,24 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
+#include "py/objlist.h"
+
+#include "shared-bindings/bleio/__init__.h"
+#include "shared-bindings/bleio/Adapter.h"
+
#include "common-hal/bleio/Adapter.h"
extern const super_adapter_obj_t common_hal_bleio_adapter_obj;
+extern void common_hal_bleio_check_connected(uint16_t conn_handle);
+
+extern uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device);
+extern mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device);
+extern void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist);
+
+extern mp_obj_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle);
+extern void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo);
+extern void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response);
+
+
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H
diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c
index af64a2028..0d41359ee 100644
--- a/shared-bindings/displayio/FourWire.c
+++ b/shared-bindings/displayio/FourWire.c
@@ -119,9 +119,7 @@ STATIC mp_obj_t displayio_fourwire_obj_send(mp_obj_t self, mp_obj_t command_obj,
// Wait for display bus to be available.
while (!common_hal_displayio_fourwire_begin_transaction(self)) {
-#ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP ;
-#endif
+ RUN_BACKGROUND_TASKS;
}
common_hal_displayio_fourwire_send(self, true, &command, 1);
common_hal_displayio_fourwire_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len);
diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c
index 1f74e8c9e..9ef989d71 100644
--- a/shared-bindings/displayio/I2CDisplay.c
+++ b/shared-bindings/displayio/I2CDisplay.c
@@ -111,9 +111,7 @@ STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_ob
// Wait for display bus to be available.
while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) {
-#ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP ;
-#endif
+ RUN_BACKGROUND_TASKS;
}
uint8_t full_command[bufinfo.len + 1];
full_command[0] = command;
diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c
index 00a96d230..c29c79fff 100644
--- a/shared-bindings/displayio/ParallelBus.c
+++ b/shared-bindings/displayio/ParallelBus.c
@@ -122,9 +122,7 @@ STATIC mp_obj_t displayio_parallelbus_obj_send(mp_obj_t self, mp_obj_t command_o
// Wait for display bus to be available.
while (!common_hal_displayio_parallelbus_begin_transaction(self)) {
-#ifdef MICROPY_VM_HOOK_LOOP
- MICROPY_VM_HOOK_LOOP ;
-#endif
+ RUN_BACKGROUND_TASKS;
}
common_hal_displayio_parallelbus_send(self, true, &command, 1);
common_hal_displayio_parallelbus_send(self, false, ((uint8_t*) bufinfo.buf), bufinfo.len);
diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c
index 6ba4914a0..53fbb51c8 100644
--- a/shared-bindings/displayio/TileGrid.c
+++ b/shared-bindings/displayio/TileGrid.c
@@ -131,7 +131,8 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_
displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t);
self->base.type = &displayio_tilegrid_type;
- common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width,
+ common_hal_displayio_tilegrid_construct(self, native,
+ bitmap_width / tile_width, bitmap_height / tile_height,
pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int,
tile_width, tile_height, x, y, args[ARG_default_tile].u_int);
return MP_OBJ_FROM_PTR(self);
@@ -346,7 +347,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v
}
if (x >= common_hal_displayio_tilegrid_get_width(self) ||
y >= common_hal_displayio_tilegrid_get_height(self)) {
- mp_raise_IndexError(translate("tile index out of bounds"));
+ mp_raise_IndexError(translate("Tile index out of bounds"));
}
if (value_obj == MP_OBJ_SENTINEL) {
@@ -357,7 +358,7 @@ STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t v
} else {
mp_int_t value = mp_obj_get_int(value_obj);
if (value < 0 || value > 255) {
- mp_raise_ValueError(translate("Tile indices must be 0 - 255"));
+ mp_raise_ValueError(translate("Tile value out of bounds"));
}
common_hal_displayio_tilegrid_set_tile(self, x, y, value);
}
diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h
index 1f9995a94..8227abfd3 100644
--- a/shared-bindings/displayio/TileGrid.h
+++ b/shared-bindings/displayio/TileGrid.h
@@ -32,7 +32,8 @@
extern const mp_obj_type_t displayio_tilegrid_type;
void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap,
- uint16_t bitmap_width_in_tiles, mp_obj_t pixel_shader, uint16_t width, uint16_t height,
+ uint16_t bitmap_width_in_tiles, uint16_t bitmap_height_in_tiles,
+ mp_obj_t pixel_shader, uint16_t width, uint16_t height,
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile);
mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self);
diff --git a/shared-bindings/i2cslave/I2CSlave.c b/shared-bindings/i2cslave/I2CSlave.c
index 2598accbb..c98ea52e0 100644
--- a/shared-bindings/i2cslave/I2CSlave.c
+++ b/shared-bindings/i2cslave/I2CSlave.c
@@ -182,7 +182,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request(size_t n_args, const mp_obj_t *pos_ar
bool is_read;
bool is_restart;
- MICROPY_VM_HOOK_LOOP
+ RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
return mp_const_none;
}
@@ -337,7 +337,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request_read(size_t n_args, const mp_obj_t *p
uint8_t *buffer = NULL;
uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000;
while (common_hal_time_monotonic() < timeout_end) {
- MICROPY_VM_HOOK_LOOP
+ RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
break;
}
@@ -382,7 +382,7 @@ STATIC mp_obj_t i2cslave_i2c_slave_request_write(mp_obj_t self_in, mp_obj_t buf_
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
for (size_t i = 0; i < bufinfo.len; i++) {
- MICROPY_VM_HOOK_LOOP
+ RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
break;
}
diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c
index 70c01c2d8..2654de09a 100644
--- a/shared-bindings/time/__init__.c
+++ b/shared-bindings/time/__init__.c
@@ -99,16 +99,17 @@ mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp
//|
//| Structure used to capture a date and time. Note that it takes a tuple!
//|
-//| :param Tuple[tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst] time_tuple: Tuple of time info.
-//| * the year, 2017 for example
-//| * the month, range [1, 12]
-//| * the day of the month, range [1, 31]
-//| * the hour, range [0, 23]
-//| * the minute, range [0, 59]
-//| * the second, range [0, 61]
-//| * the day of the week, range [0, 6], Monday is 0
-//| * the day of the year, range [1, 366], -1 indicates not known
-//| * 1 when in daylight savings, 0 when not, -1 if unknown.
+//| :param tuple time_tuple: Tuple of time info: ``(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)``
+//|
+//| * ``tm_year``: the year, 2017 for example
+//| * ``tm_month``: the month, range [1, 12]
+//| * ``tm_mday``: the day of the month, range [1, 31]
+//| * ``tm_hour``: the hour, range [0, 23]
+//| * ``tm_minute``: the minute, range [0, 59]
+//| * ``tm_sec``: the second, range [0, 61]
+//| * ``tm_wday``: the day of the week, range [0, 6], Monday is 0
+//| * ``tm_yday``: the day of the year, range [1, 366], -1 indicates not known
+//| * ``tm_isdst``: 1 when in daylight savings, 0 when not, -1 if unknown.
//|
const mp_obj_namedtuple_type_t struct_time_type_obj = {
.base = {
@@ -235,9 +236,16 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
return rtc_get_time_source_time();
}
- mp_int_t secs = mp_obj_int_get_checked(args[0]);
- if (secs < EPOCH1970_EPOCH2000_DIFF_SECS)
+ mp_obj_t arg = args[0];
+ if (mp_obj_is_float(arg)) {
+ arg = mp_obj_new_int_from_float(mp_obj_get_float(arg));
+ }
+
+ mp_int_t secs = mp_obj_get_int(arg);
+
+ if (secs < EPOCH1970_EPOCH2000_DIFF_SECS) {
mp_raise_msg(&mp_type_OverflowError, translate("timestamp out of range for platform time_t"));
+ }
timeutils_struct_time_t tm;
timeutils_seconds_since_epoch_to_struct_time(secs, &tm);
@@ -269,8 +277,9 @@ STATIC mp_obj_t time_mktime(mp_obj_t t) {
mp_raise_TypeError(translate("function takes exactly 9 arguments"));
}
- if (mp_obj_get_int(elem[0]) < 2000)
+ if (mp_obj_get_int(elem[0]) < 2000) {
mp_raise_msg(&mp_type_OverflowError, translate("timestamp out of range for platform time_t"));
+ }
mp_uint_t secs = timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]),
mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]));