From 4a6bdb6fe471b3024b2ca1d977ef02bfd94cc12a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 Jul 2019 16:47:28 -0700 Subject: Track a dirty area for in-memory bitmaps This fixes the bug that bitmap changes do not cause screen updates and optimizes the refresh when the bitmap is simply shown on the screen. If the bitmap is used in tiles, then changing it will cause all TileGrids using it to do a full refresh. Fixes #1981 --- shared-module/displayio/Bitmap.c | 38 ++++++++++++++++++++++++++++++++++++++ shared-module/displayio/Bitmap.h | 5 +++++ shared-module/displayio/TileGrid.c | 32 +++++++++++++++++++++++++++++--- shared-module/displayio/TileGrid.h | 3 ++- 4 files changed, 74 insertions(+), 4 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index f8dc24c15..59971d25c 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -63,6 +63,11 @@ void common_hal_displayio_bitmap_construct(displayio_bitmap_t *self, uint32_t wi } self->x_mask = (1 << self->x_shift) - 1; // Used as a modulus on the x value self->bitmask = (1 << bits_per_value) - 1; + + self->dirty_area.x1 = 0; + self->dirty_area.x2 = width; + self->dirty_area.y1 = 0; + self->dirty_area.y2 = height; } uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self) { @@ -104,6 +109,26 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); } + // Update the dirty area. + if (self->dirty_area.x1 == self->dirty_area.x2) { + self->dirty_area.x1 = x; + self->dirty_area.x2 = x + 1; + self->dirty_area.y1 = y; + self->dirty_area.y2 = y + 1; + } else { + if (x < self->dirty_area.x1) { + self->dirty_area.x1 = x; + } else if (x >= self->dirty_area.x2) { + self->dirty_area.x2 = x + 1; + } + if (y < self->dirty_area.y1) { + self->dirty_area.y1 = y; + } else if (y >= self->dirty_area.y2) { + self->dirty_area.y2 = y + 1; + } + } + + // Update our data int32_t row_start = y * self->stride; uint32_t bytes_per_value = self->bits_per_value / 8; if (bytes_per_value < 1) { @@ -124,3 +149,16 @@ void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, } } } + +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail) { + if (self->dirty_area.x1 == self->dirty_area.x2) { + return tail; + } + self->dirty_area.next = tail; + return &self->dirty_area; +} + +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self) { + self->dirty_area.x1 = 0; + self->dirty_area.x2 = 0; +} diff --git a/shared-module/displayio/Bitmap.h b/shared-module/displayio/Bitmap.h index 48ca9e2cf..f4bd7ce4d 100644 --- a/shared-module/displayio/Bitmap.h +++ b/shared-module/displayio/Bitmap.h @@ -31,6 +31,7 @@ #include #include "py/obj.h" +#include "shared-module/displayio/area.h" typedef struct { mp_obj_base_t base; @@ -41,8 +42,12 @@ typedef struct { uint8_t bits_per_value; uint8_t x_shift; size_t x_mask; + displayio_area_t dirty_area; uint16_t bitmask; bool read_only; } displayio_bitmap_t; +void displayio_bitmap_finish_refresh(displayio_bitmap_t *self); +displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index cdca45a29..31abfb712 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -26,6 +26,7 @@ #include "shared-bindings/displayio/TileGrid.h" +#include "py/runtime.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/OnDiskBitmap.h" @@ -33,7 +34,7 @@ #include "shared-bindings/displayio/Shape.h" void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_t bitmap, - uint16_t bitmap_width_in_tiles, + 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) { uint32_t total_tiles = width * height; @@ -54,6 +55,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ self->inline_tiles = false; } self->bitmap_width_in_tiles = bitmap_width_in_tiles; + self->tiles_in_bitmap = bitmap_width_in_tiles * bitmap_height_in_tiles; self->width_in_tiles = width; self->height_in_tiles = height; self->x = x; @@ -204,6 +206,9 @@ uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint1 } void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index) { + if (tile_index >= self->tiles_in_bitmap) { + mp_raise_ValueError(translate("Tile value out of bounds")); + } uint8_t* tiles = self->tiles; if (self->inline_tiles) { tiles = (uint8_t*) &self->tiles; @@ -442,6 +447,14 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { } else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) { displayio_colorconverter_finish_refresh(self->pixel_shader); } + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_bitmap_finish_refresh(self->bitmap); + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + // TODO: Support shape changes. + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { + // OnDiskBitmap changes will trigger a complete reload so no need to + // track changes. + } // TODO(tannewt): We could double buffer changes to position and move them over here. // That way they won't change during a refresh and tear. } @@ -458,8 +471,21 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel return &self->current_area; } - // We must recheck if our sources require a refresh because needs_refresh may or may not have - // been called. + // If we have an in-memory bitmap, then check it for modifications. + if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { + displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); + if (refresh_area != tail) { + // Special case a TileGrid that shows a full bitmap and use it's + // dirty area. Copy it to ours so we can transform it. + if (self->tiles_in_bitmap == 1) { + displayio_area_copy(refresh_area, &self->dirty_area); + self->partial_change = true; + } else { + self->full_change = true; + } + } + } + self->full_change = self->full_change || (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && displayio_palette_needs_refresh(self->pixel_shader)) || diff --git a/shared-module/displayio/TileGrid.h b/shared-module/displayio/TileGrid.h index 4d97eccc2..160b920dd 100644 --- a/shared-module/displayio/TileGrid.h +++ b/shared-module/displayio/TileGrid.h @@ -41,7 +41,8 @@ typedef struct { int16_t y; uint16_t pixel_width; uint16_t pixel_height; - uint16_t bitmap_width_in_tiles; + uint16_t bitmap_width_in_tiles;; + uint8_t tiles_in_bitmap; uint16_t width_in_tiles; uint16_t height_in_tiles; uint16_t tile_width; -- cgit v1.2.3 From d9089f52ce92519448c88ef50655b31e123b23bd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 19 Jul 2019 10:42:20 -0700 Subject: Fix it's -> its --- shared-module/displayio/TileGrid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 31abfb712..ec3950492 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -475,7 +475,7 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { displayio_area_t* refresh_area = displayio_bitmap_get_refresh_areas(self->bitmap, tail); if (refresh_area != tail) { - // Special case a TileGrid that shows a full bitmap and use it's + // Special case a TileGrid that shows a full bitmap and use its // dirty area. Copy it to ours so we can transform it. if (self->tiles_in_bitmap == 1) { displayio_area_copy(refresh_area, &self->dirty_area); -- cgit v1.2.3 From 54cde56ec5374f9b6c1aa9eb9dd6139b80df254a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 25 Jul 2019 17:55:57 -0500 Subject: audiopwmio: Add the shared files for this new module --- py/circuitpy_defns.mk | 6 + py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 9 ++ shared-bindings/audiopwmio/AudioOut.c | 294 ++++++++++++++++++++++++++++++++++ shared-bindings/audiopwmio/AudioOut.h | 49 ++++++ shared-bindings/audiopwmio/__init__.c | 71 ++++++++ shared-bindings/audiopwmio/__init__.h | 34 ++++ shared-module/audiopwmio/__init__.c | 0 shared-module/audiopwmio/__init__.h | 32 ++++ 9 files changed, 503 insertions(+) create mode 100644 shared-bindings/audiopwmio/AudioOut.c create mode 100644 shared-bindings/audiopwmio/AudioOut.h create mode 100644 shared-bindings/audiopwmio/__init__.c create mode 100644 shared-bindings/audiopwmio/__init__.h create mode 100644 shared-module/audiopwmio/__init__.c create mode 100644 shared-module/audiopwmio/__init__.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc..28d560a73 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -108,6 +108,9 @@ endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +SRC_PATTERNS += audiopwmio/% +endif ifeq ($(CIRCUITPY_AUDIOCORE),1) SRC_PATTERNS += audiocore/% endif @@ -223,6 +226,8 @@ $(filter $(SRC_PATTERNS), \ audiobusio/__init__.c \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ + audiopwmio/__init__.c \ + audiopwmio/AudioOut.c \ audioio/__init__.c \ audioio/AudioOut.c \ bleio/__init__.c \ @@ -303,6 +308,7 @@ $(filter $(SRC_PATTERNS), \ _stage/Layer.c \ _stage/Text.c \ _stage/__init__.c \ + audiopwmio/__init__.c \ audioio/__init__.c \ audiocore/__init__.c \ audiocore/Mixer.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 3440eb052..d88d6538e 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -244,6 +244,13 @@ extern const struct _mp_obj_module_t audioio_module; #define AUDIOIO_MODULE #endif +#if CIRCUITPY_AUDIOPWMIO +#define AUDIOPWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_audiopwmio), (mp_obj_t)&audiopwmio_module }, +extern const struct _mp_obj_module_t audiopwmio_module; +#else +#define AUDIOPWMIO_MODULE +#endif + #if CIRCUITPY_BITBANGIO #define BITBANGIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }, extern const struct _mp_obj_module_t bitbangio_module; @@ -573,6 +580,7 @@ extern const struct _mp_obj_module_t ustack_module; AUDIOBUSIO_MODULE \ AUDIOCORE_MODULE \ AUDIOIO_MODULE \ + AUDIOPWMIO_MODULE \ BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 772a1c3e1..a408cd7ac 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -74,9 +74,18 @@ CIRCUITPY_AUDIOIO = $(CIRCUITPY_FULL_BUILD) endif CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) +ifndef CIRCUITPY_AUDIOPWMIO +CIRCUITPY_AUDIOPWMIO = 0 +endif +CFLAGS += -DCIRCUITPY_AUDIOPWMIO=$(CIRCUITPY_AUDIOPWMIO) + ifndef CIRCUITPY_AUDIOCORE +ifeq ($(CIRCUITPY_AUDIOPWMIO),1) +CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOPWMIO) +else CIRCUITPY_AUDIOCORE = $(CIRCUITPY_AUDIOIO) endif +endif CFLAGS += -DCIRCUITPY_AUDIOCORE=$(CIRCUITPY_AUDIOCORE) ifndef CIRCUITPY_BITBANGIO diff --git a/shared-bindings/audiopwmio/AudioOut.c b/shared-bindings/audiopwmio/AudioOut.c new file mode 100644 index 000000000..37c845165 --- /dev/null +++ b/shared-bindings/audiopwmio/AudioOut.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 + +#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/AudioOut.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: audiopwmio +//| +//| :class:`AudioOut` -- Output an analog audio signal +//| ======================================================== +//| +//| AudioOut can be used to output an analog audio signal on a given pin. +//| +//| .. class:: AudioOut(left_channel, *, right_channel=None, quiescent_value=0x8000) +//| +//| Create a AudioOut 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.AudioOut(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.AudioOut(board.SPEAKER) +//| +//| print("playing") +//| a.play(wav) +//| while a.playing: +//| pass +//| print("stopped") +//| +STATIC mp_obj_t audiopwmio_audioout_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_audioout_obj_t *self = m_new_obj(audiopwmio_audioout_obj_t); + self->base.type = &audiopwmio_audioout_type; + common_hal_audiopwmio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the AudioOut and releases any hardware resources for reuse. +//| +STATIC mp_obj_t audiopwmio_audioout_deinit(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiopwmio_audioout_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_deinit_obj, audiopwmio_audioout_deinit); + +STATIC void check_for_deinit(audiopwmio_audioout_obj_t *self) { + if (common_hal_audiopwmio_audioout_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_audioout_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiopwmio_audioout_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiopwmio_audioout___exit___obj, 4, 4, audiopwmio_audioout_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 `audiopwmio.WaveFile` or `audiopwmio.RawSample`. +//| +//| 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_audioout_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_audioout_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_audioout_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiopwmio_audioout_play_obj, 1, audiopwmio_audioout_obj_play); + +//| .. method:: stop() +//| +//| Stops playback and resets to the start of the sample. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_stop(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiopwmio_audioout_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_stop_obj, audiopwmio_audioout_obj_stop); + +//| .. attribute:: playing +//| +//| True when an audio sample is being output even if `paused`. (read-only) +//| +STATIC mp_obj_t audiopwmio_audioout_obj_get_playing(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiopwmio_audioout_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_get_playing_obj, audiopwmio_audioout_obj_get_playing); + +const mp_obj_property_t audiopwmio_audioout_playing_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_audioout_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_audioout_obj_pause(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_audiopwmio_audioout_get_playing(self)) { + mp_raise_RuntimeError(translate("Not playing")); + } + common_hal_audiopwmio_audioout_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_pause_obj, audiopwmio_audioout_obj_pause); + +//| .. method:: resume() +//| +//| Resumes sample playback after :py:func:`pause`. +//| +STATIC mp_obj_t audiopwmio_audioout_obj_resume(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_audiopwmio_audioout_get_paused(self)) { + common_hal_audiopwmio_audioout_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_resume_obj, audiopwmio_audioout_obj_resume); + +//| .. attribute:: paused +//| +//| True when playback is paused. (read-only) +//| +STATIC mp_obj_t audiopwmio_audioout_obj_get_paused(mp_obj_t self_in) { + audiopwmio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiopwmio_audioout_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiopwmio_audioout_get_paused_obj, audiopwmio_audioout_obj_get_paused); + +const mp_obj_property_t audiopwmio_audioout_paused_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&audiopwmio_audioout_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_audioout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiopwmio_audioout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiopwmio_audioout___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiopwmio_audioout_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiopwmio_audioout_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&audiopwmio_audioout_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&audiopwmio_audioout_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiopwmio_audioout_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&audiopwmio_audioout_paused_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(audiopwmio_audioout_locals_dict, audiopwmio_audioout_locals_dict_table); + +const mp_obj_type_t audiopwmio_audioout_type = { + { &mp_type_type }, + .name = MP_QSTR_PWMAudioOut, + .make_new = audiopwmio_audioout_make_new, + .locals_dict = (mp_obj_dict_t*)&audiopwmio_audioout_locals_dict, +}; diff --git a/shared-bindings/audiopwmio/AudioOut.h b/shared-bindings/audiopwmio/AudioOut.h new file mode 100644 index 000000000..7fb0e0f33 --- /dev/null +++ b/shared-bindings/audiopwmio/AudioOut.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/AudioOut.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/audiocore/RawSample.h" + +extern const mp_obj_type_t audiopwmio_audioout_type; + +// left_channel will always be non-NULL but right_channel may be for mono output. +void common_hal_audiopwmio_audioout_construct(audiopwmio_audioout_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_audioout_deinit(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_deinited(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_play(audiopwmio_audioout_obj_t* self, mp_obj_t sample, bool loop); +void common_hal_audiopwmio_audioout_stop(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_get_playing(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_pause(audiopwmio_audioout_obj_t* self); +void common_hal_audiopwmio_audioout_resume(audiopwmio_audioout_obj_t* self); +bool common_hal_audiopwmio_audioout_get_paused(audiopwmio_audioout_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..6253d1e8e --- /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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiopwmio/__init__.h" +#include "shared-bindings/audiopwmio/AudioOut.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 +//| +//| AudioOut +//| +//| 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_AudioOut), MP_ROM_PTR(&audiopwmio_audioout_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-module/audiopwmio/__init__.c b/shared-module/audiopwmio/__init__.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/audiopwmio/__init__.h b/shared-module/audiopwmio/__init__.h new file mode 100644 index 000000000..964e4aafe --- /dev/null +++ b/shared-module/audiopwmio/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_MODULE_AUDIOPWMIO__INIT__H +#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H + +#include "shared-module/audiocore/__init__.h" + +#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOPWMIO__INIT__H -- cgit v1.2.3 From 7b9d26cefe02d1a357b2594339db474b7c5cd88e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 15 Jul 2019 19:56:21 -0500 Subject: WavFile.h: include vfs_fat.h for pyb_file_obj_t definition Without such a definition, this header is not self-contained, but requires whoever included it to also include vfs_fat.h --- shared-module/audiocore/WaveFile.h | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/audiocore/WaveFile.h b/shared-module/audiocore/WaveFile.h index 97dd6a46f..3eecbf15c 100644 --- a/shared-module/audiocore/WaveFile.h +++ b/shared-module/audiocore/WaveFile.h @@ -27,6 +27,7 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H #define MICROPY_INCLUDED_SHARED_MODULE_AUDIOIO_WAVEFILE_H +#include "extmod/vfs_fat.h" #include "py/obj.h" #include "shared-module/audiocore/__init__.h" -- cgit v1.2.3 From 28ca05ccdcf674ad128f357ac8f54a1931560331 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 27 Jul 2019 13:20:59 -0400 Subject: allow discovery from central or peripheral --- ports/nrf/boards/make-pins.py | 208 ------------ ports/nrf/common-hal/bleio/Central.c | 335 +------------------- ports/nrf/common-hal/bleio/Central.h | 4 +- ports/nrf/common-hal/bleio/Characteristic.c | 66 ++-- ports/nrf/common-hal/bleio/CharacteristicBuffer.c | 2 +- ports/nrf/common-hal/bleio/Peripheral.c | 15 +- ports/nrf/common-hal/bleio/Peripheral.h | 6 +- ports/nrf/common-hal/bleio/Service.c | 5 + ports/nrf/common-hal/bleio/Service.h | 2 + ports/nrf/common-hal/bleio/__init__.c | 365 +++++++++++++++++++++- ports/nrf/common-hal/bleio/__init__.h | 8 +- ports/nrf/nrfx_config.h | 1 + ports/nrf/peripherals/nrf/timers.c | 2 +- shared-bindings/bleio/Central.c | 77 +++-- shared-bindings/bleio/Central.h | 2 +- shared-bindings/bleio/Peripheral.c | 72 ++++- shared-bindings/bleio/Peripheral.h | 2 +- shared-bindings/bleio/Service.c | 22 ++ shared-bindings/bleio/Service.h | 1 + shared-bindings/bleio/__init__.h | 11 + shared-module/bleio/__init__.h | 6 - 21 files changed, 564 insertions(+), 648 deletions(-) delete mode 100644 ports/nrf/boards/make-pins.py (limited to 'shared-module') diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py deleted file mode 100644 index d1cfd5b70..000000000 --- a/ports/nrf/boards/make-pins.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -"""Creates the pin file for the nRF5.""" - -from __future__ import print_function - -import argparse -import sys -import csv - - -def parse_port_pin(name_str): - """Parses a string and returns a (port-num, pin-num) tuple.""" - if len(name_str) < 4: - raise ValueError("Expecting pin name to be at least 5 charcters.") - if name_str[0] != 'P': - raise ValueError("Expecting pin name to start with P") - if name_str[1] not in ('0', '1'): - raise ValueError("Expecting pin port to be in 0 or 1") - port = ord(name_str[1]) - ord('0') - pin_str = name_str[3:] - if not pin_str.isdigit(): - raise ValueError("Expecting numeric pin number.") - return (port, int(pin_str)) - - -class Pin(object): - """Holds the information associated with a pin.""" - - def __init__(self, port, pin): - self.port = port - self.pin = pin - self.adc_channel = '0' - self.board_pin = False - - def cpu_pin_name(self): - return 'P{:d}_{:02d}'.format(self.port, self.pin) - - def is_board_pin(self): - return self.board_pin - - def set_is_board_pin(self): - self.board_pin = True - - def parse_adc(self, adc_str): - if (adc_str[:3] != 'AIN'): - return - self.adc_channel = 'SAADC_CH_PSELP_PSELP_AnalogInput%d' % int(adc_str[3]) - - def print(self): - print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s});'.format( - self.cpu_pin_name(), self.cpu_pin_name(), - self.port, self.pin, self.adc_channel)) - - def print_header(self, hdr_file): - hdr_file.write('extern const pin_obj_t pin_{:s};\n'. - format(self.cpu_pin_name())) - - -class NamedPin(object): - - def __init__(self, name, pin): - self._name = name - self._pin = pin - - def pin(self): - return self._pin - - def name(self): - return self._name - - -class Pins(object): - - def __init__(self): - self.cpu_pins = [] # list of NamedPin objects - self.board_pins = [] # list of NamedPin objects - - def find_pin(self, port_num, pin_num): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.port == port_num and pin.pin == pin_num: - return pin - - def parse_af_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[0]) - except: - continue - pin = Pin(port_num, pin_num) - if len(row) > 1: - pin.parse_adc(row[1]) - self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin)) - - def parse_board_file(self, filename): - with open(filename, 'r') as csvfile: - rows = csv.reader(csvfile) - for row in rows: - try: - (port_num, pin_num) = parse_port_pin(row[1]) - except: - continue - pin = self.find_pin(port_num, pin_num) - if pin: - pin.set_is_board_pin() - self.board_pins.append(NamedPin(row[0], pin)) - - def print_named(self, label, named_pins): - print('') - print('STATIC const mp_rom_map_elem_t {:s}_table[] = {{'.format(label)) - for named_pin in named_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name())) - print('};') - print('MP_DEFINE_CONST_DICT({:s}, {:s}_table);'.format(label, label)) - - def print(self): - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print() - self.print_named('mcu_pin_globals', self.cpu_pins) - self.print_named('board_module_globals', self.board_pins) - - def print_header(self, hdr_filename): - with open(hdr_filename, 'wt') as hdr_file: - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - pin.print_header(hdr_file) - - def print_qstr(self, qstr_filename): - with open(qstr_filename, 'wt') as qstr_file: - qstr_set = set([]) - for named_pin in self.cpu_pins: - pin = named_pin.pin() - if pin.is_board_pin(): - qstr_set |= set([named_pin.name()]) - for named_pin in self.board_pins: - qstr_set |= set([named_pin.name()]) - for qstr in sorted(qstr_set): - print('Q({})'.format(qstr), file=qstr_file) - - -def main(): - parser = argparse.ArgumentParser( - prog="make-pins.py", - usage="%(prog)s [options] [command]", - description="Generate board specific pin file" - ) - parser.add_argument( - "-a", "--af", - dest="af_filename", - help="Specifies the alternate function file for the chip", - default="nrf_af.csv" - ) - parser.add_argument( - "-b", "--board", - dest="board_filename", - help="Specifies the board file", - ) - parser.add_argument( - "-p", "--prefix", - dest="prefix_filename", - help="Specifies beginning portion of generated pins file", - default="nrf52_prefix.c" - ) - parser.add_argument( - "-q", "--qstr", - dest="qstr_filename", - help="Specifies name of generated qstr header file", - default="build/pins_qstr.h" - ) - parser.add_argument( - "-r", "--hdr", - dest="hdr_filename", - help="Specifies name of generated pin header file", - default="build/pins.h" - ) - args = parser.parse_args(sys.argv[1:]) - - pins = Pins() - - print('// This file was automatically generated by make-pins.py') - print('//') - if args.af_filename: - print('// --af {:s}'.format(args.af_filename)) - pins.parse_af_file(args.af_filename) - - if args.board_filename: - print('// --board {:s}'.format(args.board_filename)) - pins.parse_board_file(args.board_filename) - - if args.prefix_filename: - print('// --prefix {:s}'.format(args.prefix_filename)) - print('') - with open(args.prefix_filename, 'r') as prefix_file: - print(prefix_file.read()) - pins.print() - pins.print_header(args.hdr_filename) - pins.print_qstr(args.qstr_filename) - - -if __name__ == "__main__": - main() diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c index d90737411..c42a2084a 100644 --- a/ports/nrf/common-hal/bleio/Central.c +++ b/ports/nrf/common-hal/bleio/Central.c @@ -35,216 +35,8 @@ #include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Central.h" -#include "shared-bindings/bleio/Descriptor.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" - -static bleio_service_obj_t *m_char_discovery_service; -static bleio_characteristic_obj_t *m_desc_discovery_characteristic; - -static volatile bool m_discovery_in_process; -static volatile bool m_discovery_successful; - -// service_uuid may be NULL, to discover all services. -STATIC bool discover_next_services(bleio_central_obj_t *self, uint16_t start_handle, ble_uuid_t *service_uuid) { - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_primary_services_discover(self->conn_handle, start_handle, service_uuid); - - if (err_code != NRF_SUCCESS) { - mp_raise_OSError_msg(translate("Failed to discover services")); - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_characteristics(bleio_central_obj_t *self, bleio_service_obj_t *service, uint16_t start_handle) { - m_char_discovery_service = service; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = service->end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_characteristics_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC bool discover_next_descriptors(bleio_central_obj_t *self, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { - m_desc_discovery_characteristic = characteristic; - - ble_gattc_handle_range_t handle_range; - handle_range.start_handle = start_handle; - handle_range.end_handle = end_handle; - - m_discovery_successful = false; - m_discovery_in_process = true; - - uint32_t err_code = sd_ble_gattc_descriptors_discover(self->conn_handle, &handle_range); - if (err_code != NRF_SUCCESS) { - return false; - } - - // Wait for a discovery event. - while (m_discovery_in_process) { - MICROPY_VM_HOOK_LOOP; - } - return m_discovery_successful; -} - -STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_service_t *gattc_service = &response->services[i]; - - bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); - service->base.type = &bleio_service_type; - - // Initialize several fields at once. - common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); - - service->device = MP_OBJ_FROM_PTR(central); - service->start_handle = gattc_service->handle_range.start_handle; - service->end_handle = gattc_service->handle_range.end_handle; - service->handle = gattc_service->handle_range.start_handle; - - if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known service UUID. - bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); - service->uuid = uuid; - service->device = MP_OBJ_FROM_PTR(central); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just set the UUID to NULL. - service->uuid = NULL; - } - - mp_obj_list_append(central->service_list, service); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_char_t *gattc_char = &response->chars[i]; - - bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); - characteristic->base.type = &bleio_characteristic_type; - - characteristic->descriptor_list = mp_obj_new_list(0, NULL); - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known characteristic UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - bleio_characteristic_properties_t props; - - props.broadcast = gattc_char->char_props.broadcast; - props.indicate = gattc_char->char_props.indicate; - props.notify = gattc_char->char_props.notify; - props.read = gattc_char->char_props.read; - props.write = gattc_char->char_props.write; - props.write_no_response = gattc_char->char_props.write_wo_resp; - - // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); - characteristic->handle = gattc_char->handle_value; - characteristic->service = m_char_discovery_service; - - mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} - -STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, bleio_central_obj_t *central) { - for (size_t i = 0; i < response->count; ++i) { - ble_gattc_desc_t *gattc_desc = &response->descs[i]; - - // Remember handles for certain well-known descriptors. - switch (gattc_desc->uuid.uuid) { - case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: - m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; - break; - - case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: - m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; - break; - - default: - // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, - // so ignore those. - // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors - break; - } - - bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); - descriptor->base.type = &bleio_descriptor_type; - - bleio_uuid_obj_t *uuid = NULL; - - if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { - // Known descriptor UUID. - uuid = m_new_obj(bleio_uuid_obj_t); - uuid->base.type = &bleio_uuid_type; - bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); - } else { - // The discovery response contained a 128-bit UUID that has not yet been registered with the - // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. - // For now, just leave the UUID as NULL. - } - - common_hal_bleio_descriptor_construct(descriptor, uuid); - descriptor->handle = gattc_desc->handle; - descriptor->characteristic = m_desc_discovery_characteristic; - - mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); - } - - if (response->count > 0) { - m_discovery_successful = true; - } - m_discovery_in_process = false; -} +#include "common-hal/bleio/__init__.h" STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; @@ -262,20 +54,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { case BLE_GAP_EVT_DISCONNECTED: central->conn_handle = BLE_CONN_HANDLE_INVALID; - m_discovery_successful = false; - m_discovery_in_process = false; - break; - - case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: - on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, central); - break; - - case BLE_GATTC_EVT_CHAR_DISC_RSP: - on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, central); - break; - - case BLE_GATTC_EVT_DESC_DISC_RSP: - on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, central); break; case BLE_GAP_EVT_SEC_PARAMS_REQUEST: @@ -288,7 +66,6 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { sd_ble_gap_conn_param_update(central->conn_handle, &request->conn_params); break; } - default: // For debugging. // mp_printf(&mp_plat_print, "Unhandled central event: 0x%04x\n", ble_evt->header.evt_id); @@ -299,12 +76,11 @@ STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { void common_hal_bleio_central_construct(bleio_central_obj_t *self) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = mp_obj_new_list(0, NULL); - self->gatt_role = GATT_ROLE_CLIENT; + self->remote_services_list = mp_obj_new_list(0, NULL); self->conn_handle = BLE_CONN_HANDLE_INVALID; } -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) { +void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { common_hal_bleio_adapter_set_enabled(true); ble_drv_add_event_handler(central_on_ble_evt, self); @@ -345,109 +121,6 @@ void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_o if (self->conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_OSError_msg(translate("Failed to connect: timeout")); } - - // Connection successful. - // Now discover services on the remote peripheral. - - if (service_uuids == mp_const_none) { - - // List of service UUID's not given, so discover all available services. - - uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; - - while (discover_next_services(self, next_service_start_handle, MP_OBJ_NULL)) { - // discover_next_services() appends to service_list. - - // Get the most recently discovered service, and then ask for services - // whose handles start after the last attribute handle inside that service. - const bleio_service_obj_t *service = - MP_OBJ_TO_PTR(self->service_list->items[self->service_list->len - 1]); - next_service_start_handle = service->end_handle + 1; - } - } else { - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(service_uuids, &iter_buf); - mp_obj_t uuid_obj; - while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { - mp_raise_ValueError(translate("non-UUID found in service_uuids")); - } - bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - - ble_uuid_t nrf_uuid; - bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); - - // Service might or might not be discovered; that's ok. Caller has to check - // Central.remote_services to find out. - // We only need to call this once for each service to discover. - discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid); - } - } - - - for (size_t service_idx = 0; service_idx < self->service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->service_list->items[service_idx]); - - // Skip the service if it had an unknown (unregistered) UUID. - if (service->uuid == NULL) { - continue; - } - - uint16_t next_char_start_handle = service->start_handle; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_characteristics() appends to the characteristic_list. - while (next_char_start_handle <= service->end_handle && - discover_next_characteristics(self, service, next_char_start_handle)) { - - - // Get the most recently discovered characteristic, and then ask for characteristics - // whose handles start after the last attribute handle inside that characteristic. - const bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); - next_char_start_handle = characteristic->handle + 1; - } - - // Got characteristics for this service. Now discover descriptors for each characteristic. - size_t char_list_len = service->characteristic_list->len; - for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { - bleio_characteristic_obj_t *characteristic = - MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); - const bool last_characteristic = char_idx == char_list_len - 1; - bleio_characteristic_obj_t *next_characteristic = last_characteristic - ? NULL - : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); - - // Skip the characteristic if it had an unknown (unregistered) UUID. - if (characteristic->uuid == NULL) { - continue; - } - - uint16_t next_desc_start_handle = characteristic->handle + 1; - - // Don't run past the end of this service or the beginning of the next characteristic. - uint16_t next_desc_end_handle = next_characteristic == NULL - ? service->end_handle - : next_characteristic->handle - 1; - - // Stop when we go past the end of the range of handles for this service or - // discovery call returns nothing. - // discover_next_descriptors() appends to the descriptor_list. - while (next_desc_start_handle <= service->end_handle && - next_desc_start_handle < next_desc_end_handle && - discover_next_descriptors(self, characteristic, - next_desc_start_handle, next_desc_end_handle)) { - - // Get the most recently discovered descriptor, and then ask for descriptors - // whose handles start after that descriptor's handle. - const bleio_descriptor_obj_t *descriptor = - MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); - next_desc_start_handle = descriptor->handle + 1; - } - } - - } } void common_hal_bleio_central_disconnect(bleio_central_obj_t *self) { @@ -459,5 +132,5 @@ bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { } mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { - return self->service_list; + return self->remote_services_list; } diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h index ac1670088..8b0d811bd 100644 --- a/ports/nrf/common-hal/bleio/Central.h +++ b/ports/nrf/common-hal/bleio/Central.h @@ -36,10 +36,10 @@ typedef struct { mp_obj_base_t base; - gatt_role_t gatt_role; volatile bool waiting_to_connect; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services discovered after connecting to a remote peripheral. + mp_obj_list_t *remote_services_list; } bleio_central_obj_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CENTRAL_H diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index 17417a5e6..e9f0225cf 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -33,8 +33,10 @@ #include "nrf_soc.h" #include "py/runtime.h" -#include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" + +#include "shared-bindings/bleio/__init__.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Service.h" STATIC volatile bleio_characteristic_obj_t *m_read_characteristic; @@ -225,53 +227,39 @@ mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_charact } mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self) { - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_CLIENT: + if (common_hal_bleio_service_get_is_remote(self->service)) { gattc_read(self); - break; - - case GATT_ROLE_SERVER: + } else { gatts_read(self); - break; - - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; } return self->value_data; } void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - bool sent = false; - uint16_t cccd = 0; + if (common_hal_bleio_service_get_is_remote(self->service)) { + gattc_write(self, bufinfo); + } else { + bool sent = false; + uint16_t cccd = 0; - switch (common_hal_bleio_device_get_gatt_role(self->service->device)) { - case GATT_ROLE_SERVER: - if (self->props.notify || self->props.indicate) { + if (self->props.notify || self->props.indicate) { cccd = get_cccd(self); - } - // It's possible that both notify and indicate are set. - if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); - sent = true; - } - if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { - gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); - sent = true; - } - if (!sent) { - gatts_write(self, bufinfo); - } - break; + } - case GATT_ROLE_CLIENT: - gattc_write(self, bufinfo); - break; + // It's possible that both notify and indicate are set. + if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); + sent = true; + } + if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); + sent = true; + } - default: - mp_raise_RuntimeError(translate("bad GATT role")); - break; + if (!sent) { + gatts_write(self, bufinfo); + } } } @@ -289,8 +277,8 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, mp_raise_ValueError(translate("No CCCD for this Characteristic")); } - if (common_hal_bleio_device_get_gatt_role(self->service->device) != GATT_ROLE_CLIENT) { - mp_raise_ValueError(translate("Can't set CCCD for local Characteristic")); + if (!common_hal_bleio_service_get_is_remote(self->service)) { + mp_raise_ValueError(translate("Can't set CCCD on local Characteristic")); } uint16_t cccd_value = diff --git a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c index 59eaaf02b..a6d834d7d 100644 --- a/ports/nrf/common-hal/bleio/CharacteristicBuffer.c +++ b/ports/nrf/common-hal/bleio/CharacteristicBuffer.c @@ -37,7 +37,7 @@ #include "tick.h" -#include "common-hal/bleio/__init__.h" +#include "shared-bindings/bleio/__init__.h" #include "common-hal/bleio/CharacteristicBuffer.h" STATIC void write_to_ringbuf(bleio_characteristic_buffer_obj_t *self, uint8_t *data, uint16_t len) { diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index 608bd1342..930000534 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -120,20 +120,21 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { } } -void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *service_list, mp_obj_t name) { +void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_list_t *services_list, mp_obj_t name) { common_hal_bleio_adapter_set_enabled(true); - self->service_list = service_list; + self->services_list = services_list; + // Used only for discovery when acting as a client. + self->remote_services_list = mp_obj_new_list(0, NULL); self->name = name; - self->gatt_role = GATT_ROLE_SERVER; self->conn_handle = BLE_CONN_HANDLE_INVALID; self->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; // Add all the services. - for (size_t service_idx = 0; service_idx < service_list->len; ++service_idx) { - bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_list->items[service_idx]); + for (size_t service_idx = 0; service_idx < services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(services_list->items[service_idx]); service->device = MP_OBJ_FROM_PTR(self); @@ -156,8 +157,8 @@ void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self, mp_obj_ } -mp_obj_list_t *common_hal_bleio_peripheral_get_service_list(bleio_peripheral_obj_t *self) { - return self->service_list; +mp_obj_list_t *common_hal_bleio_peripheral_get_services_list(bleio_peripheral_obj_t *self) { + return self->services_list; } bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self) { diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h index 2a1251715..3127a527f 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ b/ports/nrf/common-hal/bleio/Peripheral.h @@ -41,9 +41,11 @@ typedef struct { mp_obj_base_t base; mp_obj_t name; - gatt_role_t gatt_role; volatile uint16_t conn_handle; - mp_obj_list_t *service_list; + // Services provided by this peripheral. + mp_obj_list_t *services_list; + // Remote services discovered when this peripheral is acting as a client. + mp_obj_list_t *remote_services_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must // maintain them and not change it. If we need to change the contents during advertising, // there are tricks to get the SD to notice (see DevZone - TBS). diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index b6fcde827..02c2ac1f9 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -39,6 +39,7 @@ void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_ob self->handle = 0xFFFF; self->uuid = uuid; self->characteristic_list = characteristic_list; + self->is_remote = false; self->is_secondary = is_secondary; for (size_t characteristic_idx = 0; characteristic_idx < characteristic_list->len; ++characteristic_idx) { @@ -57,6 +58,10 @@ mp_obj_list_t *common_hal_bleio_service_get_characteristic_list(bleio_service_ob return self->characteristic_list; } +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { return self->is_secondary; } diff --git a/ports/nrf/common-hal/bleio/Service.h b/ports/nrf/common-hal/bleio/Service.h index 583593fb8..03ac2bca8 100644 --- a/ports/nrf/common-hal/bleio/Service.h +++ b/ports/nrf/common-hal/bleio/Service.h @@ -35,6 +35,8 @@ typedef struct { mp_obj_base_t base; // Handle for this service. uint16_t handle; + // True if created during discovery. + bool is_remote; bool is_secondary; bleio_uuid_obj_t *uuid; // May be a Peripheral, Central, etc. diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index 2dba5780c..a24898b0a 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -26,12 +26,24 @@ * THE SOFTWARE. */ +#include "py/runtime.h" #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Central.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" +#include "shared-bindings/bleio/Service.h" +#include "shared-bindings/bleio/UUID.h" + #include "common-hal/bleio/__init__.h" +static volatile bool m_discovery_in_process; +static volatile bool m_discovery_successful; + +static bleio_service_obj_t *m_char_discovery_service; +static bleio_characteristic_obj_t *m_desc_discovery_characteristic; + // Turn off BLE on a reset or reload. void bleio_reset() { if (common_hal_bleio_adapter_get_enabled()) { @@ -47,22 +59,359 @@ const super_adapter_obj_t common_hal_bleio_adapter_obj = { }, }; -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device) { +uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->gatt_role; + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; } else { - return GATT_ROLE_NONE; + return 0; } } -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { +mp_obj_list_t *common_hal_bleio_device_get_remote_services_list(mp_obj_t device) { if (MP_OBJ_IS_TYPE(device, &bleio_peripheral_type)) { - return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + return ((bleio_peripheral_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; } else if (MP_OBJ_IS_TYPE(device, &bleio_central_type)) { - return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->conn_handle; + return ((bleio_central_obj_t*) MP_OBJ_TO_PTR(device))->remote_services_list; } else { - return 0; + return NULL; + } +} + +// service_uuid may be NULL, to discover all services. +STATIC bool discover_next_services(mp_obj_t device, uint16_t start_handle, ble_uuid_t *service_uuid) { + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_primary_services_discover(conn_handle, start_handle, service_uuid); + + if (err_code != NRF_SUCCESS) { + mp_raise_OSError_msg(translate("Failed to discover services")); + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_characteristics(mp_obj_t device, bleio_service_obj_t *service, uint16_t start_handle) { + m_char_discovery_service = service; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = service->end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_characteristics_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC bool discover_next_descriptors(mp_obj_t device, bleio_characteristic_obj_t *characteristic, uint16_t start_handle, uint16_t end_handle) { + m_desc_discovery_characteristic = characteristic; + + ble_gattc_handle_range_t handle_range; + handle_range.start_handle = start_handle; + handle_range.end_handle = end_handle; + + m_discovery_successful = false; + m_discovery_in_process = true; + + uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(device); + uint32_t err_code = sd_ble_gattc_descriptors_discover(conn_handle, &handle_range); + if (err_code != NRF_SUCCESS) { + return false; + } + + // Wait for a discovery event. + while (m_discovery_in_process) { + MICROPY_VM_HOOK_LOOP; + } + return m_discovery_successful; +} + +STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_service_t *gattc_service = &response->services[i]; + + bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t); + service->base.type = &bleio_service_type; + + // Initialize several fields at once. + common_hal_bleio_service_construct(service, NULL, mp_obj_new_list(0, NULL), false); + + service->device = device; + service->is_remote = true; + service->start_handle = gattc_service->handle_range.start_handle; + service->end_handle = gattc_service->handle_range.end_handle; + service->handle = gattc_service->handle_range.start_handle; + + if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known service UUID. + bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid); + service->uuid = uuid; + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just set the UUID to NULL. + service->uuid = NULL; + } + + mp_obj_list_append(common_hal_bleio_device_get_remote_services_list(device), service); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_char_t *gattc_char = &response->chars[i]; + + bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t); + characteristic->base.type = &bleio_characteristic_type; + + characteristic->descriptor_list = mp_obj_new_list(0, NULL); + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known characteristic UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + bleio_characteristic_properties_t props; + + props.broadcast = gattc_char->char_props.broadcast; + props.indicate = gattc_char->char_props.indicate; + props.notify = gattc_char->char_props.notify; + props.read = gattc_char->char_props.read; + props.write = gattc_char->char_props.write; + props.write_no_response = gattc_char->char_props.write_wo_resp; + + // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. + common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); + characteristic->handle = gattc_char->handle_value; + characteristic->service = m_char_discovery_service; + + mp_obj_list_append(m_char_discovery_service->characteristic_list, MP_OBJ_FROM_PTR(characteristic)); + } + + if (response->count > 0) { + m_discovery_successful = true; } + m_discovery_in_process = false; +} + +STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_obj_t device) { + for (size_t i = 0; i < response->count; ++i) { + ble_gattc_desc_t *gattc_desc = &response->descs[i]; + + // Remember handles for certain well-known descriptors. + switch (gattc_desc->uuid.uuid) { + case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: + m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; + break; + + case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: + m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; + break; + + case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: + m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; + break; + + default: + // TODO: sd_ble_gattc_descriptors_discover() can return things that are not descriptors, + // so ignore those. + // https://devzone.nordicsemi.com/f/nordic-q-a/49500/sd_ble_gattc_descriptors_discover-is-returning-attributes-that-are-not-descriptors + break; + } + + bleio_descriptor_obj_t *descriptor = m_new_obj(bleio_descriptor_obj_t); + descriptor->base.type = &bleio_descriptor_type; + + bleio_uuid_obj_t *uuid = NULL; + + if (gattc_desc->uuid.type != BLE_UUID_TYPE_UNKNOWN) { + // Known descriptor UUID. + uuid = m_new_obj(bleio_uuid_obj_t); + uuid->base.type = &bleio_uuid_type; + bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_desc->uuid); + } else { + // The discovery response contained a 128-bit UUID that has not yet been registered with the + // softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it. + // For now, just leave the UUID as NULL. + } + + common_hal_bleio_descriptor_construct(descriptor, uuid); + descriptor->handle = gattc_desc->handle; + descriptor->characteristic = m_desc_discovery_characteristic; + + mp_obj_list_append(m_desc_discovery_characteristic->descriptor_list, MP_OBJ_FROM_PTR(descriptor)); + } + + if (response->count > 0) { + m_discovery_successful = true; + } + m_discovery_in_process = false; +} + +STATIC void discovery_on_ble_evt(ble_evt_t *ble_evt, mp_obj_t device) { + switch (ble_evt->header.evt_id) { + case BLE_GAP_EVT_DISCONNECTED: + m_discovery_successful = false; + m_discovery_in_process = false; + break; + + case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: + on_primary_srv_discovery_rsp(&ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp, device); + break; + + case BLE_GATTC_EVT_CHAR_DISC_RSP: + on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, device); + break; + + case BLE_GATTC_EVT_DESC_DISC_RSP: + on_desc_discovery_rsp(&ble_evt->evt.gattc_evt.params.desc_disc_rsp, device); + break; + + default: + // For debugging. + // mp_printf(&mp_plat_print, "Unhandled discovery event: 0x%04x\n", ble_evt->header.evt_id); + break; + } +} + + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_obj_list_t *remote_services_list = common_hal_bleio_device_get_remote_services_list(device); + + ble_drv_add_event_handler(discovery_on_ble_evt, device); + + if (service_uuids_whitelist == mp_const_none) { + // List of service UUID's not given, so discover all available services. + + uint16_t next_service_start_handle = BLE_GATT_HANDLE_START; + + while (discover_next_services(device, next_service_start_handle, MP_OBJ_NULL)) { + // discover_next_services() appends to remote_services_list. + + // Get the most recently discovered service, and then ask for services + // whose handles start after the last attribute handle inside that service. + const bleio_service_obj_t *service = + MP_OBJ_TO_PTR(remote_services_list->items[remote_services_list->len - 1]); + next_service_start_handle = service->end_handle + 1; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { + mp_raise_ValueError(translate("non-UUID found in service_uuids_whitelist")); + } + bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); + + ble_uuid_t nrf_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid); + + // Service might or might not be discovered; that's ok. Caller has to check + // Central.remote_services to find out. + // We only need to call this once for each service to discover. + discover_next_services(device, BLE_GATT_HANDLE_START, &nrf_uuid); + } + } + + + for (size_t service_idx = 0; service_idx < remote_services_list->len; ++service_idx) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(remote_services_list->items[service_idx]); + + // Skip the service if it had an unknown (unregistered) UUID. + if (service->uuid == NULL) { + continue; + } + + uint16_t next_char_start_handle = service->start_handle; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_characteristics() appends to the characteristic_list. + while (next_char_start_handle <= service->end_handle && + discover_next_characteristics(device, service, next_char_start_handle)) { + + + // Get the most recently discovered characteristic, and then ask for characteristics + // whose handles start after the last attribute handle inside that characteristic. + const bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[service->characteristic_list->len - 1]); + next_char_start_handle = characteristic->handle + 1; + } + + // Got characteristics for this service. Now discover descriptors for each characteristic. + size_t char_list_len = service->characteristic_list->len; + for (size_t char_idx = 0; char_idx < char_list_len; ++char_idx) { + bleio_characteristic_obj_t *characteristic = + MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx]); + const bool last_characteristic = char_idx == char_list_len - 1; + bleio_characteristic_obj_t *next_characteristic = last_characteristic + ? NULL + : MP_OBJ_TO_PTR(service->characteristic_list->items[char_idx + 1]); + + // Skip the characteristic if it had an unknown (unregistered) UUID. + if (characteristic->uuid == NULL) { + continue; + } + + uint16_t next_desc_start_handle = characteristic->handle + 1; + + // Don't run past the end of this service or the beginning of the next characteristic. + uint16_t next_desc_end_handle = next_characteristic == NULL + ? service->end_handle + : next_characteristic->handle - 1; + + // Stop when we go past the end of the range of handles for this service or + // discovery call returns nothing. + // discover_next_descriptors() appends to the descriptor_list. + while (next_desc_start_handle <= service->end_handle && + next_desc_start_handle < next_desc_end_handle && + discover_next_descriptors(device, characteristic, + next_desc_start_handle, next_desc_end_handle)) { + + // Get the most recently discovered descriptor, and then ask for descriptors + // whose handles start after that descriptor's handle. + const bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[characteristic->descriptor_list->len - 1]); + next_desc_start_handle = descriptor->handle + 1; + } + } + } + + // This event handler is no longer needed. + ble_drv_remove_event_handler(discovery_on_ble_evt, device); + } diff --git a/ports/nrf/common-hal/bleio/__init__.h b/ports/nrf/common-hal/bleio/__init__.h index 0c46b631f..c0bba3799 100644 --- a/ports/nrf/common-hal/bleio/__init__.h +++ b/ports/nrf/common-hal/bleio/__init__.h @@ -27,16 +27,10 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H -#include "shared-bindings/bleio/__init__.h" -#include "shared-bindings/bleio/Adapter.h" - -#include "shared-module/bleio/__init__.h" +void bleio_reset(void); // We assume variable length data. // 20 bytes max (23 - 3). #define GATT_MAX_DATA_LENGTH (BLE_GATT_ATT_MTU_DEFAULT - 3) -gatt_role_t common_hal_bleio_device_get_gatt_role(mp_obj_t device); -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); - #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_INIT_H diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index a2b48065d..8fa6721e2 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -78,6 +78,7 @@ // TIMERS #define NRFX_TIMER_ENABLED 1 // Don't enable TIMER0: it's used by the SoftDevice. +#define NRFX_TIMER0_ENABLED 0 #define NRFX_TIMER1_ENABLED 1 #define NRFX_TIMER2_ENABLED 1 diff --git a/ports/nrf/peripherals/nrf/timers.c b/ports/nrf/peripherals/nrf/timers.c index 7f7a003d3..88f3dd468 100644 --- a/ports/nrf/peripherals/nrf/timers.c +++ b/ports/nrf/peripherals/nrf/timers.c @@ -36,7 +36,7 @@ STATIC nrfx_timer_t nrfx_timers[] = { #if NRFX_CHECK(NRFX_TIMER0_ENABLED) - // Note that TIMER0 is reserved for use by the SoftDevice, so it should not usually be enabled. + #error NRFX_TIMER0_ENABLED should not be on: TIMER0 is used by the SoftDevice NRFX_TIMER_INSTANCE(0), #endif #if NRFX_CHECK(NRFX_TIMER1_ENABLED) diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c index fc00bce5c..70b270c65 100644 --- a/shared-bindings/bleio/Central.c +++ b/shared-bindings/bleio/Central.c @@ -34,6 +34,7 @@ #include "py/objproperty.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/Characteristic.h" @@ -56,12 +57,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 +//| central.discover_remote_services() //| //| .. class:: Central() @@ -79,24 +84,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 +97,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 +110,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 +130,47 @@ 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. +//| The attribute `remote_services` will contain a list of all discovered services. +//| `Central.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. +//| If a service in service_uuids_whitelist 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. Creating the UUID causes the UUID to be registered +//| for use. (This restriction may be lifted in the future.) +//| +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")); + } + + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj); + + return mp_const_none; +} +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. @@ -181,8 +213,9 @@ const mp_obj_property_t bleio_central_remote_services_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) }, diff --git a/shared-bindings/bleio/Central.h b/shared-bindings/bleio/Central.h index 0e84037f9..1d7fb6248 100644 --- a/shared-bindings/bleio/Central.h +++ b/shared-bindings/bleio/Central.h @@ -34,7 +34,7 @@ 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); diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index 1302c9652..69bc72d92 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -35,6 +35,7 @@ #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" @@ -107,15 +108,15 @@ 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; @@ -128,7 +129,7 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar 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_str); return MP_OBJ_FROM_PTR(self); } @@ -158,8 +159,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_list(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 +266,63 @@ 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. +//| The attribute `remote_services` will contain a list of all 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. +//| If a service in service_uuids_whitelist 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. 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. +//| +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")); + } + + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), + args[ARG_service_uuids_whitelist].u_obj); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_discover_remote_services_obj, 1, bleio_peripheral_discover_remote_services); + 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) }, // 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..7dad0bccd 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -33,7 +33,7 @@ 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_list(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); diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index db0606991..b4aeab2bd 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 }; @@ -119,6 +123,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__.h b/shared-bindings/bleio/__init__.h index 4aa6dd45b..dd6e55204 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -29,8 +29,19 @@ #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 "shared-module/bleio/__init__.h" #include "common-hal/bleio/Adapter.h" extern const super_adapter_obj_t common_hal_bleio_adapter_obj; +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); + + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO___INIT___H diff --git a/shared-module/bleio/__init__.h b/shared-module/bleio/__init__.h index 07d148594..f8f0e0660 100644 --- a/shared-module/bleio/__init__.h +++ b/shared-module/bleio/__init__.h @@ -27,12 +27,6 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -typedef enum { - GATT_ROLE_NONE, - GATT_ROLE_SERVER, - GATT_ROLE_CLIENT, -} gatt_role_t; - extern void bleio_reset(void); #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -- cgit v1.2.3 From c1e5247d51ffb34bdfdb1f5039ba9118fab25f26 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Fri, 2 Aug 2019 12:36:34 +0200 Subject: Add support for scaling to _stage On high-resolution displays we can use 2x2 or even 3x3 pixels. --- shared-bindings/_stage/__init__.c | 12 +++++++++--- shared-module/_stage/__init__.c | 37 +++++++++++++++++++++---------------- shared-module/_stage/__init__.h | 2 +- 3 files changed, 31 insertions(+), 20 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 1ca206339..485fa80c5 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,6 +90,10 @@ 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 @@ -103,12 +108,13 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { displayio_display_set_region_to_update(display, &area); display->send(display->bus, true, &display->write_ram_command, 1); - render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display); + 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-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 1af279e92..ca71b758e 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -34,30 +34,35 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display) { + displayio_display_obj_t *display, uint8_t scale) { size_t index = 0; for (uint16_t y = y0; y < y1; ++y) { - for (uint16_t x = x0; x < x1; ++x) { - for (size_t layer = 0; layer < layers_size; ++layer) { + for (uint8_t yscale = 0; yscale < scale; ++yscale) { + for (uint16_t x = x0; x < x1; ++x) { uint16_t c = TRANSPARENT; - layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); - if (obj->base.type == &mp_type_layer) { - c = get_layer_pixel(obj, x, y); - } else if (obj->base.type == &mp_type_text) { - c = get_text_pixel((text_obj_t *)obj, x, y); + for (size_t layer = 0; layer < layers_size; ++layer) { + layer_obj_t *obj = MP_OBJ_TO_PTR(layers[layer]); + if (obj->base.type == &mp_type_layer) { + c = get_layer_pixel(obj, x, y); + } else if (obj->base.type == &mp_type_text) { + c = get_text_pixel((text_obj_t *)obj, x, y); + } + if (c != TRANSPARENT) { + break; + } } - if (c != TRANSPARENT) { + for (uint8_t xscale = 0; xscale < scale; ++xscale) { buffer[index] = c; - break; + index += 1; + // The buffer is full, send it. + if (index >= buffer_size) { + display->send(display->bus, false, ((uint8_t*)buffer), + buffer_size * 2); + index = 0; + } } } - index += 1; - // The buffer is full, send it. - if (index >= buffer_size) { - display->send(display->bus, false, ((uint8_t*)buffer), buffer_size * 2); - index = 0; - } } } // Send the remaining data. diff --git a/shared-module/_stage/__init__.h b/shared-module/_stage/__init__.h index d263302b4..5af2124ae 100644 --- a/shared-module/_stage/__init__.h +++ b/shared-module/_stage/__init__.h @@ -37,6 +37,6 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mp_obj_t *layers, size_t layers_size, uint16_t *buffer, size_t buffer_size, - displayio_display_obj_t *display); + displayio_display_obj_t *display, uint8_t scale); #endif // MICROPY_INCLUDED_SHARED_MODULE__STAGE -- cgit v1.2.3 From 7ce3776b8086abbe0d01056651904a59bf4f8bec Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 2 Aug 2019 17:56:44 -0400 Subject: WIP: rework of Characteristic properties; enhance Descriptor; not tested --- ports/nrf/common-hal/bleio/Attribute.c | 60 ++++++++ ports/nrf/common-hal/bleio/Attribute.h | 32 +++++ ports/nrf/common-hal/bleio/Central.h | 1 - ports/nrf/common-hal/bleio/Characteristic.c | 21 +-- ports/nrf/common-hal/bleio/Characteristic.h | 6 +- ports/nrf/common-hal/bleio/Descriptor.c | 6 +- ports/nrf/common-hal/bleio/Descriptor.h | 7 +- ports/nrf/common-hal/bleio/Peripheral.c | 4 +- ports/nrf/common-hal/bleio/Peripheral.h | 1 - ports/nrf/common-hal/bleio/Service.c | 74 +++++++--- ports/nrf/common-hal/bleio/__init__.c | 29 ++-- py/circuitpy_defns.mk | 11 +- py/obj.h | 1 + py/objlist.c | 5 + shared-bindings/bleio/Address.c | 12 +- shared-bindings/bleio/Attribute.c | 93 +++++++++++++ shared-bindings/bleio/Attribute.h | 38 +++++ shared-bindings/bleio/Characteristic.c | 207 ++++++++++------------------ shared-bindings/bleio/Characteristic.h | 3 +- shared-bindings/bleio/Descriptor.c | 90 ++---------- shared-bindings/bleio/Descriptor.h | 21 +-- shared-bindings/bleio/__init__.c | 38 +++-- shared-bindings/bleio/__init__.h | 1 - shared-module/bleio/Attribute.c | 46 +++++++ shared-module/bleio/Attribute.h | 41 ++++++ shared-module/bleio/Characteristic.h | 21 +-- shared-module/bleio/__init__.h | 32 ----- 27 files changed, 546 insertions(+), 355 deletions(-) create mode 100644 ports/nrf/common-hal/bleio/Attribute.c create mode 100644 ports/nrf/common-hal/bleio/Attribute.h create mode 100644 shared-bindings/bleio/Attribute.c create mode 100644 shared-bindings/bleio/Attribute.h create mode 100644 shared-module/bleio/Attribute.c create mode 100644 shared-module/bleio/Attribute.h delete mode 100644 shared-module/bleio/__init__.h (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c new file mode 100644 index 000000000..bffe68254 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.c @@ -0,0 +1,60 @@ +/* + * 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 "shared-bindings/bleio/Attribute.h" + +// Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. +void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SEC_MODE_NO_ACCESS: + BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); + break; + + case SEC_MODE_OPEN: + BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); + break; + + case SEC_MODE_ENC_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); + break; + + case SEC_MODE_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); + break; + + case SEC_MODE_LESC_ENC_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); + break; + + case SEC_MODE_SIGNED_NO_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); + break; + + case SEC_MODE_SIGNED_WITH_MITM: + BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); + break; + } +} diff --git a/ports/nrf/common-hal/bleio/Attribute.h b/ports/nrf/common-hal/bleio/Attribute.h new file mode 100644 index 000000000..44c2fdfa1 --- /dev/null +++ b/ports/nrf/common-hal/bleio/Attribute.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H + +// Nothing yet. + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_ATTRIBUTE_H diff --git a/ports/nrf/common-hal/bleio/Central.h b/ports/nrf/common-hal/bleio/Central.h index 8b0d811bd..b7a9050b8 100644 --- a/ports/nrf/common-hal/bleio/Central.h +++ b/ports/nrf/common-hal/bleio/Central.h @@ -31,7 +31,6 @@ #include #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" typedef struct { diff --git a/ports/nrf/common-hal/bleio/Characteristic.c b/ports/nrf/common-hal/bleio/Characteristic.c index b318ae81c..41fcdd1f1 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.c +++ b/ports/nrf/common-hal/bleio/Characteristic.c @@ -164,7 +164,8 @@ STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_in check_connected(conn_handle); ble_gattc_write_params_t write_params = { - .write_op = characteristic->props.write_no_response ? BLE_GATT_OP_WRITE_CMD : BLE_GATT_OP_WRITE_REQ, + .write_op = (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) + ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, .handle = characteristic->handle, .p_value = bufinfo->buf, .len = bufinfo->len, @@ -211,12 +212,14 @@ STATIC void characteristic_on_ble_evt(ble_evt_t *ble_evt, void *param) { } -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) { +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t security_mode, mp_obj_t descriptors) { self->service = mp_const_none; self->uuid = uuid; self->value_data = mp_const_none; self->props = props; - self->descriptor_list = descriptor_list; + self->security_mode = security_mode; + self->descriptor_list = mp_obj_new_list_from_iter(descriptors); + self->handle = BLE_GATT_HANDLE_INVALID; ble_drv_add_event_handler(characteristic_on_ble_evt, self); @@ -238,21 +241,23 @@ mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *s void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { if (common_hal_bleio_service_get_is_remote(self->service)) { - gattc_write(self, bufinfo); + gattc_write(self, bufinfo); } else { bool sent = false; uint16_t cccd = 0; - if (self->props.notify || self->props.indicate) { - cccd = get_cccd(self); + const bool notify = self->props & CHAR_PROP_NOTIFY; + const bool indicate = self->props & CHAR_PROP_INDICATE; + if (notify | indicate) { + cccd = get_cccd(self); } // It's possible that both notify and indicate are set. - if (self->props.notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { + if (notify && (cccd & BLE_GATT_HVX_NOTIFICATION)) { gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_NOTIFICATION); sent = true; } - if (self->props.indicate && (cccd & BLE_GATT_HVX_INDICATION)) { + if (indicate && (cccd & BLE_GATT_HVX_INDICATION)) { gatts_notify_indicate(self, bufinfo, BLE_GATT_HVX_INDICATION); sent = true; } diff --git a/ports/nrf/common-hal/bleio/Characteristic.h b/ports/nrf/common-hal/bleio/Characteristic.h index 7cb227596..8c8309f09 100644 --- a/ports/nrf/common-hal/bleio/Characteristic.h +++ b/ports/nrf/common-hal/bleio/Characteristic.h @@ -28,17 +28,19 @@ #ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_CHARACTERISTIC_H +#include "shared-bindings/bleio/Attribute.h" +#include "shared-module/bleio/Characteristic.h" #include "common-hal/bleio/Service.h" #include "common-hal/bleio/UUID.h" -#include "shared-module/bleio/Characteristic.h" typedef struct { mp_obj_base_t base; bleio_service_obj_t *service; bleio_uuid_obj_t *uuid; - volatile mp_obj_t value_data; + mp_obj_t value_data; uint16_t handle; bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t security_mode; mp_obj_list_t *descriptor_list; uint16_t user_desc_handle; uint16_t cccd_handle; diff --git a/ports/nrf/common-hal/bleio/Descriptor.c b/ports/nrf/common-hal/bleio/Descriptor.c index 005af6eaa..ad62b2535 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.c +++ b/ports/nrf/common-hal/bleio/Descriptor.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * Copyright (c) 2016 Glenn Ruben Bakke * @@ -33,10 +33,6 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_u self->uuid = uuid; } -mp_int_t common_hal_bleio_descriptor_get_handle(bleio_descriptor_obj_t *self) { - return self->handle; -} - bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { return self->uuid; } diff --git a/ports/nrf/common-hal/bleio/Descriptor.h b/ports/nrf/common-hal/bleio/Descriptor.h index b7af6a42f..ad94a0bb9 100644 --- a/ports/nrf/common-hal/bleio/Descriptor.h +++ b/ports/nrf/common-hal/bleio/Descriptor.h @@ -30,14 +30,17 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H #include "py/obj.h" -#include "common-hal/bleio/Characteristic.h" + +#include "shared-bindings/bleio/Characteristic.h" #include "common-hal/bleio/UUID.h" typedef struct { mp_obj_base_t base; - uint16_t handle; bleio_characteristic_obj_t *characteristic; bleio_uuid_obj_t *uuid; + mp_obj_t value_data; + uint16_t handle; + bleio_attribute_security_mode_t security_mode; } bleio_descriptor_obj_t; #endif // MICROPY_INCLUDED_NRF_COMMON_HAL_BLEIO_DESCRIPTOR_H diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index c45041ad0..905b26835 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -138,10 +138,10 @@ STATIC void peripheral_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { // Pairing process completed ble_gap_evt_auth_status_t* status = &ble_evt->evt.gap_evt.params.auth_status; if (BLE_GAP_SEC_STATUS_SUCCESS == status->auth_status) { - mp_printf(&mp_plat_print, "Pairing succeeded, status: 0x%04x\n", status->auth_status); + // mp_printf(&mp_plat_print, "Pairing succeeded, status: 0x%04x\n", status->auth_status); self->pair_status = PAIR_PAIRED; } else { - mp_printf(&mp_plat_print, "Pairing failed, status: 0x%04x\n", status->auth_status); + // mp_printf(&mp_plat_print, "Pairing failed, status: 0x%04x\n", status->auth_status); self->pair_status = PAIR_NOT_PAIRED; } break; diff --git a/ports/nrf/common-hal/bleio/Peripheral.h b/ports/nrf/common-hal/bleio/Peripheral.h index e4a664b01..e75a1641a 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.h +++ b/ports/nrf/common-hal/bleio/Peripheral.h @@ -35,7 +35,6 @@ #include "py/obj.h" #include "py/objlist.h" -#include "shared-module/bleio/__init__.h" #include "shared-module/bleio/Address.h" typedef enum { diff --git a/ports/nrf/common-hal/bleio/Service.c b/ports/nrf/common-hal/bleio/Service.c index 02c2ac1f9..cdcbad7c4 100644 --- a/ports/nrf/common-hal/bleio/Service.c +++ b/ports/nrf/common-hal/bleio/Service.c @@ -29,8 +29,8 @@ #include "ble.h" #include "py/runtime.h" #include "common-hal/bleio/__init__.h" -#include "common-hal/bleio/Characteristic.h" #include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/Adapter.h" @@ -74,12 +74,12 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) MP_OBJ_TO_PTR(self->characteristic_list->items[characteristic_idx]); ble_gatts_char_md_t char_md = { - .char_props.broadcast = characteristic->props.broadcast, - .char_props.read = characteristic->props.read, - .char_props.write_wo_resp = characteristic->props.write_no_response, - .char_props.write = characteristic->props.write, - .char_props.notify = characteristic->props.notify, - .char_props.indicate = characteristic->props.indicate, + .char_props.broadcast = (bool) characteristic->props & CHAR_PROP_BROADCAST, + .char_props.read = (bool) characteristic->props & CHAR_PROP_READ, + .char_props.write_wo_resp = (bool) characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE, + .char_props.write = (bool) characteristic->props & CHAR_PROP_WRITE, + .char_props.notify = (bool) characteristic->props & CHAR_PROP_NOTIFY, + .char_props.indicate = (bool) characteristic->props & CHAR_PROP_INDICATE, }; ble_gatts_attr_md_t cccd_md = { @@ -93,28 +93,28 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) char_md.p_cccd_md = &cccd_md; } - ble_uuid_t uuid; - bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &uuid); + ble_uuid_t char_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(characteristic->uuid, &char_uuid); - ble_gatts_attr_md_t attr_md = { + ble_gatts_attr_md_t char_attr_md = { .vloc = BLE_GATTS_VLOC_STACK, .vlen = 1, }; - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm); - BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&char_attr_md.write_perm); - ble_gatts_attr_t attr_char_value = { - .p_uuid = &uuid, - .p_attr_md = &attr_md, + ble_gatts_attr_t char_attr = { + .p_uuid = &char_uuid, + .p_attr_md = &char_attr_md, .init_len = sizeof(uint8_t), .max_len = GATT_MAX_DATA_LENGTH, }; - ble_gatts_char_handles_t handles; + ble_gatts_char_handles_t char_handles; uint32_t err_code; - err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &attr_char_value, &handles); + err_code = sd_ble_gatts_characteristic_add(self->handle, &char_md, &char_attr, &char_handles); if (err_code != NRF_SUCCESS) { mp_raise_OSError_msg_varg(translate("Failed to add characteristic, err 0x%04x"), err_code); } @@ -123,9 +123,41 @@ void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self) mp_raise_ValueError(translate("Characteristic already in use by another Service.")); } - characteristic->user_desc_handle = handles.user_desc_handle; - characteristic->cccd_handle = handles.cccd_handle; - characteristic->sccd_handle = handles.sccd_handle; - characteristic->handle = handles.value_handle; + characteristic->user_desc_handle = char_handles.user_desc_handle; + characteristic->cccd_handle = char_handles.cccd_handle; + characteristic->sccd_handle = char_handles.sccd_handle; + characteristic->handle = char_handles.value_handle; + + // Add the descriptors for this characteristic. + for (size_t descriptor_idx = 0; descriptor_idx < characteristic->descriptor_list->len; ++descriptor_idx) { + bleio_descriptor_obj_t *descriptor = + MP_OBJ_TO_PTR(characteristic->descriptor_list->items[descriptor_idx]); + + ble_uuid_t desc_uuid; + bleio_uuid_convert_to_nrf_ble_uuid(descriptor->uuid, &desc_uuid); + + ble_gatts_attr_md_t desc_attr_md = { + // Data passed is not in a permanent location and should be copied. + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = 1, + }; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.read_perm); + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_attr_md.write_perm); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(descriptor->value_data, &bufinfo, MP_BUFFER_READ); + + ble_gatts_attr_t desc_attr = { + .p_uuid = &desc_uuid, + .p_attr_md = &desc_attr_md, + .init_len = bufinfo.len, + .p_value = bufinfo.buf, + .init_offs = 0, + .max_len = GATT_MAX_DATA_LENGTH, + }; + + err_code = sd_ble_gatts_descriptor_add(characteristic->handle, &desc_attr, &descriptor->handle); + } } } diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index a24898b0a..303e70797 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -204,17 +204,16 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - bleio_characteristic_properties_t props; - - props.broadcast = gattc_char->char_props.broadcast; - props.indicate = gattc_char->char_props.indicate; - props.notify = gattc_char->char_props.notify; - props.read = gattc_char->char_props.read; - props.write = gattc_char->char_props.write; - props.write_no_response = gattc_char->char_props.write_wo_resp; + bleio_characteristic_properties_t props = + (gattc_char->char_props.broadcast ? CHAR_PROP_BROADCAST : 0) | + (gattc_char->char_props.indicate ? CHAR_PROP_INDICATE : 0) | + (gattc_char->char_props.notify ? CHAR_PROP_NOTIFY : 0) | + (gattc_char->char_props.read ? CHAR_PROP_READ : 0) | + (gattc_char->char_props.write ? CHAR_PROP_WRITE : 0) | + (gattc_char->char_props.write_wo_resp ? CHAR_PROP_WRITE_NO_RESPONSE : 0); // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. - common_hal_bleio_characteristic_construct(characteristic, uuid, props, mp_obj_new_list(0, NULL)); + common_hal_bleio_characteristic_construct(characteristic, uuid, props, SEC_MODE_OPEN, mp_const_empty_tuple); characteristic->handle = gattc_char->handle_value; characteristic->service = m_char_discovery_service; @@ -233,15 +232,15 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // Remember handles for certain well-known descriptors. switch (gattc_desc->uuid.uuid) { - case DESCRIPTOR_UUID_CLIENT_CHARACTERISTIC_CONFIGURATION: + case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG: m_desc_discovery_characteristic->cccd_handle = gattc_desc->handle; break; - case DESCRIPTOR_UUID_SERVER_CHARACTERISTIC_CONFIGURATION: + case BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG: m_desc_discovery_characteristic->sccd_handle = gattc_desc->handle; break; - case DESCRIPTOR_UUID_CHARACTERISTIC_USER_DESCRIPTION: + case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC: m_desc_discovery_characteristic->user_desc_handle = gattc_desc->handle; break; @@ -268,7 +267,8 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - common_hal_bleio_descriptor_construct(descriptor, uuid); + // TODO: can we find out security mode? + common_hal_bleio_descriptor_construct(descriptor, uuid, SEC_MODE_OPEN); descriptor->handle = gattc_desc->handle; descriptor->characteristic = m_desc_discovery_characteristic; @@ -313,6 +313,9 @@ void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t ble_drv_add_event_handler(discovery_on_ble_evt, device); + // Start over with an empty list. + mp_obj_list_clear(MP_OBJ_FROM_PTR(common_hal_bleio_device_get_remote_services_list(device))); + if (service_uuids_whitelist == mp_const_none) { // List of service UUID's not given, so discover all available services. diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bdefc18cc..5e5ebeaa8 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -227,6 +227,7 @@ $(filter $(SRC_PATTERNS), \ audioio/AudioOut.c \ bleio/__init__.c \ bleio/Adapter.c \ + bleio/Attribute.c \ bleio/Central.c \ bleio/Characteristic.c \ bleio/CharacteristicBuffer.c \ @@ -276,6 +277,9 @@ $(filter $(SRC_PATTERNS), \ # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + bleio/Address.c \ + bleio/Attribute.c \ + bleio/ScanEntry.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -289,12 +293,6 @@ SRC_BINDINGS_ENUMS += \ help.c \ util.c -SRC_BINDINGS_ENUMS += \ -$(filter $(SRC_PATTERNS), \ - bleio/Address.c \ - bleio/ScanEntry.c \ -) - # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_SHARED_MODULE = \ $(filter $(SRC_PATTERNS), \ @@ -314,6 +312,7 @@ $(filter $(SRC_PATTERNS), \ bitbangio/__init__.c \ board/__init__.c \ bleio/Address.c \ + bleio/Attribute.c \ bleio/ScanEntry.c \ busio/OneWire.c \ displayio/Bitmap.c \ diff --git a/py/obj.h b/py/obj.h index 6eead377d..c719c2945 100644 --- a/py/obj.h +++ b/py/obj.h @@ -668,6 +668,7 @@ mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); mp_obj_t mp_obj_new_closure(mp_obj_t fun, size_t n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(size_t n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items); +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable); mp_obj_t mp_obj_new_dict(size_t n_args); mp_obj_t mp_obj_new_set(size_t n_args, mp_obj_t *items); mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step); diff --git a/py/objlist.c b/py/objlist.c index 558c4c611..ea38e64e5 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -68,6 +68,11 @@ STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) { return list; } +mp_obj_t mp_obj_new_list_from_iter(mp_obj_t iterable) { + mp_obj_t list = mp_obj_new_list(0, NULL); + return list_extend_from_iter(list, iterable); +} + STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { (void)type_in; mp_arg_check_num(n_args, kw_args, 0, 1, false); diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c index 475fc9427..d77cfa404 100644 --- a/shared-bindings/bleio/Address.c +++ b/shared-bindings/bleio/Address.c @@ -174,13 +174,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..f640cc05c --- /dev/null +++ b/shared-bindings/bleio/Attribute.c @@ -0,0 +1,93 @@ +/* + * 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. +//| `Attribute` is, notionally, a superclass of `Characteristic` and `Descriptor`, +//| but is not defined as a Python superclass of those classes. +//| +//| .. class:: Attribute() +//| +//| You cannot create an instance of `Attribute`. +//| + +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(SEC_MODE_NO_ACCESS) }, + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SEC_MODE_OPEN) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SEC_MODE_ENC_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_LESC_ENC_WITH_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SEC_MODE_SIGNED_NO_MITM) }, + { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SEC_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/Characteristic.c b/shared-bindings/bleio/Characteristic.c index 3bf0476ab..09ed48ef9 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -28,6 +28,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/UUID.h" @@ -40,30 +41,25 @@ //| 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, security_mode=`Attribute.OPEN`, 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 security_mode: one of the integer values `Attribute.NO_ACCESS`, `Attribute.OPEN`, +//| `Attribute.ENCRYPT_NO_MITM`, `Attribute.ENCRYPT_WITH_MITM`, `Attribute.LESC_ENCRYPT_WITH_MITM`, +//| `Attribute.SIGNED_NO_MITM`, `Attribute.SIGNED_WITH_MITM`. +//| :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_security_mode, 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_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_descriptors, MP_ARG_KW_ONLY| MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -76,129 +72,41 @@ 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); - - 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 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_characteristic_properties_t properties = args[ARG_properties].u_int; + if (properties & ~CHAR_PROP_ALL) { + mp_raise_ValueError(translate("Invalid properties")); + } -//| .. 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); + const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; + common_hal_bleio_attribute_security_mode_check_valid(security_mode); - 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); + mp_obj_t descriptors = args[ARG_descriptors].u_obj; + if (descriptors == mp_const_none) { + descriptors = mp_const_empty_tuple; + } -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 }, -}; + bleio_characteristic_obj_t *self = m_new_obj(bleio_characteristic_obj_t); + self->base.type = &bleio_characteristic_type; -//| .. 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); + common_hal_bleio_characteristic_construct(self, uuid, properties, security_mode, descriptors); - 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 }, }; @@ -301,16 +209,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 +265,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..379f9b4bf 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -28,12 +28,13 @@ #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 security_mode, mp_obj_t descriptors); 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); diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index f2e5aa01d..b709f3aa7 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,15 @@ //| information about the characteristic. //| -//| .. class:: Descriptor(uuid) +//| .. class:: Descriptor(uuid, security_mode=`Attribute.OPEN`) //| -//| Create a new descriptor object with the UUID uuid. +//| Create a new descriptor object with the UUID uuid and the given value, if any. -//| .. attribute:: handle -//| -//| The descriptor handle. (read-only) -//| - -//| .. attribute:: uuid -//| -//| The descriptor uuid. (read-only) -//| 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_security_mode }; 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_security_mode, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -69,28 +62,22 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar mp_raise_ValueError(translate("Expected a UUID")); } + const bleio_attribute_security_mode_t security_mode = args[ARG_security_mode].u_int; + common_hal_bleio_attribute_security_mode_check_valid(security_mode); + 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); -} + common_hal_bleio_descriptor_construct(self, uuid, security_mode); -STATIC mp_obj_t bleio_descriptor_get_handle(mp_obj_t self_in) { - bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - - 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); @@ -108,54 +95,7 @@ const mp_obj_property_t bleio_descriptor_uuid_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) }, - - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_AGGREGATE_FORMAT), - MP_ROM_INT(DESCRIPTOR_UUID_CHARACTERISTIC_AGGREGATE_FORMAT) }, - - { MP_ROM_QSTR(MP_QSTR_VALID_RANGE), - MP_ROM_INT(DESCRIPTOR_UUID_VALID_RANGE) }, - - { MP_ROM_QSTR(MP_QSTR_EXTERNAL_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_EXTERNAL_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_REPORT_REFERENCE), - MP_ROM_INT(DESCRIPTOR_UUID_REPORT_REFERENCE) }, - - { MP_ROM_QSTR(MP_QSTR_NUMBER_OF_DIGITALS), - MP_ROM_INT(DESCRIPTOR_UUID_NUMBER_OF_DIGITALS) }, - - { MP_ROM_QSTR(MP_QSTR_VALUE_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_VALUE_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_CONFIGURATION), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_CONFIGURATION) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_MEASUREMENT ), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_MEASUREMENT) }, - - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_ENVIRONMENTAL_SENSING_TRIGGER_SETTING) }, - - { MP_ROM_QSTR(MP_QSTR_TIME_TRIGGER_SETTING), - MP_ROM_INT(DESCRIPTOR_UUID_TIME_TRIGGER_SETTING) }, }; 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..a7daee574 100644 --- a/shared-bindings/bleio/Descriptor.h +++ b/shared-bindings/bleio/Descriptor.h @@ -28,31 +28,14 @@ #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 security_mode); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DESCRIPTOR_H diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index ba3bae6c7..7a6f96436 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -31,21 +31,26 @@ #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 `_ +//| CircuitPython library, which builds on `bleio`, and +//| provides higher-level convenience functionality, including predefined beacons, clients, +//| servers. //| //| Libraries //| @@ -72,20 +77,23 @@ //| 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_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) }, + + // constants + { MP_ROM_QSTR(MP_QSTR_SEC), MP_ROM_PTR(&bleio_uuid_type) }, }; 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 dd6e55204..626b188a9 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -34,7 +34,6 @@ #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" -#include "shared-module/bleio/__init__.h" #include "common-hal/bleio/Adapter.h" extern const super_adapter_obj_t common_hal_bleio_adapter_obj; diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c new file mode 100644 index 000000000..ac854ec6b --- /dev/null +++ b/shared-module/bleio/Attribute.c @@ -0,0 +1,46 @@ +/* + * 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 + +#include "py/runtime.h" +#include "shared-bindings/bleio/Attribute.h" + +void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { + switch (security_mode) { + case SEC_MODE_NO_ACCESS: + case SEC_MODE_OPEN: + case SEC_MODE_ENC_NO_MITM: + case SEC_MODE_ENC_WITH_MITM: + case SEC_MODE_LESC_ENC_WITH_MITM: + case SEC_MODE_SIGNED_NO_MITM: + case SEC_MODE_SIGNED_WITH_MITM: + break; + default: + mp_raise_ValueError(translate("Invalid security_mode")); + break; + } +} diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h new file mode 100644 index 000000000..62615f1b5 --- /dev/null +++ b/shared-module/bleio/Attribute.h @@ -0,0 +1,41 @@ +/* + * 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_MODULE_BLEIO_ATTRIBUTE_H +#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H + +// BLE security modes: 0x +typedef enum { + SEC_MODE_NO_ACCESS = 0x00, + SEC_MODE_OPEN = 0x11, + SEC_MODE_ENC_NO_MITM = 0x21, + SEC_MODE_ENC_WITH_MITM = 0x31, + SEC_MODE_LESC_ENC_WITH_MITM = 0x41, + SEC_MODE_SIGNED_NO_MITM = 0x12, + SEC_MODE_SIGNED_WITH_MITM = 0x22, +} bleio_attribute_security_mode_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H diff --git a/shared-module/bleio/Characteristic.h b/shared-module/bleio/Characteristic.h index 27b43588f..409a57c76 100644 --- a/shared-module/bleio/Characteristic.h +++ b/shared-module/bleio/Characteristic.h @@ -27,14 +27,17 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -// Flags for each characteristic property. Common across ports. -typedef struct { - bool broadcast : 1; - bool read : 1; - bool write_no_response : 1; - bool write : 1; - bool notify : 1; - bool indicate : 1; -} bleio_characteristic_properties_t; +typedef enum { + CHAR_PROP_NONE = 0, + CHAR_PROP_BROADCAST = 1u << 0, + CHAR_PROP_INDICATE = 1u << 1, + CHAR_PROP_NOTIFY = 1u << 2, + CHAR_PROP_READ = 1u << 3, + CHAR_PROP_WRITE = 1u << 4, + CHAR_PROP_WRITE_NO_RESPONSE = 1u << 5, + CHAR_PROP_ALL = (CHAR_PROP_BROADCAST | CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY | + CHAR_PROP_READ | CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE) +} bleio_characteristic_properties_enum_t; +typedef uint8_t bleio_characteristic_properties_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H diff --git a/shared-module/bleio/__init__.h b/shared-module/bleio/__init__.h deleted file mode 100644 index f8f0e0660..000000000 --- a/shared-module/bleio/__init__.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 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_MODULE_BLEIO_INIT_H -#define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H - -extern void bleio_reset(void); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_INIT_H -- cgit v1.2.3 From 9907e3fa288eb9c31d0152e56c4d9ba998cf8122 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 3 Aug 2019 13:48:55 +0200 Subject: Allow to specify pre-allocated buffer in audicore.WaveFile It lets us re-use the same buffer for playing multiple files. This also allows us to control the size of the buffer. Half of the buffer will be used for the fist, and half for the second internal buffer. --- shared-bindings/audiocore/WaveFile.c | 22 ++++++++++++++++------ shared-bindings/audiocore/WaveFile.h | 2 +- shared-module/audiocore/WaveFile.c | 33 ++++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 18 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 4c1993b7c..7398353b0 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -39,13 +39,15 @@ //| ======================================================== //| //| 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 //| //| Playing a wave file from flash:: //| @@ -68,15 +70,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-module/audiocore/WaveFile.c b/shared-module/audiocore/WaveFile.c index 810d9c33b..df5d4b61d 100644 --- a/shared-module/audiocore/WaveFile.c +++ b/shared-module/audiocore/WaveFile.c @@ -46,7 +46,9 @@ struct wave_format_chunk { }; 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) { // Load the wave self->file = file; uint8_t chunk_header[16]; @@ -84,7 +86,6 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, } // Get the sample_rate self->sample_rate = format.sample_rate; - self->len = 256; self->channel_count = format.num_channels; self->bits_per_sample = format.bits_per_sample; @@ -111,21 +112,31 @@ void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, // Try to allocate two buffers, one will be loaded from file and the other // DMAed to DAC. - self->buffer = m_malloc(self->len, false); - if (self->buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate first buffer")); - } + if (buffer_size) { + self->len = buffer_size / 2; + self->buffer = buffer; + self->second_buffer = buffer + self->len; + } else { + self->len = 256; + self->buffer = m_malloc(self->len, false); + if (self->buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate first buffer")); + } - self->second_buffer = m_malloc(self->len, false); - if (self->second_buffer == NULL) { - common_hal_audioio_wavefile_deinit(self); - mp_raise_msg(&mp_type_MemoryError, translate("Couldn't allocate second buffer")); + self->second_buffer = m_malloc(self->len, false); + if (self->second_buffer == NULL) { + common_hal_audioio_wavefile_deinit(self); + mp_raise_msg(&mp_type_MemoryError, + translate("Couldn't allocate second buffer")); + } } } void common_hal_audioio_wavefile_deinit(audioio_wavefile_obj_t* self) { self->buffer = NULL; + self->second_buffer = NULL; } bool common_hal_audioio_wavefile_deinited(audioio_wavefile_obj_t* self) { -- cgit v1.2.3 From 1b7e213be4dc6cacd2b648e16470756473106c4a Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 8 Aug 2019 14:58:51 -0400 Subject: fix terminalio not clearing on construct --- shared-module/terminalio/Terminal.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'shared-module') diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 86c3e903e..df92a5dc4 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -36,6 +36,12 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, d self->tilegrid = tilegrid; self->first_row = 0; + for (uint16_t x = 0; x < self->tilegrid->width_in_tiles; x++) { + for (uint16_t y = 0; y < self->tilegrid->height_in_tiles; y++) { + common_hal_displayio_tilegrid_set_tile(self->tilegrid, x, y, 0); + } + } + common_hal_displayio_tilegrid_set_top_left(self->tilegrid, 0, 1); } -- cgit v1.2.3 From be5205d02081771e7aea51285f94fee83ef4fb77 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 10 Aug 2019 09:33:45 -0500 Subject: usb_hid: Allow USB work to progress while waiting for tud_hid_ready Otherwise, examples like the one attached to the related issue fail because tud_hid_ready never returns true. Testing performed: Adapted the example to nrf particle xenon (it was handy), removed dependency on IR, verified that the problem occurred before this change, and that it was fixed after this change. Closes: #2048 --- shared-module/usb_hid/Device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index a5a57419c..26d70cb82 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -47,7 +47,11 @@ void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* // Wait until interface is ready, timeout = 2 seconds uint64_t end_ticks = ticks_ms + 2000; - while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { } + while ( (ticks_ms < end_ticks) && !tud_hid_ready() ) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP; +#endif + } if ( !tud_hid_ready() ) { mp_raise_msg(&mp_type_OSError, translate("USB Busy")); -- cgit v1.2.3 From e3c0428838efa2800dfa319089b869048dad851a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 11 Aug 2019 08:40:19 -0500 Subject: shared-module: Use RUN_BACKGROUND_TASKS --- shared-module/displayio/Display.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 51c6f292a..d1b4be20f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -85,9 +85,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint32_t i = 0; while (!self->begin_transaction(self->bus)) { -#ifdef MICROPY_VM_HOOK_LOOP - MICROPY_VM_HOOK_LOOP ; -#endif + RUN_BACKGROUND_TASKS; } while (i < init_sequence_len) { uint8_t *cmd = init_sequence + i; @@ -235,7 +233,7 @@ int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* sel uint64_t last_refresh = self->last_refresh; // Don't try to refresh if we got an exception. while (last_refresh == self->last_refresh && MP_STATE_VM(mp_pending_exception) == NULL) { - MICROPY_VM_HOOK_LOOP + RUN_BACKGROUND_TASKS; } return 0; } -- cgit v1.2.3 From b3de7efc07365bd4cb3a8c89196dfbc29bcc9c04 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 14 Aug 2019 15:53:58 -0700 Subject: Fix I2CDisplay lifecycle and splash lifecycle. Fixes https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306/issues/2 --- py/circuitpy_mpconfig.h | 10 +--------- shared-module/board/__init__.c | 29 ++++++++++++++++++++++++----- shared-module/displayio/Display.c | 19 +++++++++++++++---- shared-module/displayio/__init__.c | 6 ++++-- 4 files changed, 44 insertions(+), 20 deletions(-) (limited to 'shared-module') diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d88d6538e..1dbca8c61 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -273,13 +273,7 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_SPI (defined(DEFAULT_SPI_BUS_SCK) && defined(DEFAULT_SPI_BUS_MISO) && defined(DEFAULT_SPI_BUS_MOSI)) #define BOARD_UART (defined(DEFAULT_UART_BUS_RX) && defined(DEFAULT_UART_BUS_TX)) -#if BOARD_I2C -#define BOARD_I2C_ROOT_POINTER mp_obj_t shared_i2c_bus; -#else -#define BOARD_I2C_ROOT_POINTER -#endif - -// SPI is always allocated off the heap. +// I2C and SPI are always allocated off the heap. #if BOARD_UART #define BOARD_UART_ROOT_POINTER mp_obj_t shared_uart_bus; @@ -289,7 +283,6 @@ extern const struct _mp_obj_module_t board_module; #else #define BOARD_MODULE -#define BOARD_I2C_ROOT_POINTER #define BOARD_UART_ROOT_POINTER #endif @@ -647,7 +640,6 @@ extern const struct _mp_obj_module_t ustack_module; GAMEPAD_ROOT_POINTERS \ mp_obj_t pew_singleton; \ mp_obj_t terminal_tilegrid_tiles; \ - BOARD_I2C_ROOT_POINTER \ BOARD_UART_ROOT_POINTER \ FLASH_ROOT_POINTERS \ NETWORK_ROOT_POINTERS \ diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 5a1dead78..dd07d7190 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -40,17 +40,25 @@ #endif #if BOARD_I2C +// Statically allocate the I2C object so it can live past the end of the heap and into the next VM. +// That way it can be used by built-in I2CDisplay displays and be accessible through board.I2C(). +STATIC busio_i2c_obj_t i2c_obj; +STATIC mp_obj_t i2c_singleton = NULL; + mp_obj_t common_hal_board_get_i2c(void) { - return MP_STATE_VM(shared_i2c_bus); + return i2c_singleton; } mp_obj_t common_hal_board_create_i2c(void) { - busio_i2c_obj_t *self = m_new_ll_obj(busio_i2c_obj_t); + if (i2c_singleton != NULL) { + return i2c_singleton; + } + busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); - MP_STATE_VM(shared_i2c_bus) = MP_OBJ_FROM_PTR(self); - return MP_STATE_VM(shared_i2c_bus); + i2c_singleton = (mp_obj_t)self; + return i2c_singleton; } #endif @@ -101,7 +109,18 @@ mp_obj_t common_hal_board_create_uart(void) { void reset_board_busses(void) { #if BOARD_I2C - MP_STATE_VM(shared_i2c_bus) = NULL; + bool display_using_i2c = false; + #if CIRCUITPY_DISPLAYIO + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].i2cdisplay_bus.bus == i2c_singleton) { + display_using_i2c = true; + break; + } + } + #endif + if (!display_using_i2c) { + i2c_singleton = NULL; + } #endif #if BOARD_SPI bool display_using_spi = false; diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 51c6f292a..aa36ee982 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -199,19 +199,26 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group) { if (root_group == NULL) { - root_group = &circuitpython_splash; + if (!circuitpython_splash.in_group) { + root_group = &circuitpython_splash; + } else if (self->current_group == &circuitpython_splash) { + return false; + } } if (root_group == self->current_group) { return true; } - if (root_group->in_group) { + if (root_group != NULL && root_group->in_group) { return false; } if (self->current_group != NULL) { self->current_group->in_group = false; } - displayio_group_update_transform(root_group, &self->transform); - root_group->in_group = true; + + if (root_group != NULL) { + displayio_group_update_transform(root_group, &self->transform); + root_group->in_group = true; + } self->current_group = root_group; self->full_refresh = true; common_hal_displayio_display_refresh_soon(self); @@ -402,6 +409,10 @@ void displayio_display_update_backlight(displayio_display_obj_t* self) { } void release_display(displayio_display_obj_t* self) { + if (self->current_group != NULL) { + self->current_group->in_group = false; + } + if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 8f6e650a1..3e9c4aa2a 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -163,7 +163,7 @@ void displayio_refresh_displays(void) { void common_hal_displayio_release_displays(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].fourwire_bus.base.type; - if (bus_type == NULL) { + if (bus_type == NULL || bus_type == &mp_type_NoneType) { continue; } else if (bus_type == &displayio_fourwire_type) { common_hal_displayio_fourwire_deinit(&displays[i].fourwire_bus); @@ -235,12 +235,14 @@ void reset_displays(void) { // Not an active display. continue; } + } + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { // Reset the displayed group. Only the first will get the terminal but // that's ok. displayio_display_obj_t* display = &displays[i].display; display->auto_brightness = true; - common_hal_displayio_display_show(display, &circuitpython_splash); + common_hal_displayio_display_show(display, NULL); } } -- cgit v1.2.3 From 630c92392abef67b0e6f81c98316dea93d3b2376 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 16 Aug 2019 15:18:53 -0400 Subject: address review comments; avoid calling common_hal_bleio_device... routines from shared-bindings --- ports/nrf/common-hal/bleio/Attribute.c | 14 +++++----- ports/nrf/common-hal/bleio/Central.c | 11 +++++++- ports/nrf/common-hal/bleio/Peripheral.c | 11 +++++--- ports/nrf/common-hal/bleio/__init__.c | 4 +-- shared-bindings/bleio/Attribute.c | 14 +++++----- shared-bindings/bleio/Central.c | 45 ++++++++------------------------- shared-bindings/bleio/Central.h | 3 ++- shared-bindings/bleio/Characteristic.c | 4 +-- shared-bindings/bleio/Descriptor.c | 4 +-- shared-bindings/bleio/Peripheral.c | 41 ++++++------------------------ shared-bindings/bleio/Peripheral.h | 3 ++- shared-bindings/bleio/__init__.c | 3 --- shared-module/bleio/Attribute.c | 14 +++++----- shared-module/bleio/Attribute.h | 14 +++++----- 14 files changed, 74 insertions(+), 111 deletions(-) (limited to 'shared-module') diff --git a/ports/nrf/common-hal/bleio/Attribute.c b/ports/nrf/common-hal/bleio/Attribute.c index bffe68254..fd1e7538d 100644 --- a/ports/nrf/common-hal/bleio/Attribute.c +++ b/ports/nrf/common-hal/bleio/Attribute.c @@ -29,31 +29,31 @@ // Convert a bleio security mode to a ble_gap_conn_sec_mode_t setting. void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { switch (security_mode) { - case SEC_MODE_NO_ACCESS: + case SECURITY_MODE_NO_ACCESS: BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); break; - case SEC_MODE_OPEN: + case SECURITY_MODE_OPEN: BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); break; - case SEC_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_NO_MITM: BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); break; - case SEC_MODE_ENC_WITH_MITM: + case SECURITY_MODE_ENC_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); break; - case SEC_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); break; - case SEC_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); break; - case SEC_MODE_SIGNED_WITH_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); break; } diff --git a/ports/nrf/common-hal/bleio/Central.c b/ports/nrf/common-hal/bleio/Central.c index c42a2084a..d771437d6 100644 --- a/ports/nrf/common-hal/bleio/Central.c +++ b/ports/nrf/common-hal/bleio/Central.c @@ -34,9 +34,9 @@ #include "nrf_soc.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Central.h" -#include "common-hal/bleio/__init__.h" STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) { bleio_central_obj_t *central = (bleio_central_obj_t*)central_in; @@ -131,6 +131,15 @@ bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self) { return self->conn_handle != BLE_CONN_HANDLE_INVALID; } +mp_obj_tuple_t *common_hal_bleio_central_discover_remote_services(bleio_central_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; +} + mp_obj_list_t *common_hal_bleio_central_get_remote_services(bleio_central_obj_t *self) { return self->remote_services_list; } diff --git a/ports/nrf/common-hal/bleio/Peripheral.c b/ports/nrf/common-hal/bleio/Peripheral.c index 640b93180..ed35516fc 100644 --- a/ports/nrf/common-hal/bleio/Peripheral.c +++ b/ports/nrf/common-hal/bleio/Peripheral.c @@ -36,12 +36,12 @@ #include "py/objlist.h" #include "py/objstr.h" #include "py/runtime.h" +#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -#include "common-hal/bleio/Service.h" #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(300, UNIT_0_625_MS) @@ -303,8 +303,13 @@ void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *self) { sd_ble_gap_disconnect(self->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); } -mp_obj_list_t *common_hal_bleio_peripheral_get_remote_services(bleio_peripheral_obj_t *self) { - return self->remote_services_list; +mp_obj_tuple_t *common_hal_bleio_peripheral_discover_remote_services(bleio_peripheral_obj_t *self, mp_obj_t service_uuids_whitelist) { + common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), service_uuids_whitelist); + // Convert to a tuple and then clear the list so the callee will take ownership. + mp_obj_tuple_t *services_tuple = mp_obj_new_tuple(self->remote_services_list->len, + self->remote_services_list->items); + mp_obj_list_clear(self->remote_services_list); + return services_tuple; } void common_hal_bleio_peripheral_pair(bleio_peripheral_obj_t *self) { diff --git a/ports/nrf/common-hal/bleio/__init__.c b/ports/nrf/common-hal/bleio/__init__.c index 2d144f8b5..2e26ac07d 100644 --- a/ports/nrf/common-hal/bleio/__init__.c +++ b/ports/nrf/common-hal/bleio/__init__.c @@ -218,7 +218,7 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, mp_ob // Call common_hal_bleio_characteristic_construct() to initalize some fields and set up evt handler. common_hal_bleio_characteristic_construct( - characteristic, uuid, props, SEC_MODE_OPEN, SEC_MODE_OPEN, + characteristic, uuid, props, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, GATT_MAX_DATA_LENGTH, false, // max_length, fixed_length: values may not matter for gattc mp_obj_new_list(0, NULL)); characteristic->handle = gattc_char->handle_value; @@ -274,7 +274,7 @@ STATIC void on_desc_discovery_rsp(ble_gattc_evt_desc_disc_rsp_t *response, mp_ob // For now, just leave the UUID as NULL. } - common_hal_bleio_descriptor_construct(descriptor, uuid, SEC_MODE_OPEN, SEC_MODE_OPEN, + common_hal_bleio_descriptor_construct(descriptor, uuid, SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, GATT_MAX_DATA_LENGTH, false); descriptor->handle = gattc_desc->handle; descriptor->characteristic = m_desc_discovery_characteristic; diff --git a/shared-bindings/bleio/Attribute.c b/shared-bindings/bleio/Attribute.c index cbbc07b9e..2cc9ef6d0 100644 --- a/shared-bindings/bleio/Attribute.c +++ b/shared-bindings/bleio/Attribute.c @@ -76,13 +76,13 @@ STATIC const mp_rom_map_elem_t bleio_attribute_locals_dict_table[] = { //| //| security_mode: authenticated data signing, without man-in-the-middle protection //| - { MP_ROM_QSTR(MP_QSTR_NO_ACCESS), MP_ROM_INT(SEC_MODE_NO_ACCESS) }, - { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(SEC_MODE_OPEN) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_NO_MITM), MP_ROM_INT(SEC_MODE_ENC_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_LESC_ENCRYPT_WITH_MITM), MP_ROM_INT(SEC_MODE_LESC_ENC_WITH_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_NO_MITM), MP_ROM_INT(SEC_MODE_SIGNED_NO_MITM) }, - { MP_ROM_QSTR(MP_QSTR_SIGNED_WITH_MITM), MP_ROM_INT(SEC_MODE_SIGNED_WITH_MITM) }, + { 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); diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c index 70b270c65..1fc455d8d 100644 --- a/shared-bindings/bleio/Central.c +++ b/shared-bindings/bleio/Central.c @@ -34,7 +34,6 @@ #include "py/objproperty.h" #include "py/objstr.h" #include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/Characteristic.h" @@ -66,7 +65,7 @@ //| //| central = bleio.Central() //| central.connect(my_entry.address, 10) # timeout after 10 seconds -//| central.discover_remote_services() +//| remote_services = central.discover_remote_services() //| //| .. class:: Central() @@ -132,15 +131,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_dis //| .. 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. -//| The attribute `remote_services` will contain a list of all discovered services. -//| `Central.connected` must be True. +//| 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. -//| If a service in service_uuids_whitelist is not found during discovery, it will not -//| appear in `remote_services`. +//| 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. //| @@ -149,6 +146,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_dis //| 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]); @@ -164,10 +163,9 @@ STATIC mp_obj_t bleio_central_discover_remote_services(mp_uint_t n_args, const m mp_raise_ValueError(translate("Not connected")); } - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj); - - return mp_const_none; + 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); @@ -189,28 +187,6 @@ 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) }, @@ -219,7 +195,6 @@ STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { // 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 1d7fb6248..cbc437087 100644 --- a/shared-bindings/bleio/Central.h +++ b/shared-bindings/bleio/Central.h @@ -28,6 +28,7 @@ #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" @@ -37,6 +38,6 @@ extern void common_hal_bleio_central_construct(bleio_central_obj_t *self); extern void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout); extern void common_hal_bleio_central_disconnect(bleio_central_obj_t *self); extern bool common_hal_bleio_central_get_connected(bleio_central_obj_t *self); -extern mp_obj_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 c9e0f3757..4894ad114 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -67,8 +67,8 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t static const mp_arg_t allowed_args[] = { { MP_QSTR_uuid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_properties, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN} }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN} }, + { MP_QSTR_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} }, diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index 95477336e..d7c2a85c7 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -62,8 +62,8 @@ STATIC mp_obj_t bleio_descriptor_make_new(const mp_obj_type_t *type, size_t n_ar 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 }, - { MP_QSTR_read_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, - { MP_QSTR_write_perm, MP_ARG_KW_ONLY| MP_ARG_INT, {.u_int = SEC_MODE_OPEN } }, + { MP_QSTR_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} }, }; diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index b42ca3784..630e6ed36 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -35,7 +35,6 @@ #include "py/objstr.h" #include "py/runtime.h" -#include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Adapter.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" @@ -263,15 +262,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripher //| .. 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. -//| The attribute `remote_services` will contain a list of all discovered services. +//| 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. -//| If a service in service_uuids_whitelist is not found during discovery, it will not -//| appear in `remote_services`. +//| 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. //| @@ -285,6 +282,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripher //| 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]); @@ -300,27 +299,12 @@ STATIC mp_obj_t bleio_peripheral_discover_remote_services(mp_uint_t n_args, cons mp_raise_ValueError(translate("Not connected")); } - common_hal_bleio_device_discover_remote_services(MP_OBJ_FROM_PTR(self), - args[ARG_service_uuids_whitelist].u_obj); - - return mp_const_none; + 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); -//| .. attribute:: remote_services (read-only) -//| -//| A tuple of services provided by the remote central. -//| If discovery did not occur, an empty tuple will be returned. -//| -STATIC mp_obj_t bleio_peripheral_get_remote_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_remote_services(self); - return mp_obj_new_tuple(service_list->len, service_list->items); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_remote_services_obj, bleio_peripheral_get_remote_services); - //| .. method:: pair() //| //| Request pairing with connected central. @@ -333,14 +317,6 @@ STATIC mp_obj_t bleio_peripheral_pair(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_pair_obj, bleio_peripheral_pair); -const mp_obj_property_t bleio_peripheral_remote_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_peripheral_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_peripheral_locals_dict_table[] = { // Methods { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_peripheral_start_advertising_obj) }, @@ -352,7 +328,6 @@ STATIC const mp_rom_map_elem_t bleio_peripheral_locals_dict_table[] = { // 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_remote_services), MP_ROM_PTR(&bleio_peripheral_remote_services_obj) }, { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_peripheral_services_obj) }, }; diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h index d9b72b2c3..597b65ce2 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -28,6 +28,7 @@ #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; @@ -39,7 +40,7 @@ extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *sel 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_list_t *common_hal_bleio_peripheral_get_remote_services(bleio_peripheral_obj_t *self); +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/__init__.c b/shared-bindings/bleio/__init__.c index 05be48ddc..739f461a5 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -94,9 +94,6 @@ STATIC const mp_rom_map_elem_t bleio_module_globals_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_adapter), MP_ROM_PTR(&common_hal_bleio_adapter_obj) }, - - // constants - { MP_ROM_QSTR(MP_QSTR_SEC), MP_ROM_PTR(&bleio_uuid_type) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_module_globals, bleio_module_globals_table); diff --git a/shared-module/bleio/Attribute.c b/shared-module/bleio/Attribute.c index ac854ec6b..2275003c9 100644 --- a/shared-module/bleio/Attribute.c +++ b/shared-module/bleio/Attribute.c @@ -31,13 +31,13 @@ void common_hal_bleio_attribute_security_mode_check_valid(bleio_attribute_security_mode_t security_mode) { switch (security_mode) { - case SEC_MODE_NO_ACCESS: - case SEC_MODE_OPEN: - case SEC_MODE_ENC_NO_MITM: - case SEC_MODE_ENC_WITH_MITM: - case SEC_MODE_LESC_ENC_WITH_MITM: - case SEC_MODE_SIGNED_NO_MITM: - case SEC_MODE_SIGNED_WITH_MITM: + case SECURITY_MODE_NO_ACCESS: + case SECURITY_MODE_OPEN: + case SECURITY_MODE_ENC_NO_MITM: + case SECURITY_MODE_ENC_WITH_MITM: + case SECURITY_MODE_LESC_ENC_WITH_MITM: + case SECURITY_MODE_SIGNED_NO_MITM: + case SECURITY_MODE_SIGNED_WITH_MITM: break; default: mp_raise_ValueError(translate("Invalid security_mode")); diff --git a/shared-module/bleio/Attribute.h b/shared-module/bleio/Attribute.h index 62615f1b5..a498a14a5 100644 --- a/shared-module/bleio/Attribute.h +++ b/shared-module/bleio/Attribute.h @@ -29,13 +29,13 @@ // BLE security modes: 0x typedef enum { - SEC_MODE_NO_ACCESS = 0x00, - SEC_MODE_OPEN = 0x11, - SEC_MODE_ENC_NO_MITM = 0x21, - SEC_MODE_ENC_WITH_MITM = 0x31, - SEC_MODE_LESC_ENC_WITH_MITM = 0x41, - SEC_MODE_SIGNED_NO_MITM = 0x12, - SEC_MODE_SIGNED_WITH_MITM = 0x22, + SECURITY_MODE_NO_ACCESS = 0x00, + SECURITY_MODE_OPEN = 0x11, + SECURITY_MODE_ENC_NO_MITM = 0x21, + SECURITY_MODE_ENC_WITH_MITM = 0x31, + SECURITY_MODE_LESC_ENC_WITH_MITM = 0x41, + SECURITY_MODE_SIGNED_NO_MITM = 0x12, + SECURITY_MODE_SIGNED_WITH_MITM = 0x22, } bleio_attribute_security_mode_t; #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_ATTRIBUTE_H -- cgit v1.2.3