diff options
| author | sommersoft <sommersoft@gmail.com> | 2019-07-31 16:44:43 -0500 |
|---|---|---|
| committer | sommersoft <sommersoft@gmail.com> | 2019-07-31 16:44:43 -0500 |
| commit | 9939d0c4f49db084f52a12b6ea5f6ce97b614146 (patch) | |
| tree | 6c338f9e01c581793255757b4483d3d88824095f /shared-bindings | |
| parent | a498bcd94d7f869e2cb2e992babacb981de688c0 (diff) | |
| parent | 366fdcce18e148a6828b7a7074e1e4198fca3595 (diff) | |
Merge branch 'master' of https://github.com/adafruit/circuitpython into mixer_voice
Diffstat (limited to 'shared-bindings')
129 files changed, 3012 insertions, 1891 deletions
diff --git a/shared-bindings/_pew/PewPew.c b/shared-bindings/_pew/PewPew.c index 50647488c..3ff208761 100644 --- a/shared-bindings/_pew/PewPew.c +++ b/shared-bindings/_pew/PewPew.c @@ -88,35 +88,38 @@ STATIC mp_obj_t pewpew_make_new(const mp_obj_type_t *type, size_t n_args, mp_obj_get_array(args[ARG_cols].u_obj, &cols_size, &cols); if (bufinfo.len != rows_size * cols_size) { - mp_raise_ValueError(translate("")); + mp_raise_ValueError(translate("Incorrect buffer size")); } for (size_t i = 0; i < rows_size; ++i) { if (!MP_OBJ_IS_TYPE(rows[i], &digitalio_digitalinout_type)) { - mp_raise_TypeError(translate("")); + mp_raise_TypeError(translate("Row entry must be digitalio.DigitalInOut")); } digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(rows[i]); - raise_error_if_deinited( - common_hal_digitalio_digitalinout_deinited(pin)); + if (common_hal_digitalio_digitalinout_deinited(pin)) { + raise_deinited_error(); + } } for (size_t i = 0; i < cols_size; ++i) { if (!MP_OBJ_IS_TYPE(cols[i], &digitalio_digitalinout_type)) { - mp_raise_TypeError(translate("")); + mp_raise_TypeError(translate("Column entry must be digitalio.DigitalInOut")); } digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(cols[i]); - raise_error_if_deinited( - common_hal_digitalio_digitalinout_deinited(pin)); + if (common_hal_digitalio_digitalinout_deinited(pin)) { + raise_deinited_error(); + } } if (!MP_OBJ_IS_TYPE(args[ARG_buttons].u_obj, &digitalio_digitalinout_type)) { - mp_raise_TypeError(translate("")); + mp_raise_TypeError(translate("buttons must be digitalio.DigitalInOut")); } digitalio_digitalinout_obj_t *buttons = MP_OBJ_TO_PTR( args[ARG_buttons].u_obj); - raise_error_if_deinited( - common_hal_digitalio_digitalinout_deinited(buttons)); + if (common_hal_digitalio_digitalinout_deinited(buttons)) { + raise_deinited_error(); + } pew_obj_t *pew = MP_STATE_VM(pew_singleton); if (!pew) { @@ -148,4 +151,3 @@ const mp_obj_type_t pewpew_type = { .make_new = pewpew_make_new, .locals_dict = (mp_obj_dict_t*)&pewpew_locals_dict, }; - diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 7c2766aa3..420720e62 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -51,7 +51,7 @@ extern const int32_t colorwheel(float pos); //| //| :class:`~_pixelbuf.PixelBuf` implements an RGB[W] bytearray abstraction. //| -//| .. class:: PixelBuf(size, buf, byteorder=BGR, bpp=3) +//| .. class:: PixelBuf(size, buf, byteorder=BGR, brightness=0, rawbuf=None, offset=0, dotstar=False, auto_write=False, write_function=None, write_args=None) //| //| Create a PixelBuf object of the specified size, byteorder, and bits per pixel. //| @@ -66,14 +66,14 @@ extern const int32_t colorwheel(float pos); //| //| :param ~int size: Number of pixelsx //| :param ~bytearray buf: Bytearray to store pixel data in -//| :param ~_pixelbuf.ByteOrder byteorder: Byte order constant from `_pixelbuf` (also sets the bpp) +//| :param ~_pixelbuf.ByteOrder byteorder: Byte order constant from `_pixelbuf` //| :param ~float brightness: Brightness (0 to 1.0, default 1.0) //| :param ~bytearray rawbuf: Bytearray to store raw pixel colors in //| :param ~int offset: Offset from start of buffer (default 0) //| :param ~bool dotstar: Dotstar mode (default False) //| :param ~bool auto_write: Whether to automatically write pixels (Default False) //| :param ~callable write_function: (optional) Callable to use to send pixels -//| :param ~list write_args: (optional) Tuple or list of args to pass to ``write_function``. The +//| :param ~list write_args: (optional) Tuple or list of args to pass to ``write_function``. The //| PixelBuf instance is appended after these args. //| STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -95,7 +95,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a 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); - if (mp_obj_is_subclass_fast(args[ARG_byteorder].u_obj, &pixelbuf_byteorder_type)) + if (mp_obj_is_subclass_fast(args[ARG_byteorder].u_obj, &pixelbuf_byteorder_type)) mp_raise_TypeError_varg(translate("byteorder is not an instance of ByteOrder (got a %s)"), mp_obj_get_type_str(args[ARG_byteorder].u_obj)); pixelbuf_byteorder_obj_t *byteorder = (args[ARG_byteorder].u_obj == mp_const_none) ? MP_OBJ_FROM_PTR(&byteorder_BGR) : args[ARG_byteorder].u_obj; @@ -122,7 +122,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a if (!MP_OBJ_IS_TYPE(args[ARG_write_args].u_obj, &mp_type_list) && !MP_OBJ_IS_TYPE(args[ARG_write_args].u_obj, &mp_type_tuple) && - args[ARG_write_args].u_obj != mp_const_none) + args[ARG_write_args].u_obj != mp_const_none) { mp_raise_ValueError(translate("write_args must be a list, tuple, or None")); } @@ -186,8 +186,8 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a else if (self->brightness > 1) self->brightness = 1; } - - if (self->dotstar_mode) { + + if (self->dotstar_mode) { // Initialize the buffer with the dotstar start bytes. // Header and end must be setup by caller for (uint i = 0; i < self->pixels * 4; i += 4) { @@ -197,7 +197,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_make_new(const mp_obj_type_t *type, size_t n_a } } } - + return MP_OBJ_FROM_PTR(self); } @@ -227,7 +227,7 @@ const mp_obj_property_t pixelbuf_pixelbuf_bpp_obj = { //| setting this value causes a recomputation of the values in buf. //| If only a buf was provided, then the brightness only applies to //| future pixel changes. -//| In DotStar mode +//| In DotStar mode //| STATIC mp_obj_t pixelbuf_pixelbuf_obj_get_brightness(mp_obj_t self_in) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &pixelbuf_pixelbuf_type)); @@ -266,7 +266,7 @@ void pixelbuf_recalculate_brightness(pixelbuf_pixelbuf_obj_t *self) { // Compensate for shifted buffer (bpp=3 dotstar) for (uint i = 0; i < self->bytes; i++) { // Don't adjust per-pixel luminance bytes in dotstar mode - if (!self->dotstar_mode || (i % 4 != 0)) + if (!self->dotstar_mode || (i % 4 != 0)) buf[i] = rawbuf[i] * self->brightness; } } @@ -367,11 +367,13 @@ void call_write_function(pixelbuf_pixelbuf_obj_t *self) { } } - - -//| .. method:: [] +//| .. method:: __getitem__(index) +//| +//| Returns the pixel value at the given index. //| -//| Get or set pixels. Supports individual pixels and slices. +//| .. method:: __setitem__(index, value) +//| +//| Sets the pixel value at the given index. //| STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { mp_check_self(MP_OBJ_IS_TYPE(self_in, &pixelbuf_pixelbuf_type)); @@ -380,7 +382,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp // delete item // slice deletion return MP_OBJ_NULL; // op not supported - } + } pixelbuf_pixelbuf_obj_t *self = MP_OBJ_TO_PTR(self_in); if (0) { @@ -390,7 +392,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp if (!mp_seq_get_fast_slice_indexes(self->bytes, index_in, &slice)) mp_raise_NotImplementedError(translate("Only slices with step=1 (aka None) are supported")); - if ((slice.stop * self->pixel_step) > self->bytes) + if ((slice.stop * self->pixel_step) > self->bytes) mp_raise_IndexError(translate("Range out of bounds")); if (value == MP_OBJ_SENTINEL) { // Get @@ -422,8 +424,8 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp for (size_t i = slice.start; i < slice.stop; i++) { mp_obj_t *item = src_objs[i-slice.start]; if (MP_OBJ_IS_TYPE(value, &mp_type_list) || MP_OBJ_IS_TYPE(value, &mp_type_tuple) || MP_OBJ_IS_INT(value)) { - pixelbuf_set_pixel(self->buf + (i * self->pixel_step), - self->two_buffers ? self->rawbuf + (i * self->pixel_step) : NULL, + pixelbuf_set_pixel(self->buf + (i * self->pixel_step), + self->two_buffers ? self->rawbuf + (i * self->pixel_step) : NULL, self->brightness, item, &self->byteorder, self->dotstar_mode); } } @@ -438,14 +440,14 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp } else { // Single index rather than slice. size_t index = mp_get_index(self->base.type, self->pixels, index_in, false); size_t offset = (index * self->pixel_step); - if (offset > self->bytes) + if (offset > self->bytes) mp_raise_IndexError(translate("Pixel beyond bounds of buffer")); if (value == MP_OBJ_SENTINEL) { // Get uint8_t *pixelstart = (uint8_t *)(self->two_buffers ? self->rawbuf : self->buf) + offset; return pixelbuf_get_pixel(pixelstart, &self->byteorder, self->dotstar_mode); } else { // Store - pixelbuf_set_pixel(self->buf + offset, self->two_buffers ? self->rawbuf + offset : NULL, + pixelbuf_set_pixel(self->buf + offset, self->two_buffers ? self->rawbuf + offset : NULL, self->brightness, value, &self->byteorder, self->dotstar_mode); if (self->auto_write) call_write_function(self); diff --git a/shared-bindings/_pixelbuf/__init__.c b/shared-bindings/_pixelbuf/__init__.c index 31defc7fb..48b9f1cef 100644 --- a/shared-bindings/_pixelbuf/__init__.c +++ b/shared-bindings/_pixelbuf/__init__.c @@ -53,7 +53,7 @@ //| //| PixelBuf -//| .. class:: ByteOrder +//| .. class:: ByteOrder() //| //| Classes representing byteorders for circuitpython @@ -169,34 +169,34 @@ const int32_t colorwheel(float pos) { /// RGB -//| .. class:: RGB +//| .. data:: RGB //| //| * **order** Red, Green, Blue //| * **bpp** 3 PIXELBUF_BYTEORDER(RGB, 3, 0, 1, 2, 3, false, false) -//| .. class:: RBG +//| .. data:: RBG //| //| * **order** Red, Blue, Green //| * **bpp** 3 PIXELBUF_BYTEORDER(RBG, 3, 0, 2, 1, 3, false, false) -//| .. class:: GRB +//| .. data:: GRB //| //| * **order** Green, Red, Blue //| * **bpp** 3 //| //| Commonly used by NeoPixel. PIXELBUF_BYTEORDER(GRB, 3, 1, 0, 2, 3, false, false) -//| .. class:: GBR +//| .. data:: GBR //| //| * **order** Green, Blue, Red //| * **bpp** 3 PIXELBUF_BYTEORDER(GBR, 3, 1, 2, 0, 3, false, false) -//| .. class:: BRG +//| .. data:: BRG //| //| * **order** Blue, Red, Green //| * **bpp** 3 PIXELBUF_BYTEORDER(BRG, 3, 2, 0, 1, 3, false, false) -//| .. class:: BGR +//| .. data:: BGR //| //| * **order** Blue, Green, Red //| * **bpp** 3 @@ -205,19 +205,19 @@ PIXELBUF_BYTEORDER(BRG, 3, 2, 0, 1, 3, false, false) PIXELBUF_BYTEORDER(BGR, 3, 2, 1, 0, 3, false, false) // RGBW -//| .. class:: RGBW +//| .. data:: RGBW //| //| * **order** Red, Green, Blue, White //| * **bpp** 4 //| * **has_white** True PIXELBUF_BYTEORDER(RGBW, 4, 0, 1, 2, 3, true, false) -//| .. class:: RBGW +//| .. data:: RBGW //| //| * **order** Red, Blue, Green, White //| * **bpp** 4 //| * **has_white** True PIXELBUF_BYTEORDER(RBGW, 4, 0, 2, 1, 3, true, false) -//| .. class:: GRBW +//| .. data:: GRBW //| //| * **order** Green, Red, Blue, White //| * **bpp** 4 @@ -225,19 +225,19 @@ PIXELBUF_BYTEORDER(RBGW, 4, 0, 2, 1, 3, true, false) //| //| Commonly used by RGBW NeoPixels. PIXELBUF_BYTEORDER(GRBW, 4, 1, 0, 2, 3, true, false) -//| .. class:: GBRW +//| .. data:: GBRW //| //| * **order** Green, Blue, Red, White //| * **bpp** 4 //| * **has_white** True PIXELBUF_BYTEORDER(GBRW, 4, 1, 2, 0, 3, true, false) -//| .. class:: BRGW +//| .. data:: BRGW //| //| * **order** Blue, Red, Green, White //| * **bpp** 4 //| * **has_white** True PIXELBUF_BYTEORDER(BRGW, 4, 2, 0, 1, 3, true, false) -//| .. class:: BGRW +//| .. data:: BGRW //| //| * **order** Blue, Green, Red, White //| * **bpp** 4 @@ -248,37 +248,37 @@ PIXELBUF_BYTEORDER(BGRW, 4, 2, 1, 0, 3, true, false) // Luminosity chosen because the luminosity of a Dotstar at full bright // burns the eyes like looking at the Sun. // https://www.thesaurus.com/browse/luminosity?s=t -//| .. class:: LRGB +//| .. data:: LRGB //| //| * **order** *Luminosity*, Red, Green, Blue //| * **bpp** 4 //| * **has_luminosity** True PIXELBUF_BYTEORDER(LRGB, 4, 1, 2, 3, 0, false, true) -//| .. class:: LRBG +//| .. data:: LRBG //| //| * **order** *Luminosity*, Red, Blue, Green //| * **bpp** 4 //| * **has_luminosity** True PIXELBUF_BYTEORDER(LRBG, 4, 1, 3, 2, 0, false, true) -//| .. class:: LGRB +//| .. data:: LGRB //| //| * **order** *Luminosity*, Green, Red, Blue //| * **bpp** 4 //| * **has_luminosity** True PIXELBUF_BYTEORDER(LGRB, 4, 2, 1, 3, 0, false, true) -//| .. class:: LGBR +//| .. data:: LGBR //| //| * **order** *Luminosity*, Green, Blue, Red //| * **bpp** 4 //| * **has_luminosity** True PIXELBUF_BYTEORDER(LGBR, 4, 2, 3, 1, 0, false, true) -//| .. class:: LBRG +//| .. data:: LBRG //| //| * **order** *Luminosity*, Blue, Red, Green //| * **bpp** 4 //| * **has_luminosity** True PIXELBUF_BYTEORDER(LBRG, 4, 3, 1, 2, 0, false, true) -//| .. class:: LBGR +//| .. data:: LBGR //| //| * **order** *Luminosity*, Blue, Green, Red //| * **bpp** 4 diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c index 24a359664..9f3f89462 100644 --- a/shared-bindings/_stage/__init__.c +++ b/shared-bindings/_stage/__init__.c @@ -28,6 +28,7 @@ #include "py/mperrno.h" #include "py/runtime.h" #include "shared-bindings/busio/SPI.h" +#include "shared-bindings/displayio/Display.h" #include "shared-module/_stage/__init__.h" #include "Layer.h" #include "Text.h" @@ -49,7 +50,7 @@ //| Layer //| Text //| -//| .. function:: render(x0, y0, x1, y1, layers, buffer, spi) +//| .. function:: render(x0, y0, x1, y1, layers, buffer, display) //| //| Render and send to the display a fragment of the screen. //| @@ -59,11 +60,8 @@ //| :param int y1: Bottom edge of the fragment. //| :param list layers: A list of the :py:class:`~_stage.Layer` objects. //| :param bytearray buffer: A buffer to use for rendering. -//| :param ~busio.SPI spi: The SPI bus to use. +//| :param ~displayio.Display display: The display to use. //| -//| Note that this function only sends the raw pixel data. Setting up -//| the display for receiving it and handling the chip-select and -//| data-command pins has to be done outside of it. //| There are also no sanity checks, outside of the basic overflow //| checking. The caller is responsible for making the passed parameters //| valid. @@ -85,12 +83,26 @@ STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { uint16_t *buffer = bufinfo.buf; size_t buffer_size = bufinfo.len / 2; // 16-bit indexing - busio_spi_obj_t *spi = MP_OBJ_TO_PTR(args[6]); + mp_obj_t native_display = mp_instance_cast_to_native_base(args[6], + &displayio_display_type); + if (!MP_OBJ_IS_TYPE(native_display, &displayio_display_type)) { + mp_raise_TypeError(translate("argument num/types mismatch")); + } + displayio_display_obj_t *display = MP_OBJ_TO_PTR(native_display); - if (!render_stage(x0, y0, x1, y1, layers, layers_size, - buffer, buffer_size, spi)) { - mp_raise_OSError(MP_EIO); + while (!displayio_display_begin_transaction(display)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif } + displayio_area_t area; + area.x1 = x0; + area.y1 = y0; + area.x2 = x1; + area.y2 = y1; + displayio_display_set_region_to_update(display, &area); + render_stage(x0, y0, x1, y1, layers, layers_size, buffer, buffer_size, display); + displayio_display_end_transaction(display); return mp_const_none; } diff --git a/shared-bindings/analogio/AnalogIn.c b/shared-bindings/analogio/AnalogIn.c index 116f82a03..a8bbbf59a 100644 --- a/shared-bindings/analogio/AnalogIn.c +++ b/shared-bindings/analogio/AnalogIn.c @@ -86,6 +86,11 @@ STATIC mp_obj_t analogio_analogin_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_deinit_obj, analogio_analogin_deinit); +STATIC void check_for_deinit(analogio_analogin_obj_t *self) { + if (common_hal_analogio_analogin_deinited(self)) { + raise_deinited_error(); + } +} //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -113,7 +118,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(analogio_analogin___exit___obj, 4, 4, //| STATIC mp_obj_t analogio_analogin_obj_get_value(mp_obj_t self_in) { analogio_analogin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_analogio_analogin_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_analogio_analogin_get_value(self)); } MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_get_value_obj, analogio_analogin_obj_get_value); @@ -132,7 +137,7 @@ const mp_obj_property_t analogio_analogin_value_obj = { //| STATIC mp_obj_t analogio_analogin_obj_get_reference_voltage(mp_obj_t self_in) { analogio_analogin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_analogio_analogin_deinited(self)); + check_for_deinit(self); return mp_obj_new_float(common_hal_analogio_analogin_get_reference_voltage(self)); } MP_DEFINE_CONST_FUN_OBJ_1(analogio_analogin_get_reference_voltage_obj, diff --git a/shared-bindings/analogio/AnalogOut.c b/shared-bindings/analogio/AnalogOut.c index dcbd7ecfb..0816da465 100644 --- a/shared-bindings/analogio/AnalogOut.c +++ b/shared-bindings/analogio/AnalogOut.c @@ -112,7 +112,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(analogio_analogout___exit___obj, 4, 4 //| resolution, the value is 16-bit. STATIC mp_obj_t analogio_analogout_obj_set_value(mp_obj_t self_in, mp_obj_t value) { analogio_analogout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_analogio_analogout_deinited(self)); + if (common_hal_analogio_analogout_deinited(self)) { + raise_deinited_error(); + } uint32_t v = mp_obj_get_int(value); if (v >= (1 << 16)) { mp_raise_ValueError(translate("AnalogOut is only 16 bits. Value must be less than 65536.")); diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 48424d073..980f11392 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -134,6 +134,11 @@ STATIC mp_obj_t audiobusio_i2sout_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_deinit_obj, audiobusio_i2sout_deinit); +STATIC void check_for_deinit(audiobusio_i2sout_obj_t *self) { + if (common_hal_audiobusio_i2sout_deinited(self)) { + raise_deinited_error(); + } +} //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -169,7 +174,7 @@ STATIC mp_obj_t audiobusio_i2sout_obj_play(size_t n_args, const mp_obj_t *pos_ar { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + 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); @@ -186,7 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(audiobusio_i2sout_play_obj, 1, audiobusio_i2sout_obj_ //| STATIC mp_obj_t audiobusio_i2sout_obj_stop(mp_obj_t self_in) { audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + check_for_deinit(self); common_hal_audiobusio_i2sout_stop(self); return mp_const_none; } @@ -198,7 +203,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_stop_obj, audiobusio_i2sout_obj_stop //| STATIC mp_obj_t audiobusio_i2sout_obj_get_playing(mp_obj_t self_in) { audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_audiobusio_i2sout_get_playing(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_get_playing_obj, audiobusio_i2sout_obj_get_playing); @@ -216,7 +221,7 @@ const mp_obj_property_t audiobusio_i2sout_playing_obj = { //| STATIC mp_obj_t audiobusio_i2sout_obj_pause(mp_obj_t self_in) { audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + check_for_deinit(self); if (!common_hal_audiobusio_i2sout_get_playing(self)) { mp_raise_RuntimeError(translate("Not playing")); @@ -232,7 +237,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_pause_obj, audiobusio_i2sout_obj_pau //| STATIC mp_obj_t audiobusio_i2sout_obj_resume(mp_obj_t self_in) { audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + check_for_deinit(self); if (common_hal_audiobusio_i2sout_get_paused(self)) { common_hal_audiobusio_i2sout_resume(self); @@ -248,7 +253,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_resume_obj, audiobusio_i2sout_obj_re //| STATIC mp_obj_t audiobusio_i2sout_obj_get_paused(mp_obj_t self_in) { audiobusio_i2sout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_i2sout_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_audiobusio_i2sout_get_paused(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_i2sout_get_paused_obj, audiobusio_i2sout_obj_get_paused); diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 5dca3fa59..0c92c2478 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -43,7 +43,7 @@ //| //| PDMIn can be used to record an input audio signal on a given set of pins. //| -//| .. class:: PDMIn(clock_pin, data_pin, \*, sample_rate=16000, bit_depth=8, mono=True, oversample=64, startup_delay=0.11) +//| .. class:: PDMIn(clock_pin, data_pin, *, sample_rate=16000, bit_depth=8, mono=True, oversample=64, startup_delay=0.11) //| //| Create a PDMIn object associated with the given pins. This allows you to //| record audio signals from the given pins. Individual ports may put further @@ -156,6 +156,11 @@ STATIC mp_obj_t audiobusio_pdmin_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_pdmin_deinit_obj, audiobusio_pdmin_deinit); +STATIC void check_for_deinit(audiobusio_pdmin_obj_t *self) { + if (common_hal_audiobusio_pdmin_deinited(self)) { + raise_deinited_error(); + } +} //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -188,7 +193,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4, //| STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_obj); - raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self)); + check_for_deinit(self); if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) { mp_raise_TypeError(translate("destination_length must be an int >= 0")); } @@ -223,7 +228,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(audiobusio_pdmin_record_obj, audiobusio_pdmin_obj_reco //| STATIC mp_obj_t audiobusio_pdmin_obj_get_sample_rate(mp_obj_t self_in) { audiobusio_pdmin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audiobusio_pdmin_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audiobusio_pdmin_get_sample_rate(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audiobusio_pdmin_get_sample_rate_obj, audiobusio_pdmin_obj_get_sample_rate); diff --git a/shared-bindings/audioio/Mixer.c b/shared-bindings/audiocore/Mixer.c index 5f224ad4a..ee4d8548c 100644 --- a/shared-bindings/audioio/Mixer.c +++ b/shared-bindings/audiocore/Mixer.c @@ -23,9 +23,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "shared-bindings/audioio/Mixer.h" -#include "shared-module/audioio/MixerVoice.h" -#include "shared-bindings/audioio/MixerVoice.h" +#include "shared-bindings/audiocore/Mixer.h" #include <stdint.h> @@ -34,7 +32,7 @@ #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" @@ -129,6 +127,12 @@ STATIC mp_obj_t audioio_mixer_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_deinit_obj, audioio_mixer_deinit); +STATIC void check_for_deinit(audioio_mixer_obj_t *self) { + if (common_hal_audioio_mixer_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -147,13 +151,61 @@ STATIC mp_obj_t audioio_mixer_obj___exit__(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_mixer___exit___obj, 4, 4, audioio_mixer_obj___exit__); + +//| .. method:: play(sample, *, voice=0, 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 `audioio.WaveFile`, `audioio.Mixer` or `audioio.RawSample`. +//| +//| The sample must match the Mixer's encoding settings given in the constructor. +//| +STATIC mp_obj_t audioio_mixer_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_voice, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_voice, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audioio_mixer_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_audioio_mixer_play(self, sample, args[ARG_voice].u_int, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_play_obj, 1, audioio_mixer_obj_play); + +//| .. method:: stop_voice(voice=0) +//| +//| Stops playback of the sample on the given voice. +//| +STATIC mp_obj_t audioio_mixer_obj_stop_voice(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_voice }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_voice, MP_ARG_INT, {.u_int = 0} }, + }; + audioio_mixer_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); + + common_hal_audioio_mixer_stop_voice(self, args[ARG_voice].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(audioio_mixer_stop_voice_obj, 1, audioio_mixer_obj_stop_voice); + //| .. attribute:: playing //| //| True when any voice is being output. (read-only) //| STATIC mp_obj_t audioio_mixer_obj_get_playing(mp_obj_t self_in) { audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_audioio_mixer_get_playing(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_playing_obj, audioio_mixer_obj_get_playing); @@ -171,7 +223,7 @@ const mp_obj_property_t audioio_mixer_playing_obj = { //| STATIC mp_obj_t audioio_mixer_obj_get_sample_rate(mp_obj_t self_in) { audioio_mixer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_mixer_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_mixer_get_sample_rate(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_mixer_get_sample_rate_obj, audioio_mixer_obj_get_sample_rate); diff --git a/shared-bindings/audioio/Mixer.h b/shared-bindings/audiocore/Mixer.h index 2e5adddf7..87d681ce6 100644 --- a/shared-bindings/audioio/Mixer.h +++ b/shared-bindings/audiocore/Mixer.h @@ -28,8 +28,8 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_MIXER_H #include "common-hal/microcontroller/Pin.h" -#include "shared-module/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-module/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" extern const mp_obj_type_t audioio_mixer_type; extern const mp_obj_type_t audioio_mixervoice_type; diff --git a/shared-bindings/audioio/RawSample.c b/shared-bindings/audiocore/RawSample.c index 7fc896449..912b48bfb 100644 --- a/shared-bindings/audioio/RawSample.c +++ b/shared-bindings/audiocore/RawSample.c @@ -31,8 +31,8 @@ #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audioio/AudioOut.h" #include "shared-bindings/util.h" +#include "shared-bindings/audiocore/RawSample.h" #include "supervisor/shared/translate.h" //| .. currentmodule:: audioio @@ -115,6 +115,12 @@ STATIC mp_obj_t audioio_rawsample_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_deinit_obj, audioio_rawsample_deinit); +STATIC void check_for_deinit(audioio_rawsample_obj_t *self) { + if (common_hal_audioio_rawsample_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -142,14 +148,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_rawsample___exit___obj, 4, 4, //| STATIC mp_obj_t audioio_rawsample_obj_get_sample_rate(mp_obj_t self_in) { audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_rawsample_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_rawsample_get_sample_rate(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_rawsample_get_sample_rate_obj, audioio_rawsample_obj_get_sample_rate); STATIC mp_obj_t audioio_rawsample_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { audioio_rawsample_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_rawsample_deinited(self)); + check_for_deinit(self); common_hal_audioio_rawsample_set_sample_rate(self, mp_obj_get_int(sample_rate)); return mp_const_none; } diff --git a/shared-bindings/audioio/RawSample.h b/shared-bindings/audiocore/RawSample.h index 0d764b77c..b02778cad 100644 --- a/shared-bindings/audioio/RawSample.h +++ b/shared-bindings/audiocore/RawSample.h @@ -27,9 +27,8 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_RAWSAMPLE_H -#include "common-hal/audioio/AudioOut.h" #include "common-hal/microcontroller/Pin.h" -#include "shared-module/audioio/RawSample.h" +#include "shared-module/audiocore/RawSample.h" extern const mp_obj_type_t audioio_rawsample_type; diff --git a/shared-bindings/audioio/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index cddeef769..4c1993b7c 100644 --- a/shared-bindings/audioio/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -29,7 +29,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/objproperty.h" #include "py/runtime.h" -#include "shared-bindings/audioio/WaveFile.h" +#include "shared-bindings/audiocore/WaveFile.h" #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" @@ -41,11 +41,11 @@ //| A .wav file prepped for audio playback. Only mono and stereo files are supported. Samples must //| be 8 bit unsigned or 16 bit signed. //| -//| .. class:: WaveFile(filename) +//| .. class:: WaveFile(file) //| //| Load a .wav file for playback with `audioio.AudioOut` or `audiobusio.I2SOut`. //| -//| :param bytes-like file: Already opened wave file +//| :param typing.BinaryIO file: Already opened wave file //| //| Playing a wave file from flash:: //| @@ -92,6 +92,12 @@ STATIC mp_obj_t audioio_wavefile_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_deinit_obj, audioio_wavefile_deinit); +STATIC void check_for_deinit(audioio_wavefile_obj_t *self) { + if (common_hal_audioio_wavefile_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -118,14 +124,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_wavefile___exit___obj, 4, 4, //| STATIC mp_obj_t audioio_wavefile_obj_get_sample_rate(mp_obj_t self_in) { audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_wavefile_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_sample_rate(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_sample_rate_obj, audioio_wavefile_obj_get_sample_rate); STATIC mp_obj_t audioio_wavefile_obj_set_sample_rate(mp_obj_t self_in, mp_obj_t sample_rate) { audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_wavefile_deinited(self)); + check_for_deinit(self); common_hal_audioio_wavefile_set_sample_rate(self, mp_obj_get_int(sample_rate)); return mp_const_none; } @@ -144,7 +150,7 @@ const mp_obj_property_t audioio_wavefile_sample_rate_obj = { //| STATIC mp_obj_t audioio_wavefile_obj_get_bits_per_sample(mp_obj_t self_in) { audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_wavefile_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_bits_per_sample(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_bits_per_sample_obj, audioio_wavefile_obj_get_bits_per_sample); @@ -162,7 +168,7 @@ const mp_obj_property_t audioio_wavefile_bits_per_sample_obj = { //| STATIC mp_obj_t audioio_wavefile_obj_get_channel_count(mp_obj_t self_in) { audioio_wavefile_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_wavefile_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_wavefile_get_channel_count(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_wavefile_get_channel_count_obj, audioio_wavefile_obj_get_channel_count); diff --git a/shared-bindings/audioio/WaveFile.h b/shared-bindings/audiocore/WaveFile.h index 62a4200dc..d2572318b 100644 --- a/shared-bindings/audioio/WaveFile.h +++ b/shared-bindings/audiocore/WaveFile.h @@ -27,10 +27,11 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_WAVEFILE_H -#include "common-hal/audioio/AudioOut.h" -#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" #include "extmod/vfs_fat.h" +#include "shared-module/audiocore/WaveFile.h" + extern const mp_obj_type_t audioio_wavefile_type; void common_hal_audioio_wavefile_construct(audioio_wavefile_obj_t* self, diff --git a/shared-bindings/audiocore/__init__.c b/shared-bindings/audiocore/__init__.c new file mode 100644 index 000000000..c64759d4f --- /dev/null +++ b/shared-bindings/audiocore/__init__.c @@ -0,0 +1,69 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/audiocore/Mixer.h" +#include "shared-bindings/audiocore/RawSample.h" +#include "shared-bindings/audiocore/WaveFile.h" + +//| :mod:`audiocore` --- Support for audio samples and mixer +//| ======================================================== +//| +//| .. module:: audiocore +//| :synopsis: Support for audio samples and mixer +//| :platform: SAMD21 +//| +//| The `audiocore` module contains core classes for audio IO +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Mixer +//| RawSample +//| WaveFile +//| + +STATIC const mp_rom_map_elem_t audiocore_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiocore) }, + { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, + { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, + { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(audiocore_module_globals, audiocore_module_globals_table); + +const mp_obj_module_t audiocore_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&audiocore_module_globals, +}; diff --git a/shared-bindings/bleio/AdvertisementData.h b/shared-bindings/audiocore/__init__.h index 05b5a2c8d..02437cd13 100644 --- a/shared-bindings/bleio/AdvertisementData.h +++ b/shared-bindings/audiocore/__init__.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Artur Pacholec + * 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 @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H #include "py/obj.h" -extern const mp_obj_type_t bleio_advertisementdata_type; +// Nothing now. -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADVERTISEMENTDATA_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOCORE___INIT___H diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c index 9cb98d1f8..79df66f7d 100644 --- a/shared-bindings/audioio/AudioOut.c +++ b/shared-bindings/audioio/AudioOut.c @@ -32,7 +32,7 @@ #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioio/AudioOut.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" @@ -133,6 +133,11 @@ STATIC mp_obj_t audioio_audioout_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_deinit_obj, audioio_audioout_deinit); +STATIC void check_for_deinit(audioio_audioout_obj_t *self) { + if (common_hal_audioio_audioout_deinited(self)) { + raise_deinited_error(); + } +} //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -170,7 +175,7 @@ STATIC mp_obj_t audioio_audioout_obj_play(size_t n_args, const mp_obj_t *pos_arg { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + 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); @@ -187,7 +192,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(audioio_audioout_play_obj, 1, audioio_audioout_obj_pl //| STATIC mp_obj_t audioio_audioout_obj_stop(mp_obj_t self_in) { audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + check_for_deinit(self); common_hal_audioio_audioout_stop(self); return mp_const_none; } @@ -199,7 +204,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_stop_obj, audioio_audioout_obj_stop); //| STATIC mp_obj_t audioio_audioout_obj_get_playing(mp_obj_t self_in) { audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_audioio_audioout_get_playing(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_playing_obj, audioio_audioout_obj_get_playing); @@ -217,7 +222,7 @@ const mp_obj_property_t audioio_audioout_playing_obj = { //| STATIC mp_obj_t audioio_audioout_obj_pause(mp_obj_t self_in) { audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + check_for_deinit(self); if (!common_hal_audioio_audioout_get_playing(self)) { mp_raise_RuntimeError(translate("Not playing")); @@ -233,7 +238,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_pause_obj, audioio_audioout_obj_pause //| STATIC mp_obj_t audioio_audioout_obj_resume(mp_obj_t self_in) { audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + check_for_deinit(self); if (common_hal_audioio_audioout_get_paused(self)) { common_hal_audioio_audioout_resume(self); @@ -249,7 +254,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_resume_obj, audioio_audioout_obj_resu //| STATIC mp_obj_t audioio_audioout_obj_get_paused(mp_obj_t self_in) { audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_audioio_audioout_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_audioio_audioout_get_paused(self)); } MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_paused_obj, audioio_audioout_obj_get_paused); diff --git a/shared-bindings/audioio/AudioOut.h b/shared-bindings/audioio/AudioOut.h index d09a5c9ca..1076ac5cc 100644 --- a/shared-bindings/audioio/AudioOut.h +++ b/shared-bindings/audioio/AudioOut.h @@ -29,7 +29,7 @@ #include "common-hal/audioio/AudioOut.h" #include "common-hal/microcontroller/Pin.h" -#include "shared-bindings/audioio/RawSample.h" +#include "shared-bindings/audiocore/RawSample.h" extern const mp_obj_type_t audioio_audioout_type; diff --git a/shared-bindings/audioio/__init__.c b/shared-bindings/audioio/__init__.c index 4786b6425..3fecf2708 100644 --- a/shared-bindings/audioio/__init__.c +++ b/shared-bindings/audioio/__init__.c @@ -32,9 +32,6 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioio/__init__.h" #include "shared-bindings/audioio/AudioOut.h" -#include "shared-bindings/audioio/Mixer.h" -#include "shared-bindings/audioio/RawSample.h" -#include "shared-bindings/audioio/WaveFile.h" //| :mod:`audioio` --- Support for audio input and output //| ====================================================== @@ -51,22 +48,19 @@ //| :maxdepth: 3 //| //| AudioOut -//| Mixer -//| RawSample -//| WaveFile //| //| 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 audioio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) }, { MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) }, - { MP_ROM_QSTR(MP_QSTR_Mixer), MP_ROM_PTR(&audioio_mixer_type) }, - { MP_ROM_QSTR(MP_QSTR_RawSample), MP_ROM_PTR(&audioio_rawsample_type) }, - { MP_ROM_QSTR(MP_QSTR_WaveFile), MP_ROM_PTR(&audioio_wavefile_type) }, }; STATIC MP_DEFINE_CONST_DICT(audioio_module_globals, audioio_module_globals_table); diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index 374268e3d..0a3b03f51 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -42,7 +42,7 @@ //| :class:`I2C` --- Two wire serial protocol //| ------------------------------------------ //| -//| .. class:: I2C(scl, sda, \*, frequency=400000) +//| .. class:: I2C(scl, sda, *, frequency=400000, timeout) //| //| I2C is a two-wire protocol for communicating between devices. At the //| physical level it consists of 2 wires: SCL and SDA, the clock and data @@ -69,13 +69,12 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj); bitbangio_i2c_obj_t *self = m_new_obj(bitbangio_i2c_obj_t); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); self->base.type = &bitbangio_i2c_type; shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); return (mp_obj_t)self; } -//| .. method:: I2C.deinit() +//| .. method:: deinit() //| //| Releases control of the underlying hardware so other classes can use it. //| @@ -86,13 +85,19 @@ STATIC mp_obj_t bitbangio_i2c_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_deinit_obj, bitbangio_i2c_obj_deinit); -//| .. method:: I2C.__enter__() +STATIC void check_for_deinit(bitbangio_i2c_obj_t *self) { + if (shared_module_bitbangio_i2c_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() //| //| No-op used in Context Managers. //| // Provided by context manager helper. -//| .. method:: I2C.__exit__() +//| .. method:: __exit__() //| //| Automatically deinitializes the hardware on context exit. See //| :ref:`lifetime-and-contextmanagers` for more info. @@ -110,7 +115,7 @@ static void check_lock(bitbangio_i2c_obj_t *self) { } } -//| .. method:: I2C.scan() +//| .. method:: scan() //| //| Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of //| those that respond. A device responds if it pulls the SDA line low after @@ -118,7 +123,7 @@ static void check_lock(bitbangio_i2c_obj_t *self) { //| STATIC mp_obj_t bitbangio_i2c_scan(mp_obj_t self_in) { bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); + check_for_deinit(self); check_lock(self); mp_obj_t list = mp_obj_new_list(0, NULL); // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved @@ -132,30 +137,30 @@ STATIC mp_obj_t bitbangio_i2c_scan(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_scan_obj, bitbangio_i2c_scan); -//| .. method:: I2C.try_lock() +//| .. method:: try_lock() //| //| Attempts to grab the I2C lock. Returns True on success. //| STATIC mp_obj_t bitbangio_i2c_obj_try_lock(mp_obj_t self_in) { bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(shared_module_bitbangio_i2c_try_lock(self)); } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_try_lock_obj, bitbangio_i2c_obj_try_lock); -//| .. method:: I2C.unlock() +//| .. method:: unlock() //| //| Releases the I2C lock. //| STATIC mp_obj_t bitbangio_i2c_obj_unlock(mp_obj_t self_in) { bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); + check_for_deinit(self); shared_module_bitbangio_i2c_unlock(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock); -//| .. method:: I2C.readfrom_into(address, buffer, \*, start=0, end=len(buffer)) +//| .. method:: readfrom_into(address, buffer, *, start=0, end=None) //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. @@ -179,7 +184,7 @@ STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_a { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); + 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); check_lock(self); @@ -203,7 +208,7 @@ STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_a } MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 3, bitbangio_i2c_readfrom_into); -//| .. method:: I2C.writeto(address, buffer, \*, start=0, end=len(buffer), stop=True) +//| .. method:: writeto(address, buffer, *, start=0, end=None, stop=True) //| //| Write the bytes from ``buffer`` to the slave specified by ``address``. //| Transmits a stop bit if ``stop`` is set. @@ -232,7 +237,7 @@ STATIC mp_obj_t bitbangio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, m { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(shared_module_bitbangio_i2c_deinited(self)); + check_for_deinit(self); check_lock(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); diff --git a/shared-bindings/bitbangio/OneWire.c b/shared-bindings/bitbangio/OneWire.c index a3c53d2a5..73bedcd8d 100644 --- a/shared-bindings/bitbangio/OneWire.c +++ b/shared-bindings/bitbangio/OneWire.c @@ -91,6 +91,12 @@ STATIC mp_obj_t bitbangio_onewire_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_onewire_deinit_obj, bitbangio_onewire_deinit); +STATIC void check_for_deinit(bitbangio_onewire_obj_t *self) { + if (shared_module_bitbangio_onewire_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -115,7 +121,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_onewire___exit___obj, 4, 4, //| STATIC mp_obj_t bitbangio_onewire_obj_reset(mp_obj_t self_in) { bitbangio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_onewire_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(shared_module_bitbangio_onewire_reset(self)); } @@ -130,7 +136,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_onewire_reset_obj, bitbangio_onewire_obj_res //| STATIC mp_obj_t bitbangio_onewire_obj_read_bit(mp_obj_t self_in) { bitbangio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_onewire_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(shared_module_bitbangio_onewire_read_bit(self)); } @@ -142,7 +148,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_onewire_read_bit_obj, bitbangio_onewire_obj_ //| STATIC mp_obj_t bitbangio_onewire_obj_write_bit(mp_obj_t self_in, mp_obj_t bool_obj) { bitbangio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_onewire_deinited(self)); + check_for_deinit(self); shared_module_bitbangio_onewire_write_bit(self, mp_obj_is_true(bool_obj)); return mp_const_none; diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index 974ec99e2..88bd3d6cb 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -84,7 +84,7 @@ STATIC mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args, return (mp_obj_t)self; } -//| .. method:: SPI.deinit() +//| .. method:: deinit() //| //| Turn off the SPI bus. //| @@ -95,13 +95,19 @@ STATIC mp_obj_t bitbangio_spi_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_deinit_obj, bitbangio_spi_obj_deinit); -//| .. method:: SPI.__enter__() +STATIC void check_for_deinit(bitbangio_spi_obj_t *self) { + if (shared_module_bitbangio_spi_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() //| //| No-op used by Context Managers. //| // Provided by context manager helper. -//| .. method:: SPI.__exit__() +//| .. method:: __exit__() //| //| Automatically deinitializes the hardware when exiting a context. See //| :ref:`lifetime-and-contextmanagers` for more info. @@ -120,7 +126,7 @@ static void check_lock(bitbangio_spi_obj_t *self) { } } -//| .. method:: SPI.configure(\*, baudrate=100000, polarity=0, phase=0, bits=8) +//| .. method:: configure(*, baudrate=100000, polarity=0, phase=0, bits=8) //| //| Configures the SPI bus. Only valid when locked. //| @@ -139,7 +145,7 @@ STATIC mp_obj_t bitbangio_spi_configure(size_t n_args, const mp_obj_t *pos_args, { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, }; bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -162,7 +168,7 @@ STATIC mp_obj_t bitbangio_spi_configure(size_t n_args, const mp_obj_t *pos_args, } MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_configure_obj, 1, bitbangio_spi_configure); -//| .. method:: SPI.try_lock() +//| .. method:: try_lock() //| //| Attempts to grab the SPI lock. Returns True on success. //| @@ -171,24 +177,24 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_configure_obj, 1, bitbangio_spi_configu //| STATIC mp_obj_t bitbangio_spi_obj_try_lock(mp_obj_t self_in) { bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(shared_module_bitbangio_spi_try_lock(self)); } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_try_lock_obj, bitbangio_spi_obj_try_lock); -//| .. method:: SPI.unlock() +//| .. method:: unlock() //| //| Releases the SPI lock. //| STATIC mp_obj_t bitbangio_spi_obj_unlock(mp_obj_t self_in) { bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + check_for_deinit(self); shared_module_bitbangio_spi_unlock(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock); -//| .. method:: SPI.write(buf) +//| .. method:: write(buf) //| //| Write the data contained in ``buf``. Requires the SPI being locked. //| If the buffer is empty, nothing happens. @@ -196,7 +202,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock); // TODO(tannewt): Add support for start and end kwargs. STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + check_for_deinit(self); mp_buffer_info_t src; mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); if (src.len == 0) { @@ -212,7 +218,7 @@ STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write); -//| .. method:: SPI.readinto(buf) +//| .. method:: readinto(buf) //| //| Read into the buffer specified by ``buf`` while writing zeroes. //| Requires the SPI being locked. @@ -221,7 +227,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write); // TODO(tannewt): Add support for start and end kwargs. STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) { bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + check_for_deinit(self); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); if (bufinfo.len == 0) { @@ -236,7 +242,7 @@ STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_spi_readinto_obj, 2, 2, bitbangio_spi_readinto); -//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in)) +//| .. method:: write_readinto(buffer_out, buffer_in, *, out_start=0, out_end=None, in_start=0, in_end=None) //| //| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. //| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]`` @@ -246,9 +252,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_spi_readinto_obj, 2, 2, bitbangio_ //| :param bytearray buffer_out: Write out the data in this buffer //| :param bytearray buffer_in: Read data into this buffer //| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` -//| :param int out_end: End of the slice; this index is not included +//| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` -//| :param int in_end: End of the slice; this index is not included +//| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)`` //| STATIC mp_obj_t bitbangio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; @@ -261,7 +267,7 @@ STATIC mp_obj_t bitbangio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_ { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); + 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); diff --git a/shared-bindings/bleio/Adapter.c b/shared-bindings/bleio/Adapter.c index d9449d3ab..7b8df5103 100644 --- a/shared-bindings/bleio/Adapter.c +++ b/shared-bindings/bleio/Adapter.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/shared-bindings/bleio/Adapter.h b/shared-bindings/bleio/Adapter.h index fe3886e59..de9d1d6db 100644 --- a/shared-bindings/bleio/Adapter.h +++ b/shared-bindings/bleio/Adapter.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/shared-bindings/bleio/Address.c b/shared-bindings/bleio/Address.c index b7c76b7b2..37f01042c 100644 --- a/shared-bindings/bleio/Address.c +++ b/shared-bindings/bleio/Address.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,13 +34,6 @@ #include "shared-bindings/bleio/Address.h" #include "shared-module/bleio/Address.h" -#define ADDRESS_BYTE_LEN 12 - -STATIC uint8_t xdigit_8b_value(byte nibble1, byte nibble2) { - return unichar_xdigit_value(nibble1) | (unichar_xdigit_value(nibble2) << 4); -} - - //| .. currentmodule:: bleio //| //| :class:`Address` -- BLE address @@ -48,31 +42,20 @@ STATIC uint8_t xdigit_8b_value(byte nibble1, byte nibble2) { //| Encapsulates the address of a BLE device. //| -//| .. class:: Address(address) +//| .. class:: Address(address, address_type) //| //| Create a new Address object encapsulating the address value. //| The value itself can be one of: //| -//| - a `str` value in the format of 'XXXXXXXXXXXX' or 'XX:XX:XX:XX:XX:XX' (12 hex digits) -//| - a `bytes` or `bytearray` containing 6 bytes -//| - another Address object -//| -//| :param address: The address to encapsulate -//| - -//| .. attribute:: type -//| -//| The address type. One of: -//| -//| - `bleio.AddressType.PUBLIC` -//| - `bleio.AddressType.RANDOM_STATIC` -//| - `bleio.AddressType.RANDOM_PRIVATE_RESOLVABLE` -//| - `bleio.AddressType.RANDOM_PRIVATE_NON_RESOLVABLE` +//| :param buf address: The address value to encapsulate. A buffer object (bytearray, bytes) of 6 bytes. +//| :param int address_type: one of the integer values: `PUBLIC`, `RANDOM_STATIC`, +//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. //| STATIC mp_obj_t bleio_address_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_address }; + enum { ARG_address, ARG_address_type }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_address_type, MP_ARG_INT, {.u_int = BLEIO_ADDRESS_TYPE_PUBLIC } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -80,83 +63,52 @@ STATIC mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, bleio_address_obj_t *self = m_new_obj(bleio_address_obj_t); self->base.type = &bleio_address_type; - self->type = ADDRESS_PUBLIC; const mp_obj_t address = args[ARG_address].u_obj; + mp_buffer_info_t buf_info; + mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); + if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) { + mp_raise_ValueError_varg(translate("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES); + } - if (MP_OBJ_IS_STR(address)) { - GET_STR_DATA_LEN(address, str, str_len); - - size_t value_index = 0; - int str_index = str_len; - bool error = false; - - // Loop until fewer than two characters left. - while (str_index >= 1 && value_index < sizeof(self->value)) { - if (str[str_index] == ':') { - // Skip colon separators. - str_index--; - continue; - } - - if (!unichar_isxdigit(str[str_index]) || - !unichar_isxdigit(str[str_index-1])) { - error = true; - break; - } - - self->value[value_index] = xdigit_8b_value(str[str_index], - str[str_index-1]); - value_index += 1; - str_index -= 2; - } - // Check for correct number of hex digits and no parsing errors. - if (error || value_index != ADDRESS_BYTE_LEN || str_index != -1) { - mp_raise_ValueError_varg(translate("Address is not %d bytes long or is in wrong format"), - ADDRESS_BYTE_LEN); - } - } else if (MP_OBJ_IS_TYPE(address, &mp_type_bytearray) || MP_OBJ_IS_TYPE(address, &mp_type_bytes)) { - mp_buffer_info_t buf_info; - mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); - if (buf_info.len != BLEIO_ADDRESS_BYTES) { - mp_raise_ValueError_varg(translate("Address must be %d bytes long"), BLEIO_ADDRESS_BYTES); - } - - for (size_t b = 0; b < BLEIO_ADDRESS_BYTES; ++b) { - self->value[BLEIO_ADDRESS_BYTES - b - 1] = ((uint8_t*)buf_info.buf)[b]; - } - } else if (MP_OBJ_IS_TYPE(address, &bleio_address_type)) { - // deep copy - bleio_address_obj_t *other = MP_OBJ_TO_PTR(address); - self->type = other->type; - memcpy(self->value, other->value, BLEIO_ADDRESS_BYTES); + const mp_int_t address_type = args[ARG_address_type].u_int; + if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) { + mp_raise_ValueError(translate("Address type out of range")); } + common_hal_bleio_address_construct(self, buf_info.buf, address_type); + return MP_OBJ_FROM_PTR(self); } -STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +//| .. attribute:: address_bytes +//| +//| The bytes that make up the device address (read-only) +//| +STATIC mp_obj_t bleio_address_get_address_bytes(mp_obj_t self_in) { bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "Address('%02x:%02x:%02x:%02x:%02x:%02x')", - self->value[5], self->value[4], self->value[3], - self->value[2], self->value[1], self->value[0]); + return common_hal_bleio_address_get_address_bytes(self); } +MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_address_bytes_obj, bleio_address_get_address_bytes); + +const mp_obj_property_t bleio_address_address_bytes_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&bleio_address_get_address_bytes_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; +//| .. attribute:: type +//| +//| The address type (read-only). +//| One of the integer values: `PUBLIC`, `RANDOM_STATIC`, +//| `RANDOM_PRIVATE_RESOLVABLE`, or `RANDOM_PRIVATE_NON_RESOLVABLE`. +//| STATIC mp_obj_t bleio_address_get_type(mp_obj_t self_in) { bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (self->type == ADDRESS_PUBLIC) { - return (mp_obj_t)&bleio_addresstype_public_obj; - } else if (self->type == ADDRESS_RANDOM_STATIC) { - return (mp_obj_t)&bleio_addresstype_random_static_obj; - } else if (self->type == ADDRESS_RANDOM_PRIVATE_RESOLVABLE) { - return (mp_obj_t)&bleio_addresstype_random_private_resolvable_obj; - } else if (self->type == ADDRESS_RANDOM_PRIVATE_NON_RESOLVABLE) { - return (mp_obj_t)&bleio_addresstype_random_private_non_resolvable_obj; - } - - return mp_const_none; + return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_address_get_type(self)); } MP_DEFINE_CONST_FUN_OBJ_1(bleio_address_get_type_obj, bleio_address_get_type); @@ -167,8 +119,74 @@ const mp_obj_property_t bleio_address_type_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. method:: __eq__(other) +//| +//| Two Address objects are equal if their addresses and address types are equal. +//| +STATIC mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + // Two Addresses are equal if their address bytes and address_type are equal + case MP_BINARY_OP_EQUAL: + if (MP_OBJ_IS_TYPE(rhs_in, &bleio_address_type)) { + bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); + bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); + return mp_obj_new_bool( + mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs), + common_hal_bleio_address_get_address_bytes(rhs)) && + common_hal_bleio_address_get_type(lhs) == + common_hal_bleio_address_get_type(rhs)); + + } else { + return mp_const_false; + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (kind == PRINT_STR) { + mp_buffer_info_t buf_info; + mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self); + mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); + + const uint8_t *buf = (uint8_t *) buf_info.buf; + mp_printf(print, + "%02x:%02x:%02x:%02x:%02x:%02x", + buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); + } else { + mp_printf(print, "<Address>"); + } +} + +//| .. data:: PUBLIC +//| +//| A publicly known address, with a company ID (high 24 bits)and company-assigned part (low 24 bits). +//| +//| .. data:: RANDOM_STATIC +//| +//| A randomly generated address that does not change often. It may never change or may change after +//| a power cycle. +//| +//| .. data:: RANDOM_PRIVATE_RESOLVABLE +//| +//| An address that is usable when the peer knows the other device's secret Identity Resolving Key (IRK). +//| +//| .. data:: RANDOM_PRIVATE_NON_RESOLVABLE +//| +//| 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) }, + // 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) }, + }; STATIC MP_DEFINE_CONST_DICT(bleio_address_locals_dict, bleio_address_locals_dict_table); @@ -176,7 +194,8 @@ STATIC MP_DEFINE_CONST_DICT(bleio_address_locals_dict, bleio_address_locals_dict const mp_obj_type_t bleio_address_type = { { &mp_type_type }, .name = MP_QSTR_Address, - .print = bleio_address_print, .make_new = bleio_address_make_new, + .print = bleio_address_print, + .binary_op = bleio_address_binary_op, .locals_dict = (mp_obj_dict_t*)&bleio_address_locals_dict }; diff --git a/shared-bindings/bleio/Address.h b/shared-bindings/bleio/Address.h index 9c9e20968..5e02ee210 100644 --- a/shared-bindings/bleio/Address.h +++ b/shared-bindings/bleio/Address.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -28,7 +29,20 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H #include "py/objtype.h" +#include "shared-module/bleio/Address.h" + +#define BLEIO_ADDRESS_TYPE_PUBLIC (0) +#define BLEIO_ADDRESS_TYPE_RANDOM_STATIC (1) +#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE (2) +#define BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE (3) + +#define BLEIO_ADDRESS_TYPE_MIN BLEIO_ADDRESS_TYPE_PUBLIC +#define BLEIO_ADDRESS_TYPE_MAX BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE extern const mp_obj_type_t bleio_address_type; +extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type); +extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self); +extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESS_H diff --git a/shared-bindings/bleio/AddressType.c b/shared-bindings/bleio/AddressType.c deleted file mode 100644 index cf2151c94..000000000 --- a/shared-bindings/bleio/AddressType.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Artur Pacholec - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-bindings/bleio/AddressType.h" - -//| .. currentmodule:: bleio -//| -//| :class:`AddressType` -- defines the type of a BLE address -//| ============================================================= -//| -//| .. class:: bleio.AddressType -//| -//| Enum-like class to define the type of a BLE address, see also `bleio.Address`. -//| -//| .. data:: PUBLIC -//| -//| The address is public -//| -//| .. data:: RANDOM_STATIC -//| -//| The address is random static -//| -//| .. data:: RANDOM_PRIVATE_RESOLVABLE -//| -//| The address is random private resolvable -//| -//| .. data:: RANDOM_PRIVATE_NON_RESOLVABLE -//| -//| The address is private non-resolvable -//| -const mp_obj_type_t bleio_addresstype_type; - -const bleio_addresstype_obj_t bleio_addresstype_public_obj = { - { &bleio_addresstype_type }, -}; - -const bleio_addresstype_obj_t bleio_addresstype_random_static_obj = { - { &bleio_addresstype_type }, -}; - -const bleio_addresstype_obj_t bleio_addresstype_random_private_resolvable_obj = { - { &bleio_addresstype_type }, -}; - -const bleio_addresstype_obj_t bleio_addresstype_random_private_non_resolvable_obj = { - { &bleio_addresstype_type }, -}; - -STATIC const mp_rom_map_elem_t bleio_addresstype_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_PUBLIC), MP_ROM_PTR(&bleio_addresstype_public_obj) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_STATIC), MP_ROM_PTR(&bleio_addresstype_random_static_obj) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_RESOLVABLE), MP_ROM_PTR(&bleio_addresstype_random_private_resolvable_obj) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE), MP_ROM_PTR(&bleio_addresstype_random_private_non_resolvable_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(bleio_addresstype_locals_dict, bleio_addresstype_locals_dict_table); - -STATIC void bleio_addresstype_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - qstr type = MP_QSTR_PUBLIC; - - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&bleio_addresstype_random_static_obj)) { - type = MP_QSTR_RANDOM_STATIC; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&bleio_addresstype_random_private_resolvable_obj)) { - type = MP_QSTR_RANDOM_PRIVATE_RESOLVABLE; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&bleio_addresstype_random_private_non_resolvable_obj)) { - type = MP_QSTR_RANDOM_PRIVATE_NON_RESOLVABLE; - } - - mp_printf(print, "%q.%q.%q", MP_QSTR_bleio, MP_QSTR_AddressType, type); -} - -const mp_obj_type_t bleio_addresstype_type = { - { &mp_type_type }, - .name = MP_QSTR_AddressType, - .print = bleio_addresstype_print, - .locals_dict = (mp_obj_t)&bleio_addresstype_locals_dict, -}; diff --git a/shared-bindings/bleio/AdvertisementData.c b/shared-bindings/bleio/AdvertisementData.c deleted file mode 100644 index 9cfdd74e9..000000000 --- a/shared-bindings/bleio/AdvertisementData.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Artur Pacholec - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/obj.h" -#include "shared-module/bleio/AdvertisementData.h" - -//| .. currentmodule:: bleio -//| -//| :class:`AdvertisementData` -- data used during BLE advertising -//| ============================================================== -//| -//| Represents the data to be broadcast during BLE advertising. -//| - -STATIC const mp_rom_map_elem_t bleio_advertisementdata_locals_dict_table[] = { - // Static variables - { MP_ROM_QSTR(MP_QSTR_FLAGS), MP_ROM_INT(AdFlags) }, - { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_16BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf16BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_16BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf16BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_32BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf32BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_32BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf32BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_INCOMPLETE_LIST_OF_128BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdIncompleteListOf128BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_COMPLETE_LIST_OF_128BIT_SERVICE_CLASS_UUIDS), MP_ROM_INT(AdCompleteListOf128BitServiceClassUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_SHORTENED_LOCAL_NAME), MP_ROM_INT(AdShortenedLocalName) }, - { MP_ROM_QSTR(MP_QSTR_COMPLETE_LOCAL_NAME), MP_ROM_INT(AdCompleteLocalName) }, - { MP_ROM_QSTR(MP_QSTR_TX_POWER_LEVEL), MP_ROM_INT(AdTxPowerLevel) }, - { MP_ROM_QSTR(MP_QSTR_CLASS_OF_DEVICE), MP_ROM_INT(AdClassOfDevice) }, - { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_HASH_C), MP_ROM_INT(AdSimplePairingHashC) }, - { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_RANDOMIZER_R), MP_ROM_INT(AdSimplePairingRandomizerR) }, - { MP_ROM_QSTR(MP_QSTR_SECURITY_MANAGER_TK_VALUE), MP_ROM_INT(AdSecurityManagerTKValue) }, - { MP_ROM_QSTR(MP_QSTR_SECURITY_MANAGER_OOB_FLAGS), MP_ROM_INT(AdSecurityManagerOOBFlags) }, - { MP_ROM_QSTR(MP_QSTR_SLAVE_CONNECTION_INTERVAL_RANGE), MP_ROM_INT(AdSlaveConnectionIntervalRange) }, - { MP_ROM_QSTR(MP_QSTR_LIST_OF_16BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf16BitServiceSolicitationUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_LIST_OF_128BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf128BitServiceSolicitationUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA), MP_ROM_INT(AdServiceData) }, - { MP_ROM_QSTR(MP_QSTR_PUBLIC_TARGET_ADDRESS), MP_ROM_INT(AdPublicTargetAddress) }, - { MP_ROM_QSTR(MP_QSTR_RANDOM_TARGET_ADDRESS), MP_ROM_INT(AdRandomTargetAddress) }, - { MP_ROM_QSTR(MP_QSTR_APPEARANCE), MP_ROM_INT(AdAppearance) }, - { MP_ROM_QSTR(MP_QSTR_ADVERTISING_INTERNAL), MP_ROM_INT(AdAdvertisingInterval) }, - { MP_ROM_QSTR(MP_QSTR_LE_BLUETOOTH_DEVICE_ADDRESS), MP_ROM_INT(AdLEBluetoothDeviceAddress) }, - { MP_ROM_QSTR(MP_QSTR_LE_ROLE), MP_ROM_INT(AdLERole) }, - { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_HASH_C256), MP_ROM_INT(AdSimplePairingHashC256) }, - { MP_ROM_QSTR(MP_QSTR_SIMPLE_PAIRING_RANDOMIZER_R256), MP_ROM_INT(AdSimplePairingRandomizerR256) }, - { MP_ROM_QSTR(MP_QSTR_LIST_OF_32BIT_SERVICE_SOLICITATION_UUIDS), MP_ROM_INT(AdListOf32BitServiceSolicitationUUIDs) }, - { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA_32BIT_UUID), MP_ROM_INT(AdServiceData32BitUUID) }, - { MP_ROM_QSTR(MP_QSTR_SERVICE_DATA_128BIT_UUID), MP_ROM_INT(AdServiceData128BitUUID) }, - { MP_ROM_QSTR(MP_QSTR_LE_SECURE_CONNECTIONS_CONFIRMATION_VALUE), MP_ROM_INT(AdLESecureConnectionsConfirmationValue) }, - { MP_ROM_QSTR(MP_QSTR_LE_SECURE_CONNECTIONS_RANDOM_VALUE), MP_ROM_INT(AdLESecureConnectionsRandomValue) }, - { MP_ROM_QSTR(MP_QSTR_URI), MP_ROM_INT(AdURI) }, - { MP_ROM_QSTR(MP_QSTR_INDOOR_POSITIONING), MP_ROM_INT(AdIndoorPositioning) }, - { MP_ROM_QSTR(MP_QSTR_TRANSPORT_DISCOVERY_DATA), MP_ROM_INT(AdTransportDiscoveryData) }, - { MP_ROM_QSTR(MP_QSTR_LE_SUPPORTED_FEATURES), MP_ROM_INT(AdLESupportedFeatures) }, - { MP_ROM_QSTR(MP_QSTR_CHANNEL_MAP_UPDATE_INDICATION), MP_ROM_INT(AdChannelMapUpdateIndication) }, - { MP_ROM_QSTR(MP_QSTR_PB_ADV), MP_ROM_INT(AdPBADV) }, - { MP_ROM_QSTR(MP_QSTR_MESH_MESSAGE), MP_ROM_INT(AdMeshMessage) }, - { MP_ROM_QSTR(MP_QSTR_MESH_BEACON), MP_ROM_INT(AdMeshBeacon) }, - { MP_ROM_QSTR(MP_QSTR_3D_INFORMATION_DATA), MP_ROM_INT(Ad3DInformationData) }, - { MP_ROM_QSTR(MP_QSTR_MANUFACTURER_SPECIFIC_DATA), MP_ROM_INT(AdManufacturerSpecificData) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_advertisementdata_locals_dict, bleio_advertisementdata_locals_dict_table); - -const mp_obj_type_t bleio_advertisementdata_type = { - { &mp_type_type }, - .name = MP_QSTR_AdvertisementData, - .locals_dict = (mp_obj_dict_t*)&bleio_advertisementdata_locals_dict -}; diff --git a/shared-bindings/bleio/Broadcaster.c b/shared-bindings/bleio/Broadcaster.c deleted file mode 100644 index 209e66490..000000000 --- a/shared-bindings/bleio/Broadcaster.c +++ /dev/null @@ -1,132 +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. - */ - -#include "ble_drv.h" -#include "py/runtime.h" - -#include "shared-bindings/bleio/Broadcaster.h" - -//| .. currentmodule:: bleio -//| -//| :class:`Broadcaster` -- Broadcast advertising packets. -//| ========================================================= -//| -//| Implement a BLE broadcaster which sends data in advertising packets and does not connect. -//| Used for beacons and other one-way data transmission. -//| -//| Usage:: -//| -//| import bleio -//| import time -//| -//| # Broadcast once a second. -//| broadcaster = bleio.Broadcaster(interval=1) -//| data = 0 -//| # Broadcast a byte of data that's incremented once a minute -//| while True: -//| # data is an entire advertising data packet, starting with flags. -//| broadcaster.start_advertising(data) -//| time.sleep(60) -//| data += 1 -//| -//| .. class:: Broadcaster(interval=1) -//| -//| Create a new Broadcaster object. - -//| :param float interval: how often to broadcast -//| - -STATIC mp_obj_t bleio_broadcaster_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_interval }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_interval, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, - }; - - 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_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj); - - bleio_broadcaster_obj_t *self = m_new_obj(bleio_broadcaster_obj_t); - self->base.type = &bleio_broadcaster_type; - // Do port-specific initialization. interval will be validated. - common_hal_bleio_broadcaster_construct(self, interval); - - return MP_OBJ_FROM_PTR(self); -} - -//| .. method:: start_advertising(data) -//| -//| Start advertising using the given data packet. -//| -//| :param buf data: advertising data packet, starting with advertising data flags (0x01) -//| -STATIC mp_obj_t bleio_broadcaster_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_broadcaster_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - enum { ARG_data }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); - - common_hal_bleio_broadcaster_start_advertising(self, &bufinfo); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_broadcaster_start_advertising_obj, 0, bleio_broadcaster_start_advertising); - -//| .. method:: stop_advertising() -//| -//| Stop sending advertising packets. -STATIC mp_obj_t bleio_broadcaster_stop_advertising(mp_obj_t self_in) { - bleio_broadcaster_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_broadcaster_stop_advertising(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_broadcaster_stop_advertising_obj, bleio_broadcaster_stop_advertising); - -STATIC const mp_rom_map_elem_t bleio_broadcaster_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_broadcaster_start_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_broadcaster_stop_advertising_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_broadcaster_locals_dict, bleio_broadcaster_locals_dict_table); - -const mp_obj_type_t bleio_broadcaster_type = { - { &mp_type_type }, - .name = MP_QSTR_Broadcaster, - .make_new = bleio_broadcaster_make_new, - .locals_dict = (mp_obj_dict_t*)&bleio_broadcaster_locals_dict -}; diff --git a/shared-bindings/bleio/Central.c b/shared-bindings/bleio/Central.c new file mode 100644 index 000000000..fc00bce5c --- /dev/null +++ b/shared-bindings/bleio/Central.c @@ -0,0 +1,199 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <string.h> +#include <stdio.h> + +#include "ble_drv.h" +#include "py/objarray.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/bleio/Adapter.h" +#include "shared-bindings/bleio/Address.h" +#include "shared-bindings/bleio/Characteristic.h" +#include "shared-bindings/bleio/Central.h" +#include "shared-bindings/bleio/Service.h" + +//| .. currentmodule:: bleio +//| +//| :class:`Central` -- A BLE central device +//| ========================================================= +//| +//| Implement a BLE central, which runs locally. Can connect to a given address. +//| +//| Usage:: +//| +//| import bleio +//| +//| scanner = bleio.Scanner() +//| entries = scanner.scan(2.5) +//| +//| my_entry = None +//| for entry in entries: +//| if entry.name is not None and entry.name == 'MyPeripheral': +//| my_entry = entry +//| break +//| +//| central = bleio.Central(my_entry.address) +//| central.connect(10.0) # timeout after 10 seconds +//| + +//| .. class:: Central() +//| +//| Create a new Central object. +//| +STATIC mp_obj_t bleio_central_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 0, 0, false); + + bleio_central_obj_t *self = m_new_obj(bleio_central_obj_t); + self->base.type = &bleio_central_type; + + common_hal_bleio_central_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: connect(address, timeout, *, service_uuids=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. +//| +//| :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]); + + enum { ARG_address, ARG_timeout, ARG_service_uuids_whitelist }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_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)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (!MP_OBJ_IS_TYPE(args[ARG_address].u_obj, &bleio_address_type)) { + mp_raise_ValueError(translate("Expected an Address")); + } + + bleio_address_obj_t *address = MP_OBJ_TO_PTR(args[ARG_address].u_obj); + mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + + // common_hal_bleio_central_connect() will validate that services is an iterable or None. + common_hal_bleio_central_connect(self, address, timeout, args[ARG_service_uuids_whitelist].u_obj); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_central_connect_obj, 3, bleio_central_connect); + + +//| .. method:: disconnect() +//| +//| Disconnects from the remote peripheral. +//| +STATIC mp_obj_t bleio_central_disconnect(mp_obj_t self_in) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_central_disconnect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_disconnect_obj, bleio_central_disconnect); + +//| .. attribute:: connected +//| +//| True if connected to a remove peripheral. +//| +STATIC mp_obj_t bleio_central_get_connected(mp_obj_t self_in) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_bleio_central_get_connected(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_connected_obj, bleio_central_get_connected); + +const mp_obj_property_t bleio_central_connected_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_central_get_connected_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + + +//| .. attribute:: remote_services (read-only) +//| +//| A tuple of services provided by the remote peripheral. +//| If the Central is not connected, an empty tuple will be returned. +//| +STATIC mp_obj_t bleio_central_get_remote_services(mp_obj_t self_in) { + bleio_central_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // Return list as a tuple so user won't be able to change it. + mp_obj_list_t *service_list = common_hal_bleio_central_get_remote_services(self); + return mp_obj_new_tuple(service_list->len, service_list->items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_central_get_remote_services_obj, bleio_central_get_remote_services); + +const mp_obj_property_t bleio_central_remote_services_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_central_get_remote_services_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +STATIC const mp_rom_map_elem_t bleio_central_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_central_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_central_disconnect_obj) }, + + // 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); + +const mp_obj_type_t bleio_central_type = { + { &mp_type_type }, + .name = MP_QSTR_Central, + .make_new = bleio_central_make_new, + .locals_dict = (mp_obj_dict_t*)&bleio_central_locals_dict +}; diff --git a/shared-bindings/bleio/Device.h b/shared-bindings/bleio/Central.h index aebf1d639..0e84037f9 100644 --- a/shared-bindings/bleio/Device.h +++ b/shared-bindings/bleio/Central.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,19 +25,18 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H -#include "shared-module/bleio/AdvertisementData.h" -#include "shared-module/bleio/Device.h" -#include "shared-module/bleio/Service.h" +#include "common-hal/bleio/Central.h" +#include "common-hal/bleio/Service.h" -extern const mp_obj_type_t bleio_device_type; +extern const mp_obj_type_t bleio_central_type; -extern void common_hal_bleio_device_add_service(bleio_device_obj_t *device, bleio_service_obj_t *service); -extern void common_hal_bleio_device_start_advertising(bleio_device_obj_t *device, bool connectable, mp_buffer_info_t *raw_data); -extern void common_hal_bleio_device_stop_advertising(bleio_device_obj_t *device); -extern void common_hal_bleio_device_connect(bleio_device_obj_t *device); -extern void common_hal_bleio_device_disconnect(bleio_device_obj_t *device); +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_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); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_DEVICE_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CENTRAL_H diff --git a/shared-bindings/bleio/Characteristic.c b/shared-bindings/bleio/Characteristic.c index ae83de864..3bf0476ab 100644 --- a/shared-bindings/bleio/Characteristic.c +++ b/shared-bindings/bleio/Characteristic.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -68,15 +69,15 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t 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); - const mp_obj_t uuid = args[ARG_uuid].u_obj; + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid, &bleio_uuid_type)) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { mp_raise_ValueError(translate("Expected a UUID")); } + 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; - self->uuid = MP_OBJ_TO_PTR(uuid); bleio_characteristic_properties_t properties; @@ -87,7 +88,8 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t properties.write = args[ARG_write].u_bool; properties.write_no_response = args[ARG_write_no_response].u_bool; - common_hal_bleio_characteristic_construct(self, uuid, properties); + // 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); } @@ -99,7 +101,7 @@ STATIC mp_obj_t bleio_characteristic_make_new(const mp_obj_type_t *type, size_t 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(self->props.broadcast); + 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); @@ -117,7 +119,7 @@ const mp_obj_property_t bleio_characteristic_broadcast_obj = { 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(self->props.indicate); + 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); @@ -136,7 +138,7 @@ const mp_obj_property_t bleio_characteristic_indicate_obj = { 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(self->props.notify); + 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); @@ -154,7 +156,7 @@ const mp_obj_property_t bleio_characteristic_notify_obj = { STATIC mp_obj_t bleio_characteristic_get_read(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(self->props.read); + 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); @@ -172,7 +174,7 @@ const mp_obj_property_t bleio_characteristic_read_obj = { STATIC mp_obj_t bleio_characteristic_get_write(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(self->props.write); + return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_obj, bleio_characteristic_get_write); @@ -190,7 +192,7 @@ const mp_obj_property_t bleio_characteristic_write_obj = { STATIC mp_obj_t bleio_characteristic_get_write_no_response(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(self->props.write_no_response); + return mp_obj_new_bool(common_hal_bleio_characteristic_get_properties(self).write_no_response); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_write_no_response_obj, bleio_characteristic_get_write_no_response); @@ -204,11 +206,13 @@ const mp_obj_property_t bleio_characteristic_write_no_response_obj = { //| .. attribute:: uuid //| //| The UUID of this characteristic. (read-only) +//| Will be ``None`` if the 128-bit UUID for this characteristic is not known. //| STATIC mp_obj_t bleio_characteristic_get_uuid(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->uuid); + bleio_uuid_obj_t *uuid = common_hal_bleio_characteristic_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_uuid_obj, bleio_characteristic_get_uuid); @@ -228,9 +232,7 @@ const mp_obj_property_t bleio_characteristic_uuid_obj = { STATIC mp_obj_t bleio_characteristic_get_value(mp_obj_t self_in) { bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_bleio_characteristic_get_value(self); - - return self->value_data; + return common_hal_bleio_characteristic_get_value(self); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_value_obj, bleio_characteristic_get_value); @@ -253,22 +255,80 @@ const mp_obj_property_t bleio_characteristic_value_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: descriptors +//| +//| A tuple of `bleio.Descriptor` that describe this characteristic. (read-only) +//| +STATIC mp_obj_t bleio_characteristic_get_descriptors(mp_obj_t self_in) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + // Return list as a tuple so user won't be able to change it. + mp_obj_list_t *char_list = common_hal_bleio_characteristic_get_descriptor_list(self); + return mp_obj_new_tuple(char_list->len, char_list->items); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_get_descriptors_obj, bleio_characteristic_get_descriptors); + +const mp_obj_property_t bleio_characteristic_descriptors_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_characteristic_get_descriptors_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| .. method:: set_cccd(*, notify=False, indicate=False) +//| +//| Set the remote characteristic's CCCD to enable or disable notification and indication. +//| +//| :param bool notify: True if Characteristic should receive notifications of remote writes +//| :param float indicate: True if Characteristic should receive indications of remote writes +//| +STATIC mp_obj_t bleio_characteristic_set_cccd(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + enum { ARG_notify, ARG_indicate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_notify, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_indicate, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_bleio_characteristic_set_cccd(self, args[ARG_notify].u_bool, args[ARG_indicate].u_bool); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_characteristic_set_cccd_obj, 1, bleio_characteristic_set_cccd); + + 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) }, }; - STATIC MP_DEFINE_CONST_DICT(bleio_characteristic_locals_dict, bleio_characteristic_locals_dict_table); +STATIC void bleio_characteristic_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_characteristic_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Characteristic("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, "<Characteristic with Unregistered UUID>"); + } +} + const mp_obj_type_t bleio_characteristic_type = { { &mp_type_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 }; diff --git a/shared-bindings/bleio/Characteristic.h b/shared-bindings/bleio/Characteristic.h index 206cbcd40..d450c42b4 100644 --- a/shared-bindings/bleio/Characteristic.h +++ b/shared-bindings/bleio/Characteristic.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,12 +28,17 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_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); -extern void common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); +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 mp_obj_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self); extern void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo); +extern bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self); +extern bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self); +extern mp_obj_list_t *common_hal_bleio_characteristic_get_descriptor_list(bleio_characteristic_obj_t *self); +extern void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CHARACTERISTIC_H diff --git a/shared-bindings/bleio/CharacteristicBuffer.c b/shared-bindings/bleio/CharacteristicBuffer.c index 66d164954..26f9e012b 100644 --- a/shared-bindings/bleio/CharacteristicBuffer.c +++ b/shared-bindings/bleio/CharacteristicBuffer.c @@ -47,12 +47,15 @@ STATIC void raise_error_if_not_connected(bleio_characteristic_buffer_obj_t *self //| //| Accumulates a Characteristic's incoming values in a FIFO buffer. //| -//| .. class:: CharacteristicBuffer(Characteristic, *, timeout=1, buffer_size=64) +//| .. class:: CharacteristicBuffer(characteristic, *, timeout=1, buffer_size=64) //| -//| Create a new Characteristic object identified by the specified UUID. +//| Monitor the given Characteristic. Each time a new value is written to the Characteristic +//| add the newly-written bytes to a FIFO buffer. //| -//| :param bleio.Characteristic characteristic: The characteristic to monitor -//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters.//| +//| :param bleio.Characteristic characteristic: The Characteristic to monitor. +//| It may be a local Characteristic provided by a Peripheral Service, or a remote Characteristic +//| in a remote Service that a Central has connected to. +//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters. //| :param int buffer_size: Size of ring buffer that stores incoming data coming from client. //| Must be >= 1. //| @@ -85,13 +88,18 @@ STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, bleio_characteristic_buffer_obj_t *self = m_new_obj(bleio_characteristic_buffer_obj_t); self->base.type = &bleio_characteristic_buffer_type; - self->characteristic = MP_OBJ_TO_PTR(characteristic); - common_hal_bleio_characteristic_buffer_construct(self, self->characteristic, timeout, buffer_size); + common_hal_bleio_characteristic_buffer_construct(self, MP_OBJ_TO_PTR(characteristic), timeout, buffer_size); return MP_OBJ_FROM_PTR(self); } +STATIC void check_for_deinit(bleio_characteristic_buffer_obj_t *self) { + if (common_hal_bleio_characteristic_buffer_deinited(self)) { + raise_deinited_error(); + } +} + // These are standard stream methods. Code is in py/stream.c. // //| .. method:: read(nbytes=None) @@ -122,7 +130,7 @@ STATIC mp_obj_t bleio_characteristic_buffer_make_new(const mp_obj_type_t *type, // These three methods are used by the shared stream methods. STATIC mp_uint_t bleio_characteristic_buffer_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_bleio_characteristic_buffer_deinited(self)); + check_for_deinit(self); raise_error_if_not_connected(self); byte *buf = buf_in; @@ -141,10 +149,10 @@ STATIC mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_bleio_characteristic_buffer_deinited(self)); + check_for_deinit(self); raise_error_if_not_connected(self); if (!common_hal_bleio_characteristic_buffer_connected(self)) { - mp_raise_ValueError(translate("Not connected.")); + mp_raise_ValueError(translate("Not connected")); } mp_uint_t ret; if (request == MP_IOCTL_POLL) { @@ -170,7 +178,7 @@ STATIC mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t r //| STATIC mp_obj_t bleio_characteristic_buffer_obj_get_in_waiting(mp_obj_t self_in) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_bleio_characteristic_buffer_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_characteristic_buffer_rx_characters_available(self)); } MP_DEFINE_CONST_FUN_OBJ_1(bleio_characteristic_buffer_get_in_waiting_obj, bleio_characteristic_buffer_obj_get_in_waiting); @@ -188,7 +196,7 @@ const mp_obj_property_t bleio_characteristic_buffer_in_waiting_obj = { //| STATIC mp_obj_t bleio_characteristic_buffer_obj_reset_input_buffer(mp_obj_t self_in) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_bleio_characteristic_buffer_deinited(self)); + check_for_deinit(self); common_hal_bleio_characteristic_buffer_clear_rx_buffer(self); return mp_const_none; } diff --git a/shared-bindings/bleio/CharacteristicBuffer.h b/shared-bindings/bleio/CharacteristicBuffer.h index f25017c19..b45835ff3 100644 --- a/shared-bindings/bleio/CharacteristicBuffer.h +++ b/shared-bindings/bleio/CharacteristicBuffer.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Artur Pacholec + * 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 diff --git a/shared-bindings/bleio/Descriptor.c b/shared-bindings/bleio/Descriptor.c index b32f4f08e..f2e5aa01d 100644 --- a/shared-bindings/bleio/Descriptor.c +++ b/shared-bindings/bleio/Descriptor.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,27 +31,6 @@ #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/UUID.h" -enum { - DescriptorUuidCharacteristicExtendedProperties = 0x2900, - DescriptorUuidCharacteristicUserDescription = 0x2901, - DescriptorUuidClientCharacteristicConfiguration = 0x2902, - DescriptorUuidServerCharacteristicConfiguration = 0x2903, - DescriptorUuidCharacteristicPresentationFormat = 0x2904, - DescriptorUuidCharacteristicAggregateFormat = 0x2905, - DescriptorUuidValidRange = 0x2906, - DescriptorUuidExternalReportReference = 0x2907, - DescriptorUuidReportReference = 0x2908, - DescriptorUuidNumberOfDigitals = 0x2909, - DescriptorUuidValueTriggerSetting = 0x290A, - DescriptorUuidEnvironmentalSensingConfiguration = 0x290B, - DescriptorUuidEnvironmentalSensingMeasurement = 0x290C, - DescriptorUuidEnvironmentalSensingTriggerSetting = 0x290D, - DescriptorUuidTimeTriggerSetting = 0x290E, -}; - -// Work-in-progress: orphaned for now. -//| :orphan: -//| //| .. currentmodule:: bleio //| //| :class:`Descriptor` -- BLE descriptor @@ -113,7 +93,9 @@ const mp_obj_property_t bleio_descriptor_handle_obj = { STATIC mp_obj_t bleio_descriptor_get_uuid(mp_obj_t self_in) { bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_bleio_descriptor_get_uuid(self); + + bleio_uuid_obj_t *uuid = common_hal_bleio_descriptor_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(bleio_descriptor_get_uuid_obj, bleio_descriptor_get_uuid); @@ -130,28 +112,69 @@ STATIC const mp_rom_map_elem_t bleio_descriptor_locals_dict_table[] = { { 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(DescriptorUuidCharacteristicExtendedProperties) }, - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_USER_DESCRIPTION), MP_ROM_INT(DescriptorUuidCharacteristicUserDescription) }, - { MP_ROM_QSTR(MP_QSTR_CLIENT_CHARACTERISTIC_CONFIGURATION), MP_ROM_INT(DescriptorUuidClientCharacteristicConfiguration) }, - { MP_ROM_QSTR(MP_QSTR_SERVER_CHARACTERISTIC_CONFIGURATION), MP_ROM_INT(DescriptorUuidServerCharacteristicConfiguration) }, - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_PRESENTATION_FORMAT), MP_ROM_INT(DescriptorUuidCharacteristicPresentationFormat) }, - { MP_ROM_QSTR(MP_QSTR_CHARACTERISTIC_AGGREGATE_FORMAT), MP_ROM_INT(DescriptorUuidCharacteristicAggregateFormat) }, - { MP_ROM_QSTR(MP_QSTR_VALID_RANGE), MP_ROM_INT(DescriptorUuidValidRange) }, - { MP_ROM_QSTR(MP_QSTR_EXTERNAL_REPORT_REFERENCE), MP_ROM_INT(DescriptorUuidExternalReportReference) }, - { MP_ROM_QSTR(MP_QSTR_REPORT_REFERENCE), MP_ROM_INT(DescriptorUuidReportReference) }, - { MP_ROM_QSTR(MP_QSTR_NUMBER_OF_DIGITALS), MP_ROM_INT(DescriptorUuidNumberOfDigitals) }, - { MP_ROM_QSTR(MP_QSTR_VALUE_TRIGGER_SETTING), MP_ROM_INT(DescriptorUuidValueTriggerSetting) }, - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_CONFIGURATION), MP_ROM_INT(DescriptorUuidEnvironmentalSensingConfiguration) }, - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_MEASUREMENT ), MP_ROM_INT(DescriptorUuidEnvironmentalSensingMeasurement) }, - { MP_ROM_QSTR(MP_QSTR_ENVIRONMENTAL_SENSING_TRIGGER_SETTING), MP_ROM_INT(DescriptorUuidEnvironmentalSensingTriggerSetting) }, - { MP_ROM_QSTR(MP_QSTR_TIME_TRIGGER_SETTING), MP_ROM_INT(DescriptorUuidTimeTriggerSetting) } + { 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); +STATIC void bleio_descriptor_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_descriptor_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Descriptor("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, "<Descriptor with Unregistered UUID>"); + } +} + const mp_obj_type_t bleio_descriptor_type = { { &mp_type_type }, .name = MP_QSTR_Descriptor, .make_new = bleio_descriptor_make_new, + .print = bleio_descriptor_print, .locals_dict = (mp_obj_dict_t*)&bleio_descriptor_locals_dict }; diff --git a/shared-bindings/bleio/Descriptor.h b/shared-bindings/bleio/Descriptor.h index f47378ee1..fd11ea08c 100644 --- a/shared-bindings/bleio/Descriptor.h +++ b/shared-bindings/bleio/Descriptor.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -30,6 +31,24 @@ #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); diff --git a/shared-bindings/bleio/Device.c b/shared-bindings/bleio/Device.c deleted file mode 100644 index 80595ef33..000000000 --- a/shared-bindings/bleio/Device.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Glenn Ruben Bakke - * Copyright (c) 2018 Artur Pacholec - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include <string.h> -#include <stdio.h> - -#include "ble_drv.h" -#include "py/objarray.h" -#include "py/objproperty.h" -#include "py/objstr.h" -#include "py/runtime.h" -#include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/AddressType.h" -#include "shared-bindings/bleio/Characteristic.h" -#include "shared-bindings/bleio/Device.h" -#include "shared-bindings/bleio/Service.h" -#include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/AdvertisementData.h" -#include "shared-module/bleio/Device.h" -#include "shared-module/bleio/ScanEntry.h" - -// Work-in-progress: orphaned for now. -//| :orphan: -//| -//| .. currentmodule:: bleio -//| -//| :class:`Device` -- BLE device -//| ========================================================= -//| -//| **IGNORE ``Device`` and all its documentation. -//| It is being replaced by `Peripheral` and other classes.** -//| -//| Provides access a to BLE device, either in a Peripheral or Central role. -//| When a device is created without any parameter passed to the constructor, -//| it will be set to the Peripheral role. If a address is passed, the device -//| will be a Central. For a Peripheral you can set the `name`, add services -//| via `add_service` and then start and stop advertising via `bleio.Device.start_advertising` -//| and `bleio.Device.stop_advertising`. For the Central, you can `bleio.Device.connect` and `bleio.Device.disconnect` -//| to the device, once a connection is established, the device's services can -//| be accessed using `bleio.Device.services`. -//| -//| Usage:: -//| -//| import bleio -//| -//| # Peripheral -//| periph = bleio.Device() -//| -//| serv = bleio.Service(bleio.UUID(0x180f)) -//| p.add_service(serv) -//| -//| chara = bleio.Characteristic(bleio.UUID(0x2919)) -//| chara.read = True -//| chara.notify = True -//| serv.add_characteristic(chara) -//| -//| periph.start_advertising() -//| -//| # Central -//| scanner = bleio.Scanner() -//| entries = scanner.scan(2500) -//| -//| my_entry = None -//| for entry in entries: -//| if entry.name is not None and entry.name == 'MyDevice': -//| my_entry = entry -//| break -//| -//| central = bleio.Device(my_entry.address) -//| central.connect() -//| - -//| .. class:: Device(address=None, scan_entry=None) -//| -//| Create a new Device object. If the `address` or :py:data:`scan_entry` parameters are not `None`, -//| the role is set to Central, otherwise it's set to Peripheral. -//| -//| :param bleio.Address address: The address of the device to connect to -//| :param bleio.ScanEntry scan_entry: The scan entry returned from `bleio.Scanner` -//| - -//| .. attribute:: name -//| -//| For the Peripheral role, this property can be used to read and write the device's name. -//| For the Central role, this property will equal the name of the remote device, if one was -//| advertised by the device. In the Central role this property is read-only. -//| - -//| .. attribute:: services -//| -//| A `list` of `bleio.Service` that are offered by this device. (read-only) -//| For a Peripheral device, this list will contain services added using `add_service`, -//| for a Central, this list will be empty until a connection is established, at which point -//| it will be filled with the remote device's services. -//| - -//| .. method:: add_service(service) -//| -//| Appends the :py:data:`service` to the list of this devices's services. -//| This method can only be called for Peripheral devices. -//| -//| :param bleio.Service service: the service to append -//| - -//| .. method:: connect() -//| -//| Attempts a connection to the remote device. If the connection is successful, -//| the device's services are available via `services`. -//| This method can only be called for Central devices. -//| - -//| .. method:: disconnect() -//| -//| Disconnects from the remote device. -//| This method can only be called for Central devices. -//| - -//| .. method:: start_advertising(connectable=True) -//| -//| Starts advertising the device. The device's name and -//| services are put into the advertisement packets. -//| If :py:data:`connectable` is `True` then other devices are allowed to conncet to this device. -//| This method can only be called for Peripheral devices. -//| - -//| .. method:: stop_advertising() -//| -//| Disconnects from the remote device. -//| This method can only be called for Peripheral devices. -//| - -// TODO: Add unique MAC address part to name -static const char default_name[] = "CIRCUITPY"; - -STATIC void bleio_device_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_printf(print, "Device(role: %s)", self->is_peripheral ? "Peripheral" : "Central"); -} - -STATIC mp_obj_t bleio_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { - mp_arg_check_num(n_args, n_kw, 0, 1, true); - bleio_device_obj_t *self = m_new_obj(bleio_device_obj_t); - self->base.type = &bleio_device_type; - self->service_list = mp_obj_new_list(0, NULL); - self->notif_handler = mp_const_none; - self->conn_handler = mp_const_none; - self->conn_handle = 0xFFFF; - self->is_peripheral = true; - - mp_map_t kw_args; - mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); - - enum { ARG_address, ARG_scan_entry }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_scan_entry, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, - }; - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mp_obj_t address_obj = args[ARG_address].u_obj; - const mp_obj_t scan_entry_obj = args[ARG_scan_entry].u_obj; - - if (address_obj != mp_const_none) { - bleio_address_obj_t *address = MP_OBJ_TO_PTR(address_obj); - - self->is_peripheral = false; - self->address.type = address->type; - memcpy(self->address.value, address->value, BLEIO_ADDRESS_BYTES); - } else if (scan_entry_obj != mp_const_none) { - bleio_scanentry_obj_t *scan_entry = MP_OBJ_TO_PTR(scan_entry_obj); - - self->is_peripheral = false; - self->address.type = scan_entry->address.type; - memcpy(self->address.value, scan_entry->address.value, BLEIO_ADDRESS_BYTES); - } else { - self->name = mp_obj_new_str(default_name, strlen(default_name)); - common_hal_bleio_adapter_get_address(&self->address); - } - - return MP_OBJ_FROM_PTR(self); -} - -STATIC mp_obj_t bleio_device_add_service(mp_obj_t self_in, mp_obj_t service_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - bleio_service_obj_t *service = MP_OBJ_TO_PTR(service_in); - - if (!self->is_peripheral) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Can't add services in Central mode"))); - } - - service->device = self; - - mp_obj_list_append(self->service_list, service); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_device_add_service_obj, bleio_device_add_service); - -STATIC mp_obj_t bleio_device_connect(mp_obj_t self_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (self->is_peripheral) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Can't connect in Peripheral mode"))); - } - - common_hal_bleio_device_connect(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_connect_obj, bleio_device_connect); - -STATIC mp_obj_t bleio_device_disconnect(mp_obj_t self_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_bleio_device_disconnect(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_disconnect_obj, bleio_device_disconnect); - -STATIC mp_obj_t bleio_device_get_name(mp_obj_t self_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return self->name; -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_get_name_obj, bleio_device_get_name); - -static mp_obj_t bleio_device_set_name(mp_obj_t self_in, mp_obj_t value) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (!self->is_peripheral) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Can't change the name in Central mode"))); - } - - self->name = value; - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_device_set_name_obj, bleio_device_set_name); - -const mp_obj_property_t bleio_device_name_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_device_get_name_obj, - (mp_obj_t)&bleio_device_set_name_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC mp_obj_t bleio_device_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - - if (!self->is_peripheral) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Can't advertise in Central mode"))); - } - - enum { ARG_connectable, ARG_data }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_data, MP_ARG_KW_ONLY | 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); - - mp_buffer_info_t bufinfo = { 0 }; - if (args[ARG_data].u_obj != mp_const_none) { - mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); - } - - const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list); - for (size_t i = 0; i < service_list->len; ++i) { - bleio_service_obj_t *service = service_list->items[i]; - if (service->handle == 0xFFFF) { - common_hal_bleio_device_add_service(self, service); - } - } - - common_hal_bleio_device_start_advertising(self, args[ARG_connectable].u_bool, &bufinfo); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_device_start_advertising_obj, 0, bleio_device_start_advertising); - -STATIC mp_obj_t bleio_device_stop_advertising(mp_obj_t self_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (!self->is_peripheral) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - translate("Can't advertise in Central mode"))); - } - - common_hal_bleio_device_stop_advertising(self); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_stop_advertising_obj, bleio_device_stop_advertising); - -STATIC mp_obj_t bleio_device_get_services(mp_obj_t self_in) { - bleio_device_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return self->service_list; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_device_get_services_obj, bleio_device_get_services); - -const mp_obj_property_t bleio_device_services_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_device_get_services_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC const mp_rom_map_elem_t bleio_device_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_add_service), MP_ROM_PTR(&bleio_device_add_service_obj) }, - { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&bleio_device_connect_obj) }, - { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_device_disconnect_obj) }, - { MP_ROM_QSTR(MP_QSTR_start_advertising), MP_ROM_PTR(&bleio_device_start_advertising_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop_advertising), MP_ROM_PTR(&bleio_device_stop_advertising_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_device_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_services), MP_ROM_PTR(&bleio_device_services_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(bleio_device_locals_dict, bleio_device_locals_dict_table); - -const mp_obj_type_t bleio_device_type = { - { &mp_type_type }, - .name = MP_QSTR_Device, - .print = bleio_device_print, - .make_new = bleio_device_make_new, - .locals_dict = (mp_obj_dict_t*)&bleio_device_locals_dict -}; diff --git a/shared-bindings/bleio/Peripheral.c b/shared-bindings/bleio/Peripheral.c index 340485f35..570896d27 100644 --- a/shared-bindings/bleio/Peripheral.c +++ b/shared-bindings/bleio/Peripheral.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,19 +36,22 @@ #include "py/runtime.h" #include "shared-bindings/bleio/Adapter.h" -#include "shared-bindings/bleio/AddressType.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/Service.h" #include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/AdvertisementData.h" #include "shared-module/bleio/ScanEntry.h" #include "common-hal/bleio/Peripheral.h" -// TODO: Add unique MAC address part to name static const char default_name[] = "CIRCUITPY"; +#define ADV_INTERVAL_DEFAULT (1.0f) +#define ADV_INTERVAL_MIN (0.0020f) +#define ADV_INTERVAL_MIN_STRING "0.0020" +#define ADV_INTERVAL_MAX (10.24f) +#define ADV_INTERVAL_MAX_STRING "10.24" + //| .. currentmodule:: bleio //| //| :class:`Peripheral` -- A BLE peripheral device @@ -59,6 +63,7 @@ static const char default_name[] = "CIRCUITPY"; //| Usage:: //| //| import bleio +//| from adafruit_ble.advertising import ServerAdvertisement //| //| # Create a Characteristic. //| chara = bleio.Characteristic(bleio.UUID(0x2919), read=True, notify=True) @@ -67,26 +72,28 @@ static const char default_name[] = "CIRCUITPY"; //| serv = bleio.Service(bleio.UUID(0x180f), [chara]) //| //| # Create a peripheral and start it up. -//| periph = bleio.Peripheral([service]) -//| periph.start_advertising() +//| periph = bleio.Peripheral([serv]) +//| adv = ServerAdvertisement(periph) +//| periph.start_advertising(adv.advertising_data_bytes, adv.scan_response_bytes) //| //| while not periph.connected: //| # Wait for connection. //| pass //| -//| .. class:: Peripheral(services, *, name='CIRCUITPY') +//| .. class:: Peripheral(services=(), \*, name='CIRCUITPY') //| //| Create a new Peripheral object. - -//| :param iterable services: the Service objects representing services available from this peripheral. -//| :param str name: The name used when advertising this peripheral //| - +//| :param iterable services: the Service objects representing services available from this peripheral, if any. +//| A non-connectable peripheral will have no services. +//| :param str name: The name used when advertising this peripheral. Use ``None`` when a name is not needed, +//| such as when the peripheral is a beacon +//| STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_services, ARG_name }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_services, MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_name, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_services, MP_ARG_OBJ, {.u_obj = mp_const_empty_tuple} }, + { MP_QSTR_name, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -95,32 +102,33 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar // If services is not an iterable, an exception will be thrown. mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[ARG_services].u_obj, &iter_buf); - mp_obj_t service; bleio_peripheral_obj_t *self = m_new_obj(bleio_peripheral_obj_t); self->base.type = &bleio_peripheral_type; - self->service_list = mp_obj_new_list(0, NULL); - self->notif_handler = mp_const_none; + + // 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 service; while ((service = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (!MP_OBJ_IS_TYPE(service, &bleio_service_type)) { - mp_raise_ValueError(translate("services includes an object that is not a Service")); + mp_raise_ValueError(translate("non-Service found in services")); } - bleio_service_obj_t *service_ptr = MP_OBJ_TO_PTR(service); - service_ptr->device = MP_OBJ_FROM_PTR(self); - mp_obj_list_append(self->service_list, service); + mp_obj_list_append(service_list, service); } const mp_obj_t name = args[ARG_name].u_obj; - if (name == mp_const_none) { - self->name = mp_obj_new_str(default_name, strlen(default_name)); + mp_obj_t name_str; + if (name == MP_OBJ_NULL || name == mp_const_none) { + name_str = mp_obj_new_str(default_name, strlen(default_name)); } else if (MP_OBJ_IS_STR(name)) { - self->name = name; + name_str = name; } else { mp_raise_ValueError(translate("name must be a string")); } - // Do port-specific initialization. - common_hal_bleio_peripheral_construct(self); + common_hal_bleio_peripheral_construct(self, service_list, name_str); return MP_OBJ_FROM_PTR(self); } @@ -132,7 +140,6 @@ STATIC mp_obj_t bleio_peripheral_make_new(const mp_obj_type_t *type, size_t n_ar STATIC mp_obj_t bleio_peripheral_get_connected(mp_obj_t self_in) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - // Return list as a tuple so user won't be able to change it. return mp_obj_new_bool(common_hal_bleio_peripheral_get_connected(self)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_connected_obj, bleio_peripheral_get_connected); @@ -151,7 +158,7 @@ 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 = MP_OBJ_TO_PTR(self->service_list); + 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); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_services_obj, bleio_peripheral_get_services); @@ -170,7 +177,7 @@ const mp_obj_property_t bleio_peripheral_services_obj = { STATIC mp_obj_t bleio_peripheral_get_name(mp_obj_t self_in) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - return self->name; + return common_hal_bleio_peripheral_get_name(self); } MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_get_name_obj, bleio_peripheral_get_name); @@ -181,37 +188,55 @@ const mp_obj_property_t bleio_peripheral_name_obj = { (mp_obj_t)&mp_const_none_obj }, }; -//| .. method:: start_advertising(*, connectable=True, data=None) +//| .. method:: start_advertising(data, *, scan_response=None, connectable=True, interval=1) //| //| Starts advertising the peripheral. The peripheral's name and //| services are included in the advertisement packets. //| +//| :param buf data: advertising data packet bytes +//| :param buf scan_response: scan response data packet bytes. ``None`` if no scan response is needed. //| :param bool connectable: If `True` then other devices are allowed to connect to this peripheral. -//| :param buf data: If `None`, advertise the services passed to this Peripheral when it was created. -//| If not `None`, then send the bytes in ``data`` as the advertising packet. +//| :param float interval: advertising interval, in seconds //| STATIC mp_obj_t bleio_peripheral_start_advertising(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - enum { ARG_connectable, ARG_data }; + enum { ARG_data, ARG_scan_response, ARG_connectable, ARG_interval }; static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_scan_response, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_connectable, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_buffer_info_t bufinfo = { 0 }; - if (args[ARG_data].u_obj != mp_const_none) { - mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); + mp_buffer_info_t data_bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ); + + // Pass an empty buffer if scan_response not provided. + mp_buffer_info_t scan_response_bufinfo = { 0 }; + if (args[ARG_scan_response].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_scan_response].u_obj, &scan_response_bufinfo, MP_BUFFER_READ); } - common_hal_bleio_peripheral_start_advertising(self, args[ARG_connectable].u_bool, &bufinfo); + if (args[ARG_interval].u_obj == MP_OBJ_NULL) { + args[ARG_interval].u_obj = mp_obj_new_float(1.0F); + } + + const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); + if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) { + mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), + ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING); + } + + common_hal_bleio_peripheral_start_advertising(self, args[ARG_connectable].u_bool, interval, + &data_bufinfo, &scan_response_bufinfo); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_start_advertising_obj, 0, bleio_peripheral_start_advertising); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_peripheral_start_advertising_obj, 2, bleio_peripheral_start_advertising); //| .. method:: stop_advertising() //| @@ -225,10 +250,26 @@ STATIC mp_obj_t bleio_peripheral_stop_advertising(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_stop_advertising_obj, bleio_peripheral_stop_advertising); +//| .. method:: disconnect() +//| +//| Disconnects from the remote central. +//| Normally the central initiates a disconnection. Use this only +//| if necessary for your application. +//| +STATIC mp_obj_t bleio_peripheral_disconnect(mp_obj_t self_in) { + bleio_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_bleio_peripheral_disconnect(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_peripheral_disconnect_obj, bleio_peripheral_disconnect); + 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) }, // Properties { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_peripheral_connected_obj) }, diff --git a/shared-bindings/bleio/Peripheral.h b/shared-bindings/bleio/Peripheral.h index 02a5c1ef8..846250a5f 100644 --- a/shared-bindings/bleio/Peripheral.h +++ b/shared-bindings/bleio/Peripheral.h @@ -3,8 +3,8 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec - * 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 @@ -32,9 +32,12 @@ extern const mp_obj_type_t bleio_peripheral_type; -extern void common_hal_bleio_peripheral_construct(bleio_peripheral_obj_t *self); +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 bool common_hal_bleio_peripheral_get_connected(bleio_peripheral_obj_t *self); -extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, mp_buffer_info_t *raw_data); +extern mp_obj_t common_hal_bleio_peripheral_get_name(bleio_peripheral_obj_t *self); +extern void common_hal_bleio_peripheral_start_advertising(bleio_peripheral_obj_t *device, bool connectable, float interval, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo); extern void common_hal_bleio_peripheral_stop_advertising(bleio_peripheral_obj_t *device); +extern void common_hal_bleio_peripheral_disconnect(bleio_peripheral_obj_t *device); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_PERIPHERAL_H diff --git a/shared-bindings/bleio/ScanEntry.c b/shared-bindings/bleio/ScanEntry.c index e6b955078..6eb02c716 100644 --- a/shared-bindings/bleio/ScanEntry.c +++ b/shared-bindings/bleio/ScanEntry.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * Copyright (c) 2017 Glenn Ruben Bakke * @@ -27,278 +28,78 @@ #include <string.h> -#include "py/objarray.h" #include "py/objproperty.h" -#include "py/objstr.h" -#include "py/objtuple.h" #include "shared-bindings/bleio/Address.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/UUID.h" -#include "shared-module/bleio/AdvertisementData.h" #include "shared-module/bleio/ScanEntry.h" -// Work-in-progress: orphaned for now. -//| :orphan: -//| //| .. currentmodule:: bleio //| //| :class:`ScanEntry` -- BLE scan response entry //| ========================================================= //| //| Encapsulates information about a device that was received as a -//| response to a BLE scan request. +//| response to a BLE scan request. This object may only be created +//| by a `bleio.Scanner`: it has no user-visible constructor. //| //| .. attribute:: address //| -//| The address of the device. (read-only) -//| This attribute is of type `bleio.Address`. -//| - -//| .. attribute:: manufacturer_specific_data -//| -//| The manufacturer-specific data present in the advertisement packet. (read-only) -//| - -//| .. attribute:: name -//| -//| The name of the device. (read-only) -//| This attribute might be `None` if the data was missing from the advertisement packet. -//| - -//| .. attribute:: raw_data -//| -//| All the advertisement data present in the packet. (read-only) +//| The address of the device (read-only), of type `bleio.Address`. //| - -//| .. attribute:: rssi -//| -//| The signal strength of the device at the time of the scan. (read-only) -//| - -//| .. attribute:: service_uuids -//| -//| The address of the device. (read-only) -//| This attribute is a list of `bleio.UUID`. -//| This attribute might be empty or incomplete, depending on the advertisement packet. -//| Currently only 16-bit UUIDS are listed. -//| - -//| .. attribute:: tx_power_level -//| -//| The transmit power level of the device. (read-only) -//| This attribute might be `None` if the data was missing from the advertisement packet. -//| -static uint8_t find_data_item(mp_obj_array_t *data_in, uint8_t type, uint8_t **data_out) { - uint16_t i = 0; - while (i < data_in->len) { - const uint8_t item_len = ((uint8_t*)data_in->items)[i]; - const uint8_t item_type = ((uint8_t*)data_in->items)[i + 1]; - if (item_type != type) { - i += (item_len + 1); - continue; - } - - *data_out = &((uint8_t*)data_in->items)[i + 2]; - - return item_len; - } - - return 0; -} - -STATIC mp_obj_t scanentry_get_name(mp_obj_t self_in); - -STATIC void bleio_scanentry_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_scanentry_obj_t *self = (bleio_scanentry_obj_t *)self_in; - mp_printf(print, "ScanEntry(address: %02x:%02x:%02x:%02x:%02x:%02x", - self->address.value[5], self->address.value[4], self->address.value[3], - self->address.value[1], self->address.value[1], self->address.value[0]); - - const mp_obj_t name_obj = scanentry_get_name(self_in); - if (name_obj != mp_const_none) { - mp_obj_str_t *str = MP_OBJ_TO_PTR(name_obj); - mp_printf(print, " name: %s", str->data); - } - - mp_print_str(print, ")"); -} - STATIC mp_obj_t bleio_scanentry_get_address(mp_obj_t self_in) { bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_obj_t obj = bleio_address_type.make_new(&bleio_address_type, 1, 0, (mp_obj_t)&mp_const_none_obj); - bleio_address_obj_t *address = MP_OBJ_TO_PTR(obj); - - address->type = self->address.type; - memcpy(address->value, self->address.value, BLEIO_ADDRESS_BYTES); - - return obj; + return common_hal_bleio_scanentry_get_address(self); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_address_obj, bleio_scanentry_get_address); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_address_obj, bleio_scanentry_get_address); const mp_obj_property_t bleio_scanentry_address_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bluepy_scanentry_get_address_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC mp_obj_t scanentry_get_manufacturer_specific_data(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); - uint8_t *manuf_data; - - const uint8_t manuf_data_len = find_data_item(data, AdManufacturerSpecificData, &manuf_data); - if (manuf_data_len == 0) { - return mp_const_none; - } - - return mp_obj_new_bytearray_by_ref(manuf_data_len, manuf_data); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_manufacturer_specific_data_obj, scanentry_get_manufacturer_specific_data); - -const mp_obj_property_t bleio_scanentry_manufacturer_specific_data_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&scanentry_get_manufacturer_specific_data_obj, + .proxy = { (mp_obj_t)&bleio_scanentry_get_address_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; -STATIC mp_obj_t scanentry_get_name(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); - uint8_t *name; - - // Try for Complete but settle for Shortened - uint8_t name_len = find_data_item(data, AdCompleteLocalName, &name); - if (name_len == 0) { - name_len = find_data_item(data, AdShortenedLocalName, &name); - } - - if (name_len == 0) { - return mp_const_none; - } - - return mp_obj_new_str((const char*)name, name_len - 1); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_name_obj, scanentry_get_name); - -const mp_obj_property_t bleio_scanentry_name_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bluepy_scanentry_get_name_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC mp_obj_t scanentry_get_raw_data(mp_obj_t self_in) { +//| .. attribute:: advertisement_bytes +//| +//| All the advertisement data present in the packet, returned as a ``bytes`` object. (read-only) +//| +STATIC mp_obj_t scanentry_get_advertisement_bytes(mp_obj_t self_in) { bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_obj_t entries = mp_obj_new_list(0, NULL); - - mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); - - uint16_t i = 0; - while (i < data->len) { - mp_obj_tuple_t *entry = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - - const uint8_t item_len = ((uint8_t*)data->items)[i]; - const uint8_t item_type = ((uint8_t*)data->items)[i + 1]; - - entry->items[0] = MP_OBJ_NEW_SMALL_INT(item_type); - entry->items[1] = mp_obj_new_bytearray(item_len - 1, &((uint8_t*)data->items)[i + 2]); - mp_obj_list_append(entries, MP_OBJ_FROM_PTR(entry)); - - i += (item_len + 1); - } - - return entries; + return common_hal_bleio_scanentry_get_advertisement_bytes(self); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_raw_data_obj, scanentry_get_raw_data); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_advertisement_bytes_obj, scanentry_get_advertisement_bytes); -const mp_obj_property_t bleio_scanentry_raw_data_obj = { +const mp_obj_property_t bleio_scanentry_advertisement_bytes_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanentry_get_raw_data_obj, + .proxy = { (mp_obj_t)&bleio_scanentry_get_advertisement_bytes_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: rssi +//| +//| The signal strength of the device at the time of the scan, in integer dBm. (read-only) +//| STATIC mp_obj_t scanentry_get_rssi(mp_obj_t self_in) { bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_int(self->rssi); + return mp_obj_new_int(common_hal_bleio_scanentry_get_rssi(self)); } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluepy_scanentry_get_rssi_obj, scanentry_get_rssi); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanentry_get_rssi_obj, scanentry_get_rssi); const mp_obj_property_t bleio_scanentry_rssi_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bluepy_scanentry_get_rssi_obj, + .proxy = { (mp_obj_t)&bleio_scanentry_get_rssi_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; -STATIC mp_obj_t scanentry_get_service_uuids(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); - uint8_t *uuids; - - // Try for Complete but settle for Incomplete - uint8_t uuids_len = find_data_item(data, AdCompleteListOf16BitServiceClassUUIDs, &uuids); - if (uuids_len == 0) { - uuids_len = find_data_item(data, AdIncompleteListOf16BitServiceClassUUIDs, &uuids); - } - - mp_obj_t entries = mp_obj_new_list(0, NULL); - for (size_t i = 0; i < uuids_len / sizeof(uint16_t); ++i) { - const mp_obj_t uuid_int = mp_obj_new_int(uuids[sizeof(uint16_t) * i] | (uuids[sizeof(uint16_t) * i + 1] << 8)); - const mp_obj_t uuid_obj = bleio_uuid_type.make_new(&bleio_uuid_type, 1, &uuid_int, NULL); - - mp_obj_list_append(entries, uuid_obj); - } - - // TODO: 32-bit UUIDs - // TODO: 128-bit UUIDs - - return entries; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_service_uuids_obj, scanentry_get_service_uuids); - -const mp_obj_property_t bleio_scanentry_service_uuids_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&scanentry_get_service_uuids_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC mp_obj_t scanentry_get_tx_power_level(mp_obj_t self_in) { - bleio_scanentry_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_array_t *data = MP_OBJ_TO_PTR(self->data); - uint8_t *tx_power; - - const uint8_t tx_power_len = find_data_item(data, AdTxPowerLevel, &tx_power); - if (tx_power_len == 0) { - return mp_const_none; - } - - return mp_obj_new_int((int8_t)(*tx_power)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(scanentry_get_tx_power_level_obj, scanentry_get_tx_power_level); - -const mp_obj_property_t bleio_scanentry_tx_power_level_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&scanentry_get_tx_power_level_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj }, -}; STATIC const mp_rom_map_elem_t bleio_scanentry_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_manufacturer_specific_data), MP_ROM_PTR(&bleio_scanentry_manufacturer_specific_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_name), MP_ROM_PTR(&bleio_scanentry_name_obj) }, - { MP_ROM_QSTR(MP_QSTR_raw_data), MP_ROM_PTR(&bleio_scanentry_raw_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) }, - { MP_ROM_QSTR(MP_QSTR_service_uuids), MP_ROM_PTR(&bleio_scanentry_service_uuids_obj) }, - { MP_ROM_QSTR(MP_QSTR_tx_power_level), MP_ROM_PTR(&bleio_scanentry_tx_power_level_obj) }, + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&bleio_scanentry_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_advertisement_bytes), MP_ROM_PTR(&bleio_scanentry_advertisement_bytes_obj) }, + { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&bleio_scanentry_rssi_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_dict_table); @@ -306,6 +107,5 @@ STATIC MP_DEFINE_CONST_DICT(bleio_scanentry_locals_dict, bleio_scanentry_locals_ const mp_obj_type_t bleio_scanentry_type = { { &mp_type_type }, .name = MP_QSTR_ScanEntry, - .print = bleio_scanentry_print, .locals_dict = (mp_obj_dict_t*)&bleio_scanentry_locals_dict }; diff --git a/shared-bindings/bleio/ScanEntry.h b/shared-bindings/bleio/ScanEntry.h index 2b44ba3f4..77e93175f 100644 --- a/shared-bindings/bleio/ScanEntry.h +++ b/shared-bindings/bleio/ScanEntry.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * Copyright (c) 2017 Glenn Ruben Bakke * @@ -29,7 +30,12 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H #include "py/obj.h" +#include "shared-module/bleio/ScanEntry.h" extern const mp_obj_type_t bleio_scanentry_type; +mp_obj_t common_hal_bleio_scanentry_get_address(bleio_scanentry_obj_t *self); +mp_obj_t common_hal_bleio_scanentry_get_advertisement_bytes(bleio_scanentry_obj_t *self); +mp_int_t common_hal_bleio_scanentry_get_rssi(bleio_scanentry_obj_t *self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANENTRY_H diff --git a/shared-bindings/bleio/Scanner.c b/shared-bindings/bleio/Scanner.c index f5424f706..269c42591 100644 --- a/shared-bindings/bleio/Scanner.c +++ b/shared-bindings/bleio/Scanner.c @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,132 +30,93 @@ #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" -#define DEFAULT_INTERVAL 100 -#define DEFAULT_WINDOW 100 +#define INTERVAL_DEFAULT (0.1f) +#define INTERVAL_MIN (0.0025f) +#define INTERVAL_MIN_STRING "0.0025" +#define INTERVAL_MAX (40.959375f) +#define INTERVAL_MAX_STRING "40.959375" +#define WINDOW_DEFAULT (0.1f) -// Work-in-progress: orphaned for now. -//| :orphan: -//| //| .. currentmodule:: bleio //| //| :class:`Scanner` -- scan for nearby BLE devices //| ========================================================= //| -//| Allows scanning for nearby BLE devices. +//| Scan for nearby BLE devices. //| //| Usage:: //| //| import bleio //| scanner = bleio.Scanner() -//| entries = scanner.scan(2500) -//| print(entries) +//| entries = scanner.scan(2.5) # Scan for 2.5 seconds //| //| .. class:: Scanner() //| //| Create a new Scanner object. //| - -//| .. attribute:: interval -//| -//| The interval (in ms) between the start of two consecutive scan windows. -//| Allowed values are between 10ms and 10.24 sec. -//| - -//| .. attribute:: window -//| -//| The duration (in ms) in which a single BLE channel is scanned. -//| Allowed values are between 10ms and 10.24 sec. -//| - -//| .. method:: scan(timeout) -//| -//| Performs a BLE scan. -//| -//| :param int timeout: the scan timeout in ms -//| :returns: advertising packets found -//| :rtype: list of :py:class:`bleio.ScanEntry` -//| -STATIC void bleio_scanner_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - mp_printf(print, "Scanner(interval: %d window: %d)", self->interval, self->window); -} - STATIC mp_obj_t bleio_scanner_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *all_args, mp_map_t *kw_args) { mp_arg_check_num(n_args, kw_args, 0, 0, false); bleio_scanner_obj_t *self = m_new_obj(bleio_scanner_obj_t); self->base.type = type; - self->interval = DEFAULT_INTERVAL; - self->window = DEFAULT_WINDOW; + common_hal_bleio_scanner_construct(self); return MP_OBJ_FROM_PTR(self); } -STATIC mp_obj_t bleio_scanner_get_interval(mp_obj_t self_in) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_int(self->interval); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanner_get_interval_obj, bleio_scanner_get_interval); - -static mp_obj_t bleio_scanner_set_interval(mp_obj_t self_in, mp_obj_t value) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - self->interval = mp_obj_get_int(value); - - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_set_interval_obj, bleio_scanner_set_interval); - -const mp_obj_property_t bleio_scanner_interval_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanner_get_interval_obj, - (mp_obj_t)&bleio_scanner_set_interval_obj, - (mp_obj_t)&mp_const_none_obj }, -}; - -STATIC mp_obj_t scanner_scan(mp_obj_t self_in, mp_obj_t timeout_in) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - const mp_int_t timeout = mp_obj_get_int(timeout_in); - - self->adv_reports = mp_obj_new_list(0, NULL); - - common_hal_bleio_scanner_scan(self, timeout); - - return self->adv_reports; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_scan_obj, scanner_scan); - -STATIC mp_obj_t bleio_scanner_get_window(mp_obj_t self_in) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return mp_obj_new_int(self->window); -} -MP_DEFINE_CONST_FUN_OBJ_1(bleio_scanner_get_window_obj, bleio_scanner_get_window); - -static mp_obj_t bleio_scanner_set_window(mp_obj_t self_in, mp_obj_t value) { - bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(self_in); - - self->window = mp_obj_get_int(value); - - return mp_const_none; +//| .. method:: scan(timeout, \*, interval=0.1, window=0.1) +//| +//| Performs a BLE scan. +//| +//| :param float timeout: the scan timeout in seconds +//| :param float interval: the interval (in seconds) between the start of two consecutive scan windows +//| Must be in the range 0.0025 - 40.959375 seconds. +//| :param float window: the duration (in seconds) to scan a single BLE channel. +//| window must be <= interval. +//| :returns: an iterable of `ScanEntry` objects +//| :rtype: iterable +//| +STATIC mp_obj_t bleio_scanner_scan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_timeout, ARG_interval, ARG_window }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_timeout, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_window, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + }; + + bleio_scanner_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + + if (args[ARG_interval].u_obj == MP_OBJ_NULL) { + args[ARG_interval].u_obj = mp_obj_new_float(INTERVAL_DEFAULT); + } + + if (args[ARG_window].u_obj == MP_OBJ_NULL) { + args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT); + } + + const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); + if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { + mp_raise_ValueError_varg(translate("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING); + } + + const mp_float_t window = mp_obj_float_get(args[ARG_window].u_obj); + if (window > interval) { + mp_raise_ValueError(translate("window must be <= interval")); + } + + return common_hal_bleio_scanner_scan(self, timeout, interval, window); } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_scanner_set_window_obj, bleio_scanner_set_window); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_scanner_scan_obj, 2, bleio_scanner_scan); -const mp_obj_property_t bleio_scanner_window_obj = { - .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&bleio_scanner_get_window_obj, - (mp_obj_t)&bleio_scanner_set_window_obj, - (mp_obj_t)&mp_const_none_obj }, -}; STATIC const mp_rom_map_elem_t bleio_scanner_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_interval), MP_ROM_PTR(&bleio_scanner_interval_obj) }, { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bleio_scanner_scan_obj) }, - { MP_ROM_QSTR(MP_QSTR_window), MP_ROM_PTR(&bleio_scanner_window_obj) }, }; STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict_table); @@ -162,7 +124,6 @@ STATIC MP_DEFINE_CONST_DICT(bleio_scanner_locals_dict, bleio_scanner_locals_dict const mp_obj_type_t bleio_scanner_type = { { &mp_type_type }, .name = MP_QSTR_Scanner, - .print = bleio_scanner_print, .make_new = bleio_scanner_make_new, .locals_dict = (mp_obj_dict_t*)&bleio_scanner_locals_dict }; diff --git a/shared-bindings/bleio/Scanner.h b/shared-bindings/bleio/Scanner.h index 9bd071747..3a0ce7eae 100644 --- a/shared-bindings/bleio/Scanner.h +++ b/shared-bindings/bleio/Scanner.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,11 +29,12 @@ #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H #include "py/objtype.h" -#include "shared-module/bleio/Scanner.h" +#include "common-hal/bleio/Scanner.h" extern const mp_obj_type_t bleio_scanner_type; -extern void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_int_t timeout); +extern void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self); +extern mp_obj_t common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window); extern void common_hal_bleio_scanner_stop(bleio_scanner_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SCANNER_H diff --git a/shared-bindings/bleio/Service.c b/shared-bindings/bleio/Service.c index c3be26260..db0606991 100644 --- a/shared-bindings/bleio/Service.c +++ b/shared-bindings/bleio/Service.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -60,53 +61,53 @@ STATIC mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, 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); - const mp_obj_t uuid = args[ARG_uuid].u_obj; + const mp_obj_t uuid_obj = args[ARG_uuid].u_obj; - if (!MP_OBJ_IS_TYPE(uuid, &bleio_uuid_type)) { + if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) { mp_raise_ValueError(translate("Expected a UUID")); } bleio_service_obj_t *self = m_new_obj(bleio_service_obj_t); - self->char_list = mp_obj_new_list(0, NULL); self->base.type = &bleio_service_type; - self->device = mp_const_none; - self->handle = 0xFFFF; - self->is_secondary = args[ARG_secondary].u_bool; - self->uuid = MP_OBJ_TO_PTR(uuid); + + const bool is_secondary = args[ARG_secondary].u_bool; + bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); // If characteristics is not an iterable, an exception will be thrown. mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(args[ARG_characteristics].u_obj, &iter_buf); - mp_obj_t characteristic; + mp_obj_t characteristic_obj; - while ((characteristic = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (!MP_OBJ_IS_TYPE(characteristic, &bleio_characteristic_type)) { + // Copy the characteristics list and validate its items. + mp_obj_t char_list_obj = mp_obj_new_list(0, NULL); + mp_obj_list_t *char_list = MP_OBJ_TO_PTR(char_list_obj); + + while ((characteristic_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (!MP_OBJ_IS_TYPE(characteristic_obj, &bleio_characteristic_type)) { mp_raise_ValueError(translate("characteristics includes an object that is not a Characteristic")); } - bleio_characteristic_obj_t *characteristic_ptr = MP_OBJ_TO_PTR(characteristic); + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(characteristic_obj); if (common_hal_bleio_uuid_get_uuid128_reference(uuid) != - common_hal_bleio_uuid_get_uuid128_reference(characteristic_ptr->uuid)) { + common_hal_bleio_uuid_get_uuid128_reference(characteristic->uuid)) { // The descriptor base UUID doesn't match the characteristic base UUID. mp_raise_ValueError(translate("Characteristic UUID doesn't match Service UUID")); } - characteristic_ptr->service = self; - mp_obj_list_append(self->char_list, characteristic); + mp_obj_list_append(char_list_obj, characteristic_obj); } - // Do port-specific initialization. - common_hal_bleio_service_construct(self); + common_hal_bleio_service_construct(self, uuid, char_list, is_secondary); return MP_OBJ_FROM_PTR(self); } //| .. attribute:: characteristics //| -//| A `list` of `bleio.Characteristic` that are offered by this service. (read-only) +//| A tuple of `bleio.Characteristic` that are offered by this service. (read-only) //| STATIC mp_obj_t bleio_service_get_characteristics(mp_obj_t self_in) { bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); // Return list as a tuple so user won't be able to change it. - mp_obj_list_t *char_list = MP_OBJ_TO_PTR(self->char_list); + mp_obj_list_t *char_list = common_hal_bleio_service_get_characteristic_list(self); return mp_obj_new_tuple(char_list->len, char_list->items); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_characteristics_obj, bleio_service_get_characteristics); @@ -118,14 +119,34 @@ const mp_obj_property_t bleio_service_characteristics_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| .. attribute:: secondary +//| +//| True if this is a secondary service. (read-only) +//| +STATIC mp_obj_t bleio_service_get_secondary(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_secondary(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_secondary_obj, bleio_service_get_secondary); + +const mp_obj_property_t bleio_service_secondary_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&bleio_service_get_secondary_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + //| .. attribute:: uuid //| //| The UUID of this service. (read-only) +//| Will be ``None`` if the 128-bit UUID for this service is not known. //| STATIC mp_obj_t bleio_service_get_uuid(mp_obj_t self_in) { bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_FROM_PTR(self->uuid); + bleio_uuid_obj_t *uuid = common_hal_bleio_service_get_uuid(self); + return uuid ? MP_OBJ_FROM_PTR(uuid) : mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_service_get_uuid_obj, bleio_service_get_uuid); @@ -138,14 +159,26 @@ const mp_obj_property_t bleio_service_uuid_obj = { STATIC const mp_rom_map_elem_t bleio_service_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_characteristics), MP_ROM_PTR(&bleio_service_characteristics_obj) }, + { MP_ROM_QSTR(MP_QSTR_secondary), MP_ROM_PTR(&bleio_service_secondary_obj) }, { MP_ROM_QSTR(MP_QSTR_uuid), MP_ROM_PTR(&bleio_service_uuid_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(bleio_service_locals_dict, bleio_service_locals_dict_table); +STATIC void bleio_service_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + bleio_service_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->uuid) { + mp_printf(print, "Service("); + bleio_uuid_print(print, MP_OBJ_FROM_PTR(self->uuid), kind); + mp_printf(print, ")"); + } else { + mp_printf(print, "<Service with unregistered UUID>"); + } +} + const mp_obj_type_t bleio_service_type = { { &mp_type_type }, .name = MP_QSTR_Service, .make_new = bleio_service_make_new, + .print = bleio_service_print, .locals_dict = (mp_obj_dict_t*)&bleio_service_locals_dict }; diff --git a/shared-bindings/bleio/Service.h b/shared-bindings/bleio/Service.h index 389db3b2e..f646c81a9 100644 --- a/shared-bindings/bleio/Service.h +++ b/shared-bindings/bleio/Service.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -27,12 +28,14 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H #define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H -#include "shared-module/bleio/Characteristic.h" -#include "shared-module/bleio/Service.h" +#include "common-hal/bleio/Service.h" const mp_obj_type_t bleio_service_type; -extern void common_hal_bleio_service_construct(bleio_service_obj_t *self); +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_secondary(bleio_service_obj_t *self); extern void common_hal_bleio_service_add_all_characteristics(bleio_service_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_SERVICE_H diff --git a/shared-bindings/bleio/UUID.c b/shared-bindings/bleio/UUID.c index c6ad9e626..dca7ea010 100644 --- a/shared-bindings/bleio/UUID.c +++ b/shared-bindings/bleio/UUID.c @@ -3,9 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec - * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * Copyright (c) 2017 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -47,9 +47,14 @@ //| The value can be one of: //| //| - an `int` value in range 0 to 0xFFFF (Bluetooth SIG 16-bit UUID) -//| - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID) +//| - a buffer object (bytearray, bytes) of 16 bytes in little-endian order (128-bit UUID) +//| - a string of hex digits of the form 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' +//| +//| Creating a 128-bit UUID registers the UUID with the onboard BLE software, and provides a +//| temporary 16-bit UUID that can be used in place of the full 128-bit UUID. //| -//| :param int/buffer value: The uuid value to encapsulate +//| :param value: The uuid value to encapsulate +//| :type value: int or typing.ByteString //| STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_arg_check_num(n_args, kw_args, 1, 1, false); @@ -63,7 +68,7 @@ STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, co if (MP_OBJ_IS_INT(value)) { mp_int_t uuid16 = mp_obj_get_int(value); if (uuid16 < 0 || uuid16 > 0xffff) { - mp_raise_ValueError(translate("UUID integer value not in range 0 to 0xffff")); + mp_raise_ValueError(translate("UUID integer value must be 0-0xffff")); } // NULL means no 128-bit value. @@ -124,6 +129,8 @@ STATIC mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, co //| //| The 16-bit part of the UUID. (read-only) //| +//| :type: int +//| STATIC mp_obj_t bleio_uuid_get_uuid16(mp_obj_t self_in) { bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT(common_hal_bleio_uuid_get_uuid16(self)); @@ -140,9 +147,11 @@ const mp_obj_property_t bleio_uuid_uuid16_obj = { //| .. attribute:: uuid128 //| -//| The 128-bit value of the UUID, returned as bytes. +//| The 128-bit value of the UUID //| Raises AttributeError if this is a 16-bit UUID. (read-only) //| +//| :type: bytes +//| STATIC mp_obj_t bleio_uuid_get_uuid128(mp_obj_t self_in) { bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -164,9 +173,10 @@ const mp_obj_property_t bleio_uuid_uuid128_obj = { //| .. attribute:: size //| -//| Returns 128 if this UUID represents a 128-bit vendor-specific UUID. -//| Returns 16 if this UUID represents a 16-bit Bluetooth SIG assigned UUID. (read-only) -//| 32-bit UUIDs are not currently supported. +//| 128 if this UUID represents a 128-bit vendor-specific UUID. 16 if this UUID represents a +//| 16-bit Bluetooth SIG assigned UUID. (read-only) 32-bit UUIDs are not currently supported. +//| +//| :type: int //| STATIC mp_obj_t bleio_uuid_get_size(mp_obj_t self_in) { bleio_uuid_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -213,6 +223,12 @@ STATIC mp_obj_t bleio_uuid_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } } +//| + +//| .. method:: __eq__(other) +//| +//| Two UUID objects are equal if their values match and they are both 128-bit or both 16-bit. +//| STATIC mp_obj_t bleio_uuid_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { switch (op) { // Two UUID's are equal if their uuid16 values and uuid128 references match. diff --git a/shared-bindings/bleio/UUID.h b/shared-bindings/bleio/UUID.h index aef2c1e29..caf039aec 100644 --- a/shared-bindings/bleio/UUID.h +++ b/shared-bindings/bleio/UUID.h @@ -3,6 +3,7 @@ * * The MIT License (MIT) * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec * * Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/shared-bindings/bleio/__init__.c b/shared-bindings/bleio/__init__.c index 7348655ac..ba3bae6c7 100644 --- a/shared-bindings/bleio/__init__.c +++ b/shared-bindings/bleio/__init__.c @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,12 +28,10 @@ #include "shared-bindings/bleio/__init__.h" #include "shared-bindings/bleio/Address.h" -#include "shared-bindings/bleio/AddressType.h" -#include "shared-bindings/bleio/AdvertisementData.h" -#include "shared-bindings/bleio/Broadcaster.h" +#include "shared-bindings/bleio/Central.h" #include "shared-bindings/bleio/Characteristic.h" #include "shared-bindings/bleio/CharacteristicBuffer.h" -#include "shared-bindings/bleio/Descriptor.h" +// #include "shared-bindings/bleio/Descriptor.h" #include "shared-bindings/bleio/Peripheral.h" #include "shared-bindings/bleio/ScanEntry.h" #include "shared-bindings/bleio/Scanner.h" @@ -54,18 +53,14 @@ //| :maxdepth: 3 //| //| Address -//| AddressType -//| AdvertisementData //| Adapter -//| Broadcaster +//| Central //| Characteristic //| CharacteristicBuffer -// Work-in-progress classes are omitted, and marked as :orphan: in their files. -// Descriptor -// Device +//| Descriptor //| Peripheral -// ScanEntry -// Scanner +//| ScanEntry +//| Scanner //| Service //| UUID //| @@ -79,23 +74,18 @@ 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_AdvertisementData), MP_ROM_PTR(&bleio_advertisementdata_type) }, - { MP_ROM_QSTR(MP_QSTR_Broadcaster), MP_ROM_PTR(&bleio_broadcaster_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) }, -// Hide work-in-progress. -// { 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_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) }, - - // Enum-like Classes. - { MP_ROM_QSTR(MP_QSTR_AddressType), MP_ROM_PTR(&bleio_addresstype_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 1f4e0a66f..4aa6dd45b 100644 --- a/shared-bindings/bleio/__init__.h +++ b/shared-bindings/bleio/__init__.h @@ -3,8 +3,9 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Glenn Ruben Bakke + * Copyright (c) 2019 Dan Halbert for Adafruit Industries * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Glenn Ruben Bakke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index 06c2f218f..47e2d64bc 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -25,6 +25,7 @@ */ #include "py/obj.h" +#include "py/runtime.h" #include "shared-bindings/board/__init__.h" @@ -33,10 +34,84 @@ //| //| .. module:: board //| :synopsis: Board specific pin names -//| :platform: SAMD21 //| //| Common container for board base pin names. These will vary from board to //| board so don't expect portability when using this module. +//| +//| .. warning:: The board module varies by board. The APIs documented here may or may not be +//| available on a specific board. + +//| .. function:: I2C() +//| +//| Returns the `busio.I2C` object for the board designated SDA and SCL pins. It is a singleton. +//| + +#if BOARD_I2C +mp_obj_t board_i2c(void) { + mp_obj_t singleton = common_hal_board_get_i2c(); + if (singleton != NULL) { + return singleton; + } + assert_pin_free(DEFAULT_I2C_BUS_SDA); + assert_pin_free(DEFAULT_I2C_BUS_SCL); + return common_hal_board_create_i2c(); +} +#else +mp_obj_t board_i2c(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_I2C); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); + + +//| .. function:: SPI() +//| +//| Returns the `busio.SPI` object for the board designated SCK, MOSI and MISO pins. It is a +//| singleton. +//| +#if BOARD_SPI +mp_obj_t board_spi(void) { + mp_obj_t singleton = common_hal_board_get_spi(); + if (singleton != NULL) { + return singleton; + } + assert_pin_free(DEFAULT_SPI_BUS_SCK); + assert_pin_free(DEFAULT_SPI_BUS_MOSI); + assert_pin_free(DEFAULT_SPI_BUS_MISO); + return common_hal_board_create_spi(); +} +#else +mp_obj_t board_spi(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_spi_obj, board_spi); + +//| .. function:: UART() +//| +//| Returns the `busio.UART` object for the board designated TX and RX pins. It is a singleton. +//| +#if BOARD_UART +mp_obj_t board_uart(void) { + mp_obj_t singleton = common_hal_board_get_uart(); + if (singleton != NULL) { + return singleton; + } + + assert_pin_free(DEFAULT_UART_BUS_RX); + assert_pin_free(DEFAULT_UART_BUS_TX); + + return common_hal_board_create_uart(); +} +#else +mp_obj_t board_uart(void) { + mp_raise_NotImplementedError_varg(translate("No default %q bus"), MP_QSTR_SPI); + return NULL; +} +#endif +MP_DEFINE_CONST_FUN_OBJ_0(board_uart_obj, board_uart); const mp_obj_module_t board_module = { .base = { &mp_type_module }, diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index 2730e5f51..a9b652ba8 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -33,4 +33,16 @@ extern const mp_obj_dict_t board_module_globals; +mp_obj_t common_hal_board_get_i2c(void); +mp_obj_t common_hal_board_create_i2c(void); +MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj); + +mp_obj_t common_hal_board_get_spi(void); +mp_obj_t common_hal_board_create_spi(void); +MP_DECLARE_CONST_FUN_OBJ_0(board_spi_obj); + +mp_obj_t common_hal_board_get_uart(void); +mp_obj_t common_hal_board_create_uart(void); +MP_DECLARE_CONST_FUN_OBJ_0(board_uart_obj); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BOARD___INIT___H diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index e792d2575..0e639f0b5 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -41,7 +41,7 @@ //| :class:`I2C` --- Two wire serial protocol //| ------------------------------------------ //| -//| .. class:: I2C(scl, sda, \*, frequency=400000) +//| .. class:: I2C(scl, sda, *, frequency=400000, timeout=255) //| //| I2C is a two-wire protocol for communicating between devices. At the //| physical level it consists of 2 wires: SCL and SDA, the clock and data @@ -82,7 +82,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, con return (mp_obj_t)self; } -//| .. method:: I2C.deinit() +//| .. method:: deinit() //| //| Releases control of the underlying hardware so other classes can use it. //| @@ -93,13 +93,19 @@ STATIC mp_obj_t busio_i2c_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_deinit_obj, busio_i2c_obj_deinit); -//| .. method:: I2C.__enter__() +STATIC void check_for_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: __enter__() //| //| No-op used in Context Managers. //| // Provided by context manager helper. -//| .. method:: I2C.__exit__() +//| .. method:: __exit__() //| //| Automatically deinitializes the hardware on context exit. See //| :ref:`lifetime-and-contextmanagers` for more info. @@ -114,11 +120,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i static void check_lock(busio_i2c_obj_t *self) { asm(""); if (!common_hal_busio_i2c_has_lock(self)) { - mp_raise_RuntimeError(translate("Function requires lock.")); + mp_raise_RuntimeError(translate("Function requires lock")); } } -//| .. method:: I2C.scan() +//| .. method:: scan() //| //| Scan all I2C addresses between 0x08 and 0x77 inclusive and return a //| list of those that respond. @@ -128,7 +134,7 @@ static void check_lock(busio_i2c_obj_t *self) { //| STATIC mp_obj_t busio_i2c_scan(mp_obj_t self_in) { busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_i2c_deinited(self)); + check_for_deinit(self); check_lock(self); mp_obj_t list = mp_obj_new_list(0, NULL); // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved @@ -142,7 +148,7 @@ STATIC mp_obj_t busio_i2c_scan(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_scan_obj, busio_i2c_scan); -//| .. method:: I2C.try_lock() +//| .. method:: try_lock() //| //| Attempts to grab the I2C lock. Returns True on success. //| @@ -151,24 +157,24 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_scan_obj, busio_i2c_scan); //| STATIC mp_obj_t busio_i2c_obj_try_lock(mp_obj_t self_in) { busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_i2c_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_busio_i2c_try_lock(self)); } MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_try_lock_obj, busio_i2c_obj_try_lock); -//| .. method:: I2C.unlock() +//| .. method:: unlock() //| //| Releases the I2C lock. //| STATIC mp_obj_t busio_i2c_obj_unlock(mp_obj_t self_in) { busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_i2c_deinited(self)); + check_for_deinit(self); common_hal_busio_i2c_unlock(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock); -//| .. method:: I2C.readfrom_into(address, buffer, \*, start=0, end=len(buffer)) +//| .. method:: readfrom_into(address, buffer, *, start=0, end=None) //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. @@ -181,7 +187,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock); //| :param int address: 7-bit device address //| :param bytearray buffer: buffer to write into //| :param int start: Index to start writing at -//| :param int end: Index to write up to but not include +//| :param int end: Index to write up to but not include. Defaults to ``len(buffer)`` //| STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; @@ -192,7 +198,7 @@ STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_i2c_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -216,7 +222,7 @@ STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, } MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_into); -//| .. method:: I2C.writeto(address, buffer, \*, start=0, end=len(buffer), stop=True) +//| .. method:: writeto(address, buffer, *, start=0, end=None, stop=True) //| //| Write the bytes from ``buffer`` to the slave specified by ``address``. //| Transmits a stop bit if ``stop`` is set. @@ -231,7 +237,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_in //| :param int address: 7-bit device address //| :param bytearray buffer: buffer containing the bytes to write //| :param int start: Index to start writing from -//| :param int end: Index to read up to but not include +//| :param int end: Index to read up to but not include. Defaults to ``len(buffer)`` //| :param bool stop: If true, output an I2C stop condition after the //| buffer is written //| @@ -245,7 +251,7 @@ STATIC mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_ma { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_i2c_deinited(self)); + check_for_deinit(self); check_lock(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); diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index 739732e97..a2d5dbf50 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -69,4 +69,7 @@ extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addres extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t * data, size_t len); +// This is used by the supervisor to claim I2C devices indefinitely. +extern void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H diff --git a/shared-bindings/busio/OneWire.c b/shared-bindings/busio/OneWire.c index ceba4f8ee..aca2a3ef2 100644 --- a/shared-bindings/busio/OneWire.c +++ b/shared-bindings/busio/OneWire.c @@ -91,6 +91,12 @@ STATIC mp_obj_t busio_onewire_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_deinit_obj, busio_onewire_deinit); +STATIC void check_for_deinit(busio_onewire_obj_t *self) { + if (common_hal_busio_onewire_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -118,7 +124,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_onewire___exit___obj, 4, 4, bus //| STATIC mp_obj_t busio_onewire_obj_reset(mp_obj_t self_in) { busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_onewire_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_busio_onewire_reset(self)); } @@ -133,7 +139,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_reset_obj, busio_onewire_obj_reset); //| STATIC mp_obj_t busio_onewire_obj_read_bit(mp_obj_t self_in) { busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_onewire_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_busio_onewire_read_bit(self)); } @@ -145,7 +151,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_read_bit_obj, busio_onewire_obj_read_bit //| STATIC mp_obj_t busio_onewire_obj_write_bit(mp_obj_t self_in, mp_obj_t bool_obj) { busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_onewire_deinited(self)); + check_for_deinit(self); common_hal_busio_onewire_write_bit(self, mp_obj_is_true(bool_obj)); return mp_const_none; diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index f690eea18..a7d7d515c 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -95,7 +95,7 @@ STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, con return (mp_obj_t)self; } -//| .. method:: SPI.deinit() +//| .. method:: deinit() //| //| Turn off the SPI bus. //| @@ -106,13 +106,13 @@ STATIC mp_obj_t busio_spi_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit); -//| .. method:: SPI.__enter__() +//| .. method:: __enter__() //| //| No-op used by Context Managers. //| // Provided by context manager helper. -//| .. method:: SPI.__exit__() +//| .. method:: __exit__() //| //| Automatically deinitializes the hardware when exiting a context. See //| :ref:`lifetime-and-contextmanagers` for more info. @@ -124,14 +124,20 @@ STATIC mp_obj_t busio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_spi_obj___exit___obj, 4, 4, busio_spi_obj___exit__); -static void check_lock(busio_spi_obj_t *self) { +STATIC void check_lock(busio_spi_obj_t *self) { asm(""); if (!common_hal_busio_spi_has_lock(self)) { mp_raise_RuntimeError(translate("Function requires lock")); } } -//| .. method:: SPI.configure(\*, baudrate=100000, polarity=0, phase=0, bits=8) +STATIC void check_for_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + raise_deinited_error(); + } +} + +//| .. method:: configure(*, baudrate=100000, polarity=0, phase=0, bits=8) //| //| Configures the SPI bus. The SPI object must be locked. //| @@ -162,7 +168,7 @@ STATIC mp_obj_t busio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, }; busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -188,7 +194,7 @@ STATIC mp_obj_t busio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_ } MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_configure_obj, 1, busio_spi_configure); -//| .. method:: SPI.try_lock() +//| .. method:: try_lock() //| //| Attempts to grab the SPI lock. Returns True on success. //| @@ -197,31 +203,30 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_configure_obj, 1, busio_spi_configure); //| STATIC mp_obj_t busio_spi_obj_try_lock(mp_obj_t self_in) { busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); return mp_obj_new_bool(common_hal_busio_spi_try_lock(self)); } MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_try_lock_obj, busio_spi_obj_try_lock); -//| .. method:: SPI.unlock() +//| .. method:: unlock() //| //| Releases the SPI lock. //| STATIC mp_obj_t busio_spi_obj_unlock(mp_obj_t self_in) { busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); common_hal_busio_spi_unlock(self); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock); -//| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer)) +//| .. method:: write(buffer, *, start=0, end=None) //| //| Write the data contained in ``buffer``. The SPI object must be locked. //| If the buffer is empty, nothing happens. //| //| :param bytearray buffer: Write out the data in this buffer //| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` -//| :param int end: End of the slice; this index is not included +//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` //| STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; @@ -231,7 +236,7 @@ STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_ { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -255,7 +260,7 @@ STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write); -//| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0) +//| .. method:: readinto(buffer, *, start=0, end=None, write_value=0) //| //| Read into ``buffer`` while writing ``write_value`` for each byte read. //| The SPI object must be locked. @@ -263,7 +268,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write); //| //| :param bytearray buffer: Read data into this buffer //| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` -//| :param int end: End of the slice; this index is not included +//| :param int end: End of the slice; this index is not included. Defaults to ``len(buffer)`` //| :param int write_value: Value to write while reading. (Usually ignored.) //| STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -275,7 +280,7 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m { MP_QSTR_write_value,MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, }; busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -298,7 +303,7 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m } MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto); -//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in)) +//| .. method:: write_readinto(buffer_out, buffer_in, *, out_start=0, out_end=None, in_start=0, in_end=None) //| //| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. //| The SPI object must be locked. @@ -309,9 +314,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto); //| :param bytearray buffer_out: Write out the data in this buffer //| :param bytearray buffer_in: Read data into this buffer //| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` -//| :param int out_end: End of the slice; this index is not included +//| :param int out_end: End of the slice; this index is not included. Defaults to ``len(buffer_out)`` //| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` -//| :param int in_end: End of the slice; this index is not included +//| :param int in_end: End of the slice; this index is not included. Defaults to ``len(buffer_in)`` //| STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; @@ -324,7 +329,7 @@ STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); check_lock(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); @@ -367,7 +372,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_read //| STATIC mp_obj_t busio_spi_obj_get_frequency(mp_obj_t self_in) { busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_busio_spi_get_frequency(self)); } MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_get_frequency_obj, busio_spi_obj_get_frequency); diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index 2d12b8b76..b7b0715d1 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -61,6 +61,12 @@ extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_o // Return actual SPI bus frequency. uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self); +// Return SPI bus phase. +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t* self); + +// Return SPI bus polarity. +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t* self); + // This is used by the supervisor to claim SPI devices indefinitely. extern void common_hal_busio_spi_never_reset(busio_spi_obj_t *self); diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index b40f3fa03..c7eef8c43 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -46,7 +46,7 @@ //| ================================================= //| //| -//| .. class:: UART(tx, rx, \*, baudrate=9600, bits=8, parity=None, stop=1, timeout=1, receiver_buffer_size=64) +//| .. class:: UART(tx, rx, *, baudrate=9600, bits=8, parity=None, stop=1, timeout=1, receiver_buffer_size=64) //| //| A common bidirectional serial protocol that uses an an agreed upon speed //| rather than a shared clock line. @@ -57,7 +57,7 @@ //| :param int bits: the number of bits per byte, 7, 8 or 9. //| :param Parity parity: the parity used for error checking. //| :param int stop: the number of stop bits, 1 or 2. -//| :param int timeout: the timeout in seconds to wait for the first character and between subsequent characters. Raises ``ValueError`` if timeout >100 seconds. +//| :param float timeout: the timeout in seconds to wait for the first character and between subsequent characters. Raises ``ValueError`` if timeout >100 seconds. //| :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.) //| //| *New in CircuitPython 4.0:* ``timeout`` has incompatibly changed units from milliseconds to seconds. @@ -137,6 +137,12 @@ STATIC mp_obj_t busio_uart_obj_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_deinit_obj, busio_uart_obj_deinit); +STATIC void check_for_deinit(busio_uart_obj_t *self) { + if (common_hal_busio_uart_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -196,7 +202,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_uart___exit___obj, 4, 4, busio_ // These three methods are used by the shared stream methods. STATIC mp_uint_t busio_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); byte *buf = buf_in; // make sure we want at least 1 char @@ -209,7 +215,7 @@ STATIC mp_uint_t busio_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, STATIC mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); const byte *buf = buf_in; return common_hal_busio_uart_write(self, buf, size, errcode); @@ -217,7 +223,7 @@ STATIC mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_ STATIC mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); mp_uint_t ret; if (request == MP_IOCTL_POLL) { mp_uint_t flags = arg; @@ -241,14 +247,14 @@ STATIC mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t //| STATIC mp_obj_t busio_uart_obj_get_baudrate(mp_obj_t self_in) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_busio_uart_get_baudrate(self)); } MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_baudrate_obj, busio_uart_obj_get_baudrate); STATIC mp_obj_t busio_uart_obj_set_baudrate(mp_obj_t self_in, mp_obj_t baudrate) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); common_hal_busio_uart_set_baudrate(self, mp_obj_get_int(baudrate)); return mp_const_none; } @@ -268,7 +274,7 @@ const mp_obj_property_t busio_uart_baudrate_obj = { //| STATIC mp_obj_t busio_uart_obj_get_in_waiting(mp_obj_t self_in) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_busio_uart_rx_characters_available(self)); } MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_get_in_waiting_obj, busio_uart_obj_get_in_waiting); @@ -286,13 +292,13 @@ const mp_obj_property_t busio_uart_in_waiting_obj = { //| STATIC mp_obj_t busio_uart_obj_reset_input_buffer(mp_obj_t self_in) { busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_busio_uart_deinited(self)); + check_for_deinit(self); common_hal_busio_uart_clear_rx_buffer(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_reset_input_buffer_obj, busio_uart_obj_reset_input_buffer); -//| .. class:: busio.UART.Parity +//| .. class:: busio.UART.Parity() //| //| Enum-like class to define the parity used to verify correct data transfer. //| diff --git a/shared-bindings/busio/UART.h b/shared-bindings/busio/UART.h index e171f8bb4..776a996be 100644 --- a/shared-bindings/busio/UART.h +++ b/shared-bindings/busio/UART.h @@ -42,7 +42,7 @@ typedef enum { extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, const mcu_pin_obj_t * tx, const mcu_pin_obj_t * rx, uint32_t baudrate, uint8_t bits, uart_parity_t parity, uint8_t stop, mp_float_t timeout, - uint8_t receiver_buffer_size); + uint16_t receiver_buffer_size); extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); extern bool common_hal_busio_uart_deinited(busio_uart_obj_t *self); diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c index 958ee062a..ff2933dc6 100644 --- a/shared-bindings/busio/__init__.c +++ b/shared-bindings/busio/__init__.c @@ -35,7 +35,6 @@ #include "shared-bindings/busio/OneWire.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/busio/UART.h" -#include "shared-bindings/busio/__init__.h" #include "py/runtime.h" diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index 2fcbefe11..16472c12c 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -49,8 +49,8 @@ //| ========================================================= //| //| A DigitalInOut is used to digitally control I/O pins. For analog control of -//| a pin, see the :py:class:`~digitalio.AnalogIn` and -//| :py:class:`~digitalio.AnalogOut` classes. +//| a pin, see the :py:class:`analogio.AnalogIn` and +//| :py:class:`analogio.AnalogOut` classes. //| //| .. class:: DigitalInOut(pin) @@ -105,6 +105,12 @@ STATIC mp_obj_t digitalio_digitalinout_obj___exit__(size_t n_args, const mp_obj_ } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(digitalio_digitalinout_obj___exit___obj, 4, 4, digitalio_digitalinout_obj___exit__); +STATIC void check_for_deinit(digitalio_digitalinout_obj_t *self) { + if (common_hal_digitalio_digitalinout_deinited(self)) { + raise_deinited_error(); + } +} + //| //| .. method:: switch_to_output(value=False, drive_mode=digitalio.DriveMode.PUSH_PULL) //| @@ -121,7 +127,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = &digitalio_drive_mode_push_pull_obj} }, }; digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + 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); @@ -158,7 +164,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, }; digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + 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); @@ -191,7 +197,7 @@ extern const digitalio_digitalio_direction_obj_t digitalio_digitalio_direction_o STATIC mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); if (direction == DIRECTION_INPUT) { return (mp_obj_t)&digitalio_direction_input_obj; @@ -202,7 +208,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_direction_obj, digitalio_di STATIC mp_obj_t digitalio_digitalinout_obj_set_direction(mp_obj_t self_in, mp_obj_t value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (value == &digitalio_direction_input_obj) { common_hal_digitalio_digitalinout_switch_to_input(self, PULL_NONE); } else if (value == &digitalio_direction_output_obj) { @@ -227,7 +233,7 @@ const mp_obj_property_t digitalio_digitalio_direction_obj = { //| STATIC mp_obj_t digitalio_digitalinout_obj_get_value(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); bool value = common_hal_digitalio_digitalinout_get_value(self); return mp_obj_new_bool(value); } @@ -235,7 +241,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_value_obj, digitalio_digita STATIC mp_obj_t digitalio_digitalinout_obj_set_value(mp_obj_t self_in, mp_obj_t value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) { mp_raise_AttributeError(translate("Cannot set value when direction is input.")); return mp_const_none; @@ -261,7 +267,7 @@ const mp_obj_property_t digitalio_digitalinout_value_obj = { //| STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) { mp_raise_AttributeError(translate("Drive mode not used when direction is input.")); return mp_const_none; @@ -276,7 +282,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_drive_mode_obj, digitalio_d STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_obj_t drive_mode) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) { mp_raise_AttributeError(translate("Drive mode not used when direction is input.")); return mp_const_none; @@ -309,7 +315,7 @@ const mp_obj_property_t digitalio_digitalio_drive_mode_obj = { //| STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_OUTPUT) { mp_raise_AttributeError(translate("Pull not used when direction is output.")); return mp_const_none; @@ -326,7 +332,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_pull_obj, digitalio_digital STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t pull_obj) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_digitalio_digitalinout_deinited(self)); + check_for_deinit(self); if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_OUTPUT) { mp_raise_AttributeError(translate("Pull not used when direction is output.")); return mp_const_none; @@ -374,3 +380,13 @@ const mp_obj_type_t digitalio_digitalinout_type = { .make_new = digitalio_digitalinout_make_new, .locals_dict = (mp_obj_t)&digitalio_digitalinout_locals_dict, }; + +// Helper for validating digitalio.DigitalInOut arguments +digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj) { + if (!MP_OBJ_IS_TYPE(obj, &digitalio_digitalinout_type)) { + mp_raise_TypeError(translate("argument num/types mismatch")); + } + digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(obj); + check_for_deinit(pin); + return pin; +} diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index 2aaa31b7f..eee0d5801 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -52,5 +52,7 @@ void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode(digitalio_digitalinout_obj_t* self); void common_hal_digitalio_digitalinout_set_pull(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull); digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_never_reset(digitalio_digitalinout_obj_t *self); +digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H diff --git a/shared-bindings/digitalio/Direction.c b/shared-bindings/digitalio/Direction.c index a3433d4b0..c8188fc89 100644 --- a/shared-bindings/digitalio/Direction.c +++ b/shared-bindings/digitalio/Direction.c @@ -43,7 +43,7 @@ //| :class:`Direction` -- defines the direction of a digital pin //| ============================================================= //| -//| .. class:: digitalio.DigitalInOut.Direction +//| .. class:: Direction //| //| Enum-like class to define which direction the digital values are //| going. diff --git a/shared-bindings/digitalio/DriveMode.c b/shared-bindings/digitalio/DriveMode.c index 477cd904c..51e1e2ee5 100644 --- a/shared-bindings/digitalio/DriveMode.c +++ b/shared-bindings/digitalio/DriveMode.c @@ -31,7 +31,7 @@ //| :class:`DriveMode` -- defines the drive mode of a digital pin //| ============================================================= //| -//| .. class:: digitalio.DriveMode +//| .. class:: DriveMode //| //| Enum-like class to define the drive mode used when outputting //| digital values. diff --git a/shared-bindings/digitalio/Pull.c b/shared-bindings/digitalio/Pull.c index 8d03f6c05..813268db7 100644 --- a/shared-bindings/digitalio/Pull.c +++ b/shared-bindings/digitalio/Pull.c @@ -31,7 +31,7 @@ //| :class:`Pull` -- defines the pull of a digital input pin //| ============================================================= //| -//| .. class:: digitalio.Pull +//| .. class:: Pull //| //| Enum-like class to define the pull value, if any, used while reading //| digital values in. diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index 3612b8d63..91c17f2d1 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -58,14 +58,22 @@ STATIC mp_obj_t displayio_bitmap_make_new(const mp_obj_type_t *type, size_t n_ar uint32_t width = mp_obj_get_int(pos_args[0]); uint32_t height = mp_obj_get_int(pos_args[1]); uint32_t value_count = mp_obj_get_int(pos_args[2]); - uint32_t power_of_two = 1; - while (value_count > (1U << power_of_two)) { - power_of_two <<= 1; + uint32_t bits = 1; + + if (value_count == 0) { + mp_raise_ValueError(translate("value_count must be > 0")); + } + while ((value_count - 1) >> bits) { + if (bits < 8) { + bits <<= 1; + } else { + bits += 8; + } } displayio_bitmap_t *self = m_new_obj(displayio_bitmap_t); self->base.type = &displayio_bitmap_type; - common_hal_displayio_bitmap_construct(self, width, height, power_of_two); + common_hal_displayio_bitmap_construct(self, width, height, bits); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 561883810..d9524870d 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -62,6 +62,8 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz //| .. method:: convert(color) //| +//| Converts the given RGB888 color to RGB565 +//| STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); @@ -69,8 +71,10 @@ STATIC mp_obj_t displayio_colorconverter_obj_convert(mp_obj_t self_in, mp_obj_t if (!mp_obj_get_int_maybe(color_obj, &color)) { mp_raise_ValueError(translate("color should be an int")); } - uint16_t output_color; - common_hal_displayio_colorconverter_convert(self, color, &output_color); + _displayio_colorspace_t colorspace; + colorspace.depth = 16; + uint32_t output_color; + common_hal_displayio_colorconverter_convert(self, &colorspace, color, &output_color); return MP_OBJ_NEW_SMALL_INT(output_color); } MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_convert_obj, displayio_colorconverter_obj_convert); diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 71be7f543..24895500e 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -29,9 +29,11 @@ #include "shared-module/displayio/ColorConverter.h" +#include "shared-module/displayio/Palette.h" + extern const mp_obj_type_t displayio_colorconverter_type; void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self); -bool common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, uint32_t input_color, uint16_t* output_color); +void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 1f46330e8..9cb4d6e74 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -31,6 +31,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/binary.h" #include "py/objproperty.h" +#include "py/objtype.h" #include "py/runtime.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/microcontroller/Pin.h" @@ -50,7 +51,7 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the initialization sequence at minimum. //| -//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None) +//| .. class:: Display(display_bus, init_sequence, *, width, height, colstart=0, rowstart=0, rotation=0, color_depth=16, grayscale=False, pixels_in_byte_share_row=True, bytes_per_cell=1, reverse_pixels_in_byte=False, set_column_command=0x2a, set_row_command=0x2b, write_ram_command=0x2c, set_vertical_scroll=0, backlight_pin=None, brightness_command=None, brightness=1.0, auto_brightness=False, single_byte_bounds=False, data_as_commands=False) //| //| Create a Display object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| @@ -77,7 +78,8 @@ //| The initialization sequence should always leave the display memory access inline with the scan //| of the display to minimize tearing artifacts. //| -//| :param displayio.FourWire or displayio.ParallelBus display_bus: The bus that the display is connected to +//| :param display_bus: The bus that the display is connected to +//| :type display_bus: displayio.FourWire or displayio.ParallelBus //| :param buffer init_sequence: Byte-packed initialization sequence. //| :param int width: Width in pixels //| :param int height: Height in pixels @@ -86,14 +88,23 @@ //| :param int rotation: The rotation of the display in degrees clockwise. Must be in 90 degree increments (0, 90, 180, 270) //| :param int color_depth: The number of bits of color per pixel transmitted. (Some displays //| support 18 bit but 16 is easier to transmit. The last bit is extrapolated.) +//| :param bool grayscale: True if the display only shows a single color. +//| :param bool pixels_in_byte_share_row: True when pixels are less than a byte and a byte includes pixels from the same row of the display. When False, pixels share a column. +//| :param int bytes_per_cell: Number of bytes per addressable memory location when color_depth < 8. When greater than one, bytes share a row or column according to pixels_in_byte_share_row. +//| :param bool reverse_pixels_in_byte: Reverses the pixel order within each byte when color_depth < 8. Does not apply across multiple bytes even if there is more than one byte per cell (bytes_per_cell.) //| :param int set_column_command: Command used to set the start and end columns to update //| :param int set_row_command: Command used so set the start and end rows to update -//| :param int write_ram_command: Command used to write pixels values into the update region +//| :param int write_ram_command: Command used to write pixels values into the update region. Ignored if data_as_commands is set. //| :param int set_vertical_scroll: Command used to set the first row to show //| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight +//| :param int brightness_command: Command to set display brightness. Usually available in OLED controllers. +//| :param bool brightness: Initial display brightness. This value is ignored if auto_brightness is True. +//| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. +//| :param bool single_byte_bounds: Display column and row commands use single bytes +//| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. //| STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -103,11 +114,20 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_rowstart, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_rotation, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_color_depth, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_pixels_in_byte_share_row, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_bytes_per_cell, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + { MP_QSTR_reverse_pixels_in_byte, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, + { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, + { MP_QSTR_auto_brightness, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_single_byte_bounds, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_data_as_commands, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; 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); @@ -124,6 +144,9 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a backlight_pin = MP_OBJ_TO_PTR(backlight_pin_obj); assert_pin_free(backlight_pin); } + + mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + mp_int_t rotation = args[ARG_rotation].u_int; if (rotation % 90 != 0) { mp_raise_ValueError(translate("Display rotation must be in 90 degree increments")); @@ -141,33 +164,50 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a mp_raise_RuntimeError(translate("Too many displays")); } self->base.type = &displayio_display_type; - common_hal_displayio_display_construct(self, - display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, - args[ARG_color_depth].u_int, args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, - args[ARG_write_ram_command].u_int, - args[ARG_set_vertical_scroll].u_int, - bufinfo.buf, bufinfo.len, MP_OBJ_TO_PTR(backlight_pin)); + common_hal_displayio_display_construct( + self, + display_bus, args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, + args[ARG_color_depth].u_int, args[ARG_grayscale].u_bool, + args[ARG_pixels_in_byte_share_row].u_bool, args[ARG_bytes_per_cell].u_bool, args[ARG_reverse_pixels_in_byte].u_bool, + args[ARG_set_column_command].u_int, args[ARG_set_row_command].u_int, + args[ARG_write_ram_command].u_int, + args[ARG_set_vertical_scroll].u_int, + bufinfo.buf, bufinfo.len, + MP_OBJ_TO_PTR(backlight_pin), + args[ARG_brightness_command].u_int, + brightness, + args[ARG_auto_brightness].u_bool, + args[ARG_single_byte_bounds].u_bool, + args[ARG_data_as_commands].u_bool + ); return self; } +// Helper to ensure we have the native super class instead of a subclass. +static displayio_display_obj_t* native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_instance_cast_to_native_base(display_obj, &displayio_display_type); + mp_obj_assert_native_inited(native_display); + return MP_OBJ_TO_PTR(native_display); +} + //| .. method:: show(group) //| //| Switches to displaying the given group of layers. When group is None, the default //| CircuitPython terminal will be shown. //| +//| :param Group group: The group to show. STATIC mp_obj_t displayio_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); displayio_group_t* group = NULL; if (group_in != mp_const_none) { - mp_obj_t native_layer = mp_instance_cast_to_native_base(group_in, &displayio_group_type); - if (native_layer == MP_OBJ_NULL) { - mp_raise_ValueError(translate("Must be a Group subclass.")); - } - group = MP_OBJ_TO_PTR(native_layer); + group = MP_OBJ_TO_PTR(native_group(group_in)); } - common_hal_displayio_display_show(self, group); + bool ok = common_hal_displayio_display_show(self, group); + if (!ok) { + mp_raise_ValueError(translate("Group already used")); + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show); @@ -177,7 +217,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| Queues up a display refresh that happens in the background. //| STATIC mp_obj_t displayio_display_obj_refresh_soon(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); common_hal_displayio_display_refresh_soon(self); return mp_const_none; } @@ -189,7 +229,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_refresh_soon_obj, displayio_display_ //| behind the rendered frames. In that case, this will return immediately with the wait count. //| STATIC mp_obj_t displayio_display_obj_wait_for_frame(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_wait_for_frame(self)); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_display_obj_wait_for_frame); @@ -197,11 +237,11 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_wait_for_frame_obj, displayio_displa //| .. attribute:: brightness //| //| The brightness of the display as a float. 0.0 is off and 1.0 is full brightness. When -//| `auto_brightness` is True this value will change automatically and setting it will have no -//| effect. To control the brightness, auto_brightness must be false. +//| `auto_brightness` is True, the value of `brightness` will change automatically. +//| If `brightness` is set, `auto_brightness` will be disabled and will be set to False. //| STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); mp_float_t brightness = common_hal_displayio_display_get_brightness(self); if (brightness < 0) { mp_raise_RuntimeError(translate("Brightness not adjustable")); @@ -210,9 +250,14 @@ STATIC mp_obj_t displayio_display_obj_get_brightness(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_brightness_obj, displayio_display_obj_get_brightness); -STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); - bool ok = common_hal_displayio_display_set_brightness(self, mp_obj_get_float(brightness)); +STATIC mp_obj_t displayio_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { + displayio_display_obj_t *self = native_display(self_in); + common_hal_displayio_display_set_auto_brightness(self, false); + mp_float_t brightness = mp_obj_get_float(brightness_obj); + if (brightness < 0 || brightness > 1.0) { + mp_raise_ValueError(translate("Brightness must be 0-1.0")); + } + bool ok = common_hal_displayio_display_set_brightness(self, brightness); if (!ok) { mp_raise_RuntimeError(translate("Brightness not adjustable")); } @@ -229,16 +274,19 @@ const mp_obj_property_t displayio_display_brightness_obj = { //| .. attribute:: auto_brightness //| -//| True when the display brightness is auto adjusted. +//| True when the display brightness is adjusted automatically, based on an ambient +//| light sensor or other method. Note that some displays may have this set to True by default, +//| but not actually implement automatic brightness adjustment. `auto_brightness` is set to False +//| if `brightness` is set manually. //| STATIC mp_obj_t displayio_display_obj_get_auto_brightness(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); return mp_obj_new_bool(common_hal_displayio_display_get_auto_brightness(self)); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_auto_brightness_obj, displayio_display_obj_get_auto_brightness); STATIC mp_obj_t displayio_display_obj_set_auto_brightness(mp_obj_t self_in, mp_obj_t auto_brightness) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); common_hal_displayio_display_set_auto_brightness(self, mp_obj_is_true(auto_brightness)); @@ -259,7 +307,7 @@ const mp_obj_property_t displayio_display_auto_brightness_obj = { //| //| STATIC mp_obj_t displayio_display_obj_get_width(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_width(self)); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_width_obj, displayio_display_obj_get_width); @@ -277,7 +325,7 @@ const mp_obj_property_t displayio_display_width_obj = { //| //| STATIC mp_obj_t displayio_display_obj_get_height(mp_obj_t self_in) { - displayio_display_obj_t *self = MP_OBJ_TO_PTR(self_in); + displayio_display_obj_t *self = native_display(self_in); return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_display_get_height(self)); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_height_obj, displayio_display_obj_get_height); @@ -289,6 +337,25 @@ const mp_obj_property_t displayio_display_height_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. attribute:: bus +//| +//| The bus being used by the display +//| +//| +STATIC mp_obj_t displayio_display_obj_get_bus(mp_obj_t self_in) { + displayio_display_obj_t *self = native_display(self_in); + return self->bus; +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_display_get_bus_obj, displayio_display_obj_get_bus); + +const mp_obj_property_t displayio_display_bus_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_display_get_bus_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&displayio_display_show_obj) }, { MP_ROM_QSTR(MP_QSTR_refresh_soon), MP_ROM_PTR(&displayio_display_refresh_soon_obj) }, @@ -299,6 +366,7 @@ STATIC const mp_rom_map_elem_t displayio_display_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_display_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_display_bus_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_display_locals_dict, displayio_display_locals_dict_table); diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index 7d6444a2d..a8938bbcd 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -36,27 +36,33 @@ extern const mp_obj_type_t displayio_display_type; #define DELAY 0x80 +#define NO_BRIGHTNESS_COMMAND 0x100 + void common_hal_displayio_display_construct(displayio_display_obj_t* self, mp_obj_t bus, uint16_t width, uint16_t height, - int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, + int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, + bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, - uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin); + uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, + mp_float_t brightness, bool auto_brightness, + bool single_byte_bounds, bool data_as_commands); int32_t common_hal_displayio_display_wait_for_frame(displayio_display_obj_t* self); -void common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); +bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self); bool displayio_display_begin_transaction(displayio_display_obj_t* self); void displayio_display_end_transaction(displayio_display_obj_t* self); -void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); +// The second point of the region is exclusive. +void displayio_display_set_region_to_update(displayio_display_obj_t* self, displayio_area_t* area); bool displayio_display_frame_queued(displayio_display_obj_t* self); bool displayio_display_refresh_queued(displayio_display_obj_t* self); void displayio_display_finish_refresh(displayio_display_obj_t* self); -void displayio_display_send_pixels(displayio_display_obj_t* self, uint32_t* pixels, uint32_t length); +void displayio_display_send_pixels(displayio_display_obj_t* self, uint8_t* pixels, uint32_t length); bool common_hal_displayio_display_get_auto_brightness(displayio_display_obj_t* self); void common_hal_displayio_display_set_auto_brightness(displayio_display_obj_t* self, bool auto_brightness); diff --git a/shared-bindings/displayio/FourWire.c b/shared-bindings/displayio/FourWire.c index 70cd42747..af64a2028 100644 --- a/shared-bindings/displayio/FourWire.c +++ b/shared-bindings/displayio/FourWire.c @@ -46,22 +46,29 @@ //| Manage updating a display over SPI four wire protocol in the background while Python code runs. //| It doesn't handle display initialization. //| -//| .. class:: FourWire(spi_bus, *, command, chip_select, reset) +//| .. class:: FourWire(spi_bus, *, command, chip_select, reset=None, baudrate=24000000) //| //| Create a FourWire object associated with the given pins. //| +//| The SPI bus and pins are then in use by the display until `displayio.release_displays()` is +//| called even after a reload. (It does this so CircuitPython can use the display after your code +//| is done.) So, the first time you initialize a display bus in code.py you should call +//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run. +//| //| :param busio.SPI spi_bus: The SPI bus that make up the clock and data lines //| :param microcontroller.Pin command: Data or command pin //| :param microcontroller.Pin chip_select: Chip select pin -//| :param microcontroller.Pin reset: Reset pin +//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used +//| :param int baudrate: Maximum baudrate in Hz for the display on the bus //| STATIC mp_obj_t displayio_fourwire_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_spi_bus, ARG_command, ARG_chip_select, ARG_reset }; + enum { ARG_spi_bus, ARG_command, ARG_chip_select, ARG_reset, ARG_baudrate }; static const mp_arg_t allowed_args[] = { { MP_QSTR_spi_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_command, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_baudrate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 24000000} }, }; 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); @@ -92,7 +99,7 @@ STATIC mp_obj_t displayio_fourwire_make_new(const mp_obj_type_t *type, size_t n_ } common_hal_displayio_fourwire_construct(self, - MP_OBJ_TO_PTR(spi), command, chip_select, reset); + MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int); return self; } diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index b8b00372c..5dbd60764 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -31,13 +31,12 @@ #include "common-hal/microcontroller/Pin.h" #include "shared-module/displayio/Group.h" -#include "supervisor/shared/board_busses.h" extern const mp_obj_type_t displayio_fourwire_type; void common_hal_displayio_fourwire_construct(displayio_fourwire_obj_t* self, busio_spi_obj_t* spi, const mcu_pin_obj_t* command, - const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset); + const mcu_pin_obj_t* chip_select, const mcu_pin_obj_t* reset, uint32_t baudrate); void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self); diff --git a/shared-bindings/displayio/Group.c b/shared-bindings/displayio/Group.c index 7b79f3229..5a35424ce 100644 --- a/shared-bindings/displayio/Group.c +++ b/shared-bindings/displayio/Group.c @@ -31,6 +31,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/binary.h" #include "py/objproperty.h" +#include "py/objtype.h" #include "py/runtime.h" #include "supervisor/shared/translate.h" @@ -41,19 +42,23 @@ //| //| Manage a group of sprites and groups and how they are inter-related. //| -//| .. class:: Group(*, max_size=4, scale=1) +//| .. class:: Group(*, max_size=4, scale=1, x=0, y=0) //| //| Create a Group of a given size and scale. Scale is in one dimension. For example, scale=2 //| leads to a layer's pixel being 2x2 pixels when in the group. //| //| :param int max_size: The maximum group size. //| :param int scale: Scale of layer pixels in one dimension. +//| :param int x: Initial x position within the parent. +//| :param int y: Initial y position within the parent. //| STATIC mp_obj_t displayio_group_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_max_size, ARG_scale }; + enum { ARG_max_size, ARG_scale, ARG_x, ARG_y }; static const mp_arg_t allowed_args[] = { { MP_QSTR_max_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4} }, { MP_QSTR_scale, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, }; 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); @@ -70,14 +75,18 @@ STATIC mp_obj_t displayio_group_make_new(const mp_obj_type_t *type, size_t n_arg displayio_group_t *self = m_new_obj(displayio_group_t); self->base.type = &displayio_group_type; - common_hal_displayio_group_construct(self, max_size, scale); + common_hal_displayio_group_construct(self, max_size, scale, args[ARG_x].u_int, args[ARG_y].u_int); return MP_OBJ_FROM_PTR(self); } // Helper to ensure we have the native super class instead of a subclass. -static displayio_group_t* native_group(mp_obj_t group_obj) { +displayio_group_t* native_group(mp_obj_t group_obj) { mp_obj_t native_group = mp_instance_cast_to_native_base(group_obj, &displayio_group_type); + if (native_group == MP_OBJ_NULL) { + mp_raise_ValueError_varg(translate("Must be a %q subclass."), MP_QSTR_Group); + } + mp_obj_assert_native_inited(native_group); return MP_OBJ_TO_PTR(native_group); } @@ -168,7 +177,7 @@ const mp_obj_property_t displayio_group_y_obj = { //| Append a layer to the group. It will be drawn above other layers. //| STATIC mp_obj_t displayio_group_obj_append(mp_obj_t self_in, mp_obj_t layer) { - displayio_group_t *self = MP_OBJ_TO_PTR(self_in); + displayio_group_t *self = native_group(self_in); common_hal_displayio_group_insert(self, common_hal_displayio_group_get_len(self), layer); return mp_const_none; } @@ -179,13 +188,28 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_append_obj, displayio_group_obj_append //| Insert a layer into the group. //| STATIC mp_obj_t displayio_group_obj_insert(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t layer) { - displayio_group_t *self = MP_OBJ_TO_PTR(self_in); + displayio_group_t *self = native_group(self_in); size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), index_obj, false); common_hal_displayio_group_insert(self, index, layer); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(displayio_group_insert_obj, displayio_group_obj_insert); + +//| .. method:: index(layer) +//| +//| Returns the index of the first copy of layer. Raises ValueError if not found. +//| +STATIC mp_obj_t displayio_group_obj_index(mp_obj_t self_in, mp_obj_t layer) { + displayio_group_t *self = native_group(self_in); + mp_int_t index = common_hal_displayio_group_index(self, layer); + if (index < 0) { + mp_raise_ValueError(translate("object not in sequence")); + } + return MP_OBJ_NEW_SMALL_INT(index); +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_index_obj, displayio_group_obj_index); + //| .. method:: pop(i=-1) //| //| Remove the ith item and return it. @@ -198,7 +222,7 @@ STATIC mp_obj_t displayio_group_obj_pop(size_t n_args, const mp_obj_t *pos_args, 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); - displayio_group_t *self = MP_OBJ_TO_PTR(pos_args[0]); + displayio_group_t *self = native_group(pos_args[0]); size_t index = mp_get_index(&displayio_group_type, common_hal_displayio_group_get_len(self), @@ -208,12 +232,26 @@ STATIC mp_obj_t displayio_group_obj_pop(size_t n_args, const mp_obj_t *pos_args, } MP_DEFINE_CONST_FUN_OBJ_KW(displayio_group_pop_obj, 1, displayio_group_obj_pop); + +//| .. method:: remove(layer) +//| +//| Remove the first copy of layer. Raises ValueError if it is not present. +//| +STATIC mp_obj_t displayio_group_obj_remove(mp_obj_t self_in, mp_obj_t layer) { + mp_obj_t index = displayio_group_obj_index(self_in, layer); + displayio_group_t *self = native_group(self_in); + + common_hal_displayio_group_pop(self, MP_OBJ_SMALL_INT_VALUE(index)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_group_remove_obj, displayio_group_obj_remove); + //| .. method:: __len__() //| //| Returns the number of layers in a Group //| STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - displayio_group_t *self = MP_OBJ_TO_PTR(self_in); + displayio_group_t *self = native_group(self_in); uint16_t len = common_hal_displayio_group_get_len(self); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); @@ -247,7 +285,7 @@ STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { //| del group[0] //| STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) { - displayio_group_t *self = MP_OBJ_TO_PTR(self_in); + displayio_group_t *self = native_group(self_in); if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); @@ -257,7 +295,7 @@ STATIC mp_obj_t group_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t valu if (value == MP_OBJ_SENTINEL) { // load return common_hal_displayio_group_get(self, index); - } else if (value == mp_const_none) { + } else if (value == MP_OBJ_NULL) { common_hal_displayio_group_pop(self, index); } else { common_hal_displayio_group_set(self, index, value); @@ -272,7 +310,9 @@ STATIC const mp_rom_map_elem_t displayio_group_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_group_y_obj) }, { MP_ROM_QSTR(MP_QSTR_append), MP_ROM_PTR(&displayio_group_append_obj) }, { MP_ROM_QSTR(MP_QSTR_insert), MP_ROM_PTR(&displayio_group_insert_obj) }, + { MP_ROM_QSTR(MP_QSTR_index), MP_ROM_PTR(&displayio_group_index_obj) }, { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&displayio_group_pop_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&displayio_group_remove_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_group_locals_dict, displayio_group_locals_dict_table); @@ -282,5 +322,6 @@ const mp_obj_type_t displayio_group_type = { .make_new = displayio_group_make_new, .subscr = group_subscr, .unary_op = group_unary_op, + .getiter = mp_obj_new_generic_iterator, .locals_dict = (mp_obj_dict_t*)&displayio_group_locals_dict, }; diff --git a/shared-bindings/displayio/Group.h b/shared-bindings/displayio/Group.h index d326dbf4d..dc9616f2e 100644 --- a/shared-bindings/displayio/Group.h +++ b/shared-bindings/displayio/Group.h @@ -31,8 +31,9 @@ extern const mp_obj_type_t displayio_group_type; +displayio_group_t* native_group(mp_obj_t group_obj); -void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size, uint32_t scale); +void common_hal_displayio_group_construct(displayio_group_t* self, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y); uint32_t common_hal_displayio_group_get_scale(displayio_group_t* self); void common_hal_displayio_group_set_scale(displayio_group_t* self, uint32_t scale); mp_int_t common_hal_displayio_group_get_x(displayio_group_t* self); @@ -43,6 +44,7 @@ void common_hal_displayio_group_append(displayio_group_t* self, mp_obj_t layer); void common_hal_displayio_group_insert(displayio_group_t* self, size_t index, mp_obj_t layer); size_t common_hal_displayio_group_get_len(displayio_group_t* self); mp_obj_t common_hal_displayio_group_pop(displayio_group_t* self, size_t index); +mp_int_t common_hal_displayio_group_index(displayio_group_t* self, mp_obj_t layer); mp_obj_t common_hal_displayio_group_get(displayio_group_t* self, size_t index); void common_hal_displayio_group_set(displayio_group_t* self, size_t index, mp_obj_t layer); diff --git a/shared-bindings/displayio/I2CDisplay.c b/shared-bindings/displayio/I2CDisplay.c new file mode 100644 index 000000000..1f74e8c9e --- /dev/null +++ b/shared-bindings/displayio/I2CDisplay.c @@ -0,0 +1,138 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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 "shared-bindings/displayio/I2CDisplay.h" + +#include <stdint.h> +#include <string.h> + +#include "lib/utils/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: displayio +//| +//| :class:`I2CDisplay` -- Manage updating a display over I2C +//| ========================================================================== +//| +//| Manage updating a display over I2C in the background while Python code runs. +//| It doesn't handle display initialization. +//| +//| .. class:: I2CDisplay(i2c_bus, *, device_address, reset=None) +//| +//| Create a I2CDisplay object associated with the given I2C bus and reset pin. +//| +//| The I2C bus and pins are then in use by the display until `displayio.release_displays()` is +//| called even after a reload. (It does this so CircuitPython can use the display after your code +//| is done.) So, the first time you initialize a display bus in code.py you should call +//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run. +//| +//| :param busio.I2C i2c_bus: The I2C bus that make up the clock and data lines +//| :param int device_address: The I2C address of the device +//| :param microcontroller.Pin reset: Reset pin. When None only software reset can be used +//| +STATIC mp_obj_t displayio_i2cdisplay_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_i2c_bus, ARG_device_address, ARG_reset }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_INT | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_reset, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t reset = args[ARG_reset].u_obj; + if (reset != mp_const_none) { + assert_pin_free(reset); + } else { + reset = NULL; + } + + displayio_i2cdisplay_obj_t* self = NULL; + mp_obj_t i2c = args[ARG_i2c_bus].u_obj; + for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (displays[i].i2cdisplay_bus.base.type == NULL || + displays[i].i2cdisplay_bus.base.type == &mp_type_NoneType) { + self = &displays[i].i2cdisplay_bus; + self->base.type = &displayio_i2cdisplay_type; + break; + } + } + if (self == NULL) { + mp_raise_RuntimeError(translate("Too many display busses")); + } + + common_hal_displayio_i2cdisplay_construct(self, + MP_OBJ_TO_PTR(i2c), args[ARG_device_address].u_int, reset); + return self; +} + +//| .. method:: send(command, data) +//| +//| Sends the given command value followed by the full set of data. Display state, such as +//| vertical scroll, set via ``send`` may or may not be reset once the code is done. +//| +STATIC mp_obj_t displayio_i2cdisplay_obj_send(mp_obj_t self, mp_obj_t command_obj, mp_obj_t data_obj) { + mp_int_t command_int = MP_OBJ_SMALL_INT_VALUE(command_obj); + if (!MP_OBJ_IS_SMALL_INT(command_obj) || command_int > 255 || command_int < 0) { + mp_raise_ValueError(translate("Command must be 0-255")); + } + uint8_t command = command_int; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + + // Wait for display bus to be available. + while (!common_hal_displayio_i2cdisplay_begin_transaction(self)) { +#ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP ; +#endif + } + uint8_t full_command[bufinfo.len + 1]; + full_command[0] = command; + memcpy(full_command + 1, ((uint8_t*) bufinfo.buf), bufinfo.len); + common_hal_displayio_i2cdisplay_send(self, true, full_command, bufinfo.len + 1); + common_hal_displayio_i2cdisplay_end_transaction(self); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(displayio_i2cdisplay_send_obj, displayio_i2cdisplay_obj_send); + +STATIC const mp_rom_map_elem_t displayio_i2cdisplay_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&displayio_i2cdisplay_send_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(displayio_i2cdisplay_locals_dict, displayio_i2cdisplay_locals_dict_table); + +const mp_obj_type_t displayio_i2cdisplay_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDisplay, + .make_new = displayio_i2cdisplay_make_new, + .locals_dict = (mp_obj_dict_t*)&displayio_i2cdisplay_locals_dict, +}; diff --git a/shared-bindings/bleio/AddressType.h b/shared-bindings/displayio/I2CDisplay.h index e69caffab..cc4162800 100644 --- a/shared-bindings/bleio/AddressType.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2017, 2018 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 @@ -24,27 +24,23 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESSTYPE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESSTYPE_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H -#include "py/obj.h" +#include "shared-module/displayio/I2CDisplay.h" +#include "common-hal/microcontroller/Pin.h" -typedef enum { - ADDRESS_PUBLIC, - ADDRESS_RANDOM_STATIC, - ADDRESS_RANDOM_PRIVATE_RESOLVABLE, - ADDRESS_RANDOM_PRIVATE_NON_RESOLVABLE -} bleio_address_type_t; +extern const mp_obj_type_t displayio_i2cdisplay_type; -extern const mp_obj_type_t bleio_addresstype_type; +void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, + busio_i2c_obj_t* i2c, uint16_t device_address, const mcu_pin_obj_t* reset); -typedef struct { - mp_obj_base_t base; -} bleio_addresstype_obj_t; +void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self); -extern const bleio_addresstype_obj_t bleio_addresstype_public_obj; -extern const bleio_addresstype_obj_t bleio_addresstype_random_static_obj; -extern const bleio_addresstype_obj_t bleio_addresstype_random_private_resolvable_obj; -extern const bleio_addresstype_obj_t bleio_addresstype_random_private_non_resolvable_obj; +bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_ADDRESSTYPE_H +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, bool command, uint8_t *data, uint32_t data_length); + +void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYBUSIO_I2CDISPLAY_H diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c index 799d42bef..dda58e3c5 100644 --- a/shared-bindings/displayio/Palette.c +++ b/shared-bindings/displayio/Palette.c @@ -67,6 +67,34 @@ STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_a return MP_OBJ_FROM_PTR(self); } +//| .. method:: __len__() +//| +//| Returns the number of colors in a Palette +//| +STATIC mp_obj_t group_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_const_true; + case MP_UNARY_OP_LEN: + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_len(self)); + default: return MP_OBJ_NULL; // op not supported + } +} + +//| .. method:: __setitem__(index, value) +//| +//| Sets the pixel color at the given index. The index should be an integer in the range 0 to color_count-1. +//| +//| The value argument represents a color, and can be from 0x000000 to 0xFFFFFF (to represent an RGB value). +//| Value can be an int, bytes (3 bytes (RGB) or 4 bytes (RGB + pad byte)), or bytearray. +//| +//| This allows you to:: +//| +//| palette[0] = 0xFFFFFF # set using an integer +//| palette[1] = b'\xff\xff\x00' # set using 3 bytes +//| palette[2] = b'\xff\xff\x00\x00' # set using 4 bytes +//| palette[3] = bytearray(b'\x00\x00\xFF') # set using a bytearay of 3 or 4 bytes +//| STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete item @@ -76,12 +104,12 @@ STATIC mp_obj_t palette_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t val if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { return MP_OBJ_NULL; } - // index read is not supported - if (value == MP_OBJ_SENTINEL) { - return MP_OBJ_NULL; - } displayio_palette_t *self = MP_OBJ_TO_PTR(self_in); size_t index = mp_get_index(&displayio_palette_type, self->color_count, index_in, false); + // index read + if (value == MP_OBJ_SENTINEL) { + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_palette_get_color(self, index)); + } uint32_t color; mp_int_t int_value; @@ -147,5 +175,7 @@ const mp_obj_type_t displayio_palette_type = { .name = MP_QSTR_Palette, .make_new = displayio_palette_make_new, .subscr = palette_subscr, + .unary_op = group_unary_op, + .getiter = mp_obj_new_generic_iterator, .locals_dict = (mp_obj_dict_t*)&displayio_palette_locals_dict, }; diff --git a/shared-bindings/displayio/Palette.h b/shared-bindings/displayio/Palette.h index 767fc7b63..8c9fe11e3 100644 --- a/shared-bindings/displayio/Palette.h +++ b/shared-bindings/displayio/Palette.h @@ -33,6 +33,8 @@ extern const mp_obj_type_t displayio_palette_type; void common_hal_displayio_palette_construct(displayio_palette_t* self, uint16_t color_count); void common_hal_displayio_palette_set_color(displayio_palette_t* self, uint32_t palette_index, uint32_t color); +uint32_t common_hal_displayio_palette_get_color(displayio_palette_t* self, uint32_t palette_index); +uint32_t common_hal_displayio_palette_get_len(displayio_palette_t* self); void common_hal_displayio_palette_make_opaque(displayio_palette_t* self, uint32_t palette_index); void common_hal_displayio_palette_make_transparent(displayio_palette_t* self, uint32_t palette_index); diff --git a/shared-bindings/displayio/ParallelBus.c b/shared-bindings/displayio/ParallelBus.c index 6a499ed06..00a96d230 100644 --- a/shared-bindings/displayio/ParallelBus.c +++ b/shared-bindings/displayio/ParallelBus.c @@ -39,18 +39,24 @@ //| .. currentmodule:: displayio //| -//| :class:`ParallelBus` -- Manage updating a display over SPI four wire protocol +//| :class:`ParallelBus` -- Manage updating a display over 8-bit parallel bus //| ============================================================================== //| -//| Manage updating a display over SPI four wire protocol in the background while Python code runs. -//| It doesn't handle display initialization. +//| Manage updating a display over 8-bit parallel bus in the background while Python code runs. This +//| protocol may be refered to as 8080-I Series Parallel Interface in datasheets. It doesn't handle +//| display initialization. //| //| .. class:: ParallelBus(*, data0, command, chip_select, write, read, reset) //| //| Create a ParallelBus object associated with the given pins. The bus is inferred from data0 //| by implying the next 7 additional pins on a given GPIO port. //| -//| :param microcontroller.Pin: The first data pin. The rest are implied +//| The parallel bus and pins are then in use by the display until `displayio.release_displays()` +//| is called even after a reload. (It does this so CircuitPython can use the display after your +//| code is done.) So, the first time you initialize a display bus in code.py you should call +//| :py:func`displayio.release_displays` first, otherwise it will error after the first code.py run. +//| +//| :param microcontroller.Pin data0: The first data pin. The rest are implied //| :param microcontroller.Pin command: Data or command pin //| :param microcontroller.Pin chip_select: Chip select pin //| :param microcontroller.Pin write: Write pin diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index eeacd1918..6ba4914a0 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -31,6 +31,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/binary.h" #include "py/objproperty.h" +#include "py/objtype.h" #include "py/runtime.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/ColorConverter.h" @@ -39,17 +40,6 @@ #include "shared-bindings/displayio/Shape.h" #include "supervisor/shared/translate.h" -static void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) { - // TODO(tannewt): Support any value sequence such as bytearray or bytes. - mp_obj_tuple_t *position = MP_OBJ_TO_PTR(position_obj); - if (MP_OBJ_IS_TYPE(position_obj, &mp_type_tuple) && position->len == 2) { - *x = mp_obj_get_int(position->items[0]); - *y = mp_obj_get_int(position->items[1]); - } else if (position != mp_const_none) { - mp_raise_TypeError(translate("position must be 2-tuple")); - } -} - //| .. currentmodule:: displayio //| //| :class:`TileGrid` -- A grid of tiles sourced out of one bitmap @@ -60,7 +50,7 @@ static void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) { //| //| A single tile grid is also known as a Sprite. //| -//| .. class:: TileGrid(bitmap, *, pixel_shader, position, width=1, height=1, tile_width=None, tile_height=None, default_tile=0) +//| .. class:: TileGrid(bitmap, *, pixel_shader, width=1, height=1, tile_width=None, tile_height=None, default_tile=0, x=0, y=0) //| //| Create a TileGrid object. The bitmap is source for 2d pixels. The pixel_shader is used to //| convert the value and its location to a display native pixel color. This may be a simple color @@ -70,24 +60,26 @@ static void unpack_position(mp_obj_t position_obj, int16_t* x, int16_t* y) { //| //| :param displayio.Bitmap bitmap: The bitmap storing one or more tiles. //| :param displayio.Palette pixel_shader: The pixel shader that produces colors from values -//| :param tuple position: Upper left corner of the grid //| :param int width: Width of the grid in tiles. //| :param int height: Height of the grid in tiles. //| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions. //| :param int tile_height: Height of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions. -//| :param in default_tile: Default tile index to show. +//| :param int default_tile: Default tile index to show. +//| :param int x: Initial x position of the left edge within the parent. +//| :param int y: Initial y position of the top edge within the parent. //| STATIC mp_obj_t displayio_tilegrid_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_bitmap, ARG_pixel_shader, ARG_position, ARG_width, ARG_height, ARG_tile_width, ARG_tile_height, ARG_default_tile }; + enum { ARG_bitmap, ARG_pixel_shader, ARG_width, ARG_height, ARG_tile_width, ARG_tile_height, ARG_default_tile, ARG_x, ARG_y }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_pixel_shader, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_position, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, { MP_QSTR_tile_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_tile_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_default_tile, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_x, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, }; 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); @@ -112,7 +104,12 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ bitmap_width = bmp->width; bitmap_height = bmp->height; } else { - mp_raise_TypeError(translate("unsupported bitmap type")); + mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_bitmap); + } + mp_obj_t pixel_shader = args[ARG_pixel_shader].u_obj; + if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type) && + !MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type)) { + mp_raise_TypeError_varg(translate("unsupported %q type"), MP_QSTR_pixel_shader); } uint16_t tile_width = args[ARG_tile_width].u_int; if (tile_width == 0) { @@ -129,54 +126,150 @@ STATIC mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ mp_raise_ValueError(translate("Tile height must exactly divide bitmap height")); } - int16_t x = 0; - int16_t y = 0; - mp_obj_t position_obj = args[ARG_position].u_obj; - unpack_position(position_obj, &x, &y); + int16_t x = args[ARG_x].u_int; + int16_t y = args[ARG_y].u_int; displayio_tilegrid_t *self = m_new_obj(displayio_tilegrid_t); self->base.type = &displayio_tilegrid_type; common_hal_displayio_tilegrid_construct(self, native, bitmap_width / tile_width, - args[ARG_pixel_shader].u_obj, args[ARG_width].u_int, args[ARG_height].u_int, + pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y, args[ARG_default_tile].u_int); return MP_OBJ_FROM_PTR(self); } -//| .. attribute:: position +// Helper to ensure we have the native super class instead of a subclass. +static displayio_tilegrid_t* native_tilegrid(mp_obj_t tilegrid_obj) { + mp_obj_t native_tilegrid = mp_instance_cast_to_native_base(tilegrid_obj, &displayio_tilegrid_type); + mp_obj_assert_native_inited(native_tilegrid); + return MP_OBJ_TO_PTR(native_tilegrid); +} + +//| .. attribute:: x //| -//| The position of the top-left corner of the tilegrid. +//| X position of the left edge in the parent. //| -STATIC mp_obj_t displayio_tilegrid_obj_get_position(mp_obj_t self_in) { - displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in); - int16_t x; - int16_t y; - common_hal_displayio_tilegrid_get_position(self, &x, &y); +STATIC mp_obj_t displayio_tilegrid_obj_get_x(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_x(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_x_obj, displayio_tilegrid_obj_get_x); - mp_obj_t coords[2]; - coords[0] = mp_obj_new_int(x); - coords[1] = mp_obj_new_int(y); +STATIC mp_obj_t displayio_tilegrid_obj_set_x(mp_obj_t self_in, mp_obj_t x_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); - return mp_obj_new_tuple(2, coords); + mp_int_t x = mp_obj_get_int(x_obj); + common_hal_displayio_tilegrid_set_x(self, x); + return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_position_obj, displayio_tilegrid_obj_get_position); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_x_obj, displayio_tilegrid_obj_set_x); -STATIC mp_obj_t displayio_tilegrid_obj_set_position(mp_obj_t self_in, mp_obj_t value) { - displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in); +const mp_obj_property_t displayio_tilegrid_x_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_x_obj, + (mp_obj_t)&displayio_tilegrid_set_x_obj, + (mp_obj_t)&mp_const_none_obj}, +}; - int16_t x = 0; - int16_t y = 0; - unpack_position(value, &x, &y); +//| .. attribute:: y +//| +//| Y position of the top edge in the parent. +//| +STATIC mp_obj_t displayio_tilegrid_obj_get_y(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_y(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_y_obj, displayio_tilegrid_obj_get_y); - common_hal_displayio_tilegrid_set_position(self, x, y); +STATIC mp_obj_t displayio_tilegrid_obj_set_y(mp_obj_t self_in, mp_obj_t y_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + mp_int_t y = mp_obj_get_int(y_obj); + common_hal_displayio_tilegrid_set_y(self, y); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_position_obj, displayio_tilegrid_obj_set_position); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_y_obj, displayio_tilegrid_obj_set_y); -const mp_obj_property_t displayio_tilegrid_position_obj = { +const mp_obj_property_t displayio_tilegrid_y_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_tilegrid_get_position_obj, - (mp_obj_t)&displayio_tilegrid_set_position_obj, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_y_obj, + (mp_obj_t)&displayio_tilegrid_set_y_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: flip_x +//| +//| If true, the left edge rendered will be the right edge of the right-most tile. +//| +STATIC mp_obj_t displayio_tilegrid_obj_get_flip_x(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_x(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_x_obj, displayio_tilegrid_obj_get_flip_x); + +STATIC mp_obj_t displayio_tilegrid_obj_set_flip_x(mp_obj_t self_in, mp_obj_t flip_x_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + + common_hal_displayio_tilegrid_set_flip_x(self, mp_obj_is_true(flip_x_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_x_obj, displayio_tilegrid_obj_set_flip_x); + +const mp_obj_property_t displayio_tilegrid_flip_x_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_flip_x_obj, + (mp_obj_t)&displayio_tilegrid_set_flip_x_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| .. attribute:: flip_y +//| +//| If true, the top edge rendered will be the bottom edge of the bottom-most tile. +//| +STATIC mp_obj_t displayio_tilegrid_obj_get_flip_y(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return mp_obj_new_bool(common_hal_displayio_tilegrid_get_flip_y(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_flip_y_obj, displayio_tilegrid_obj_get_flip_y); + +STATIC mp_obj_t displayio_tilegrid_obj_set_flip_y(mp_obj_t self_in, mp_obj_t flip_y_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + + common_hal_displayio_tilegrid_set_flip_y(self, mp_obj_is_true(flip_y_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_flip_y_obj, displayio_tilegrid_obj_set_flip_y); + +const mp_obj_property_t displayio_tilegrid_flip_y_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_flip_y_obj, + (mp_obj_t)&displayio_tilegrid_set_flip_y_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| .. attribute:: transpose_xy +//| +//| If true, the TileGrid's axis will be swapped. When combined with mirroring, any 90 degree +//| rotation can be achieved along with the corresponding mirrored version. +//| +STATIC mp_obj_t displayio_tilegrid_obj_get_transpose_xy(mp_obj_t self_in) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + return mp_obj_new_bool(common_hal_displayio_tilegrid_get_transpose_xy(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_transpose_xy_obj, displayio_tilegrid_obj_get_transpose_xy); + +STATIC mp_obj_t displayio_tilegrid_obj_set_transpose_xy(mp_obj_t self_in, mp_obj_t transpose_xy_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + + common_hal_displayio_tilegrid_set_transpose_xy(self, mp_obj_is_true(transpose_xy_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_set_transpose_xy_obj, displayio_tilegrid_obj_set_transpose_xy); + +const mp_obj_property_t displayio_tilegrid_transpose_xy_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_tilegrid_get_transpose_xy_obj, + (mp_obj_t)&displayio_tilegrid_set_transpose_xy_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -185,13 +278,13 @@ const mp_obj_property_t displayio_tilegrid_position_obj = { //| The pixel shader of the tilegrid. //| STATIC mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) { - displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in); + displayio_tilegrid_t *self = native_tilegrid(self_in); return common_hal_displayio_tilegrid_get_pixel_shader(self); } MP_DEFINE_CONST_FUN_OBJ_1(displayio_tilegrid_get_pixel_shader_obj, displayio_tilegrid_obj_get_pixel_shader); STATIC mp_obj_t displayio_tilegrid_obj_set_pixel_shader(mp_obj_t self_in, mp_obj_t pixel_shader) { - displayio_tilegrid_t *self = MP_OBJ_TO_PTR(self_in); + displayio_tilegrid_t *self = native_tilegrid(self_in); if (!MP_OBJ_IS_TYPE(pixel_shader, &displayio_palette_type) && !MP_OBJ_IS_TYPE(pixel_shader, &displayio_colorconverter_type)) { mp_raise_TypeError(translate("pixel_shader must be displayio.Palette or displayio.ColorConverter")); } @@ -209,9 +302,76 @@ const mp_obj_property_t displayio_tilegrid_pixel_shader_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| .. method:: __getitem__(index) +//| +//| Returns the tile index at the given index. The index can either be an x,y tuple or an int equal +//| to ``y * width + x``. +//| +//| This allows you to:: +//| +//| print(grid[0]) +//| +//| .. method:: __setitem__(index, tile_index) +//| +//| Sets the tile index at the given index. The index can either be an x,y tuple or an int equal +//| to ``y * width + x``. +//| +//| This allows you to:: +//| +//| grid[0] = 10 +//| +//| or:: +//| +//| grid[0,0] = 10 +//| +STATIC mp_obj_t tilegrid_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value_obj) { + displayio_tilegrid_t *self = native_tilegrid(self_in); + + + if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + mp_raise_NotImplementedError(translate("Slices not supported")); + } else { + uint16_t x = 0; + uint16_t y = 0; + if (MP_OBJ_IS_SMALL_INT(index_obj)) { + mp_int_t i = MP_OBJ_SMALL_INT_VALUE(index_obj); + uint16_t width = common_hal_displayio_tilegrid_get_width(self); + x = i % width; + y = i / width; + } else { + mp_obj_t* items; + mp_obj_get_array_fixed_n(index_obj, 2, &items); + x = mp_obj_get_int(items[0]); + y = mp_obj_get_int(items[1]); + } + if (x >= common_hal_displayio_tilegrid_get_width(self) || + y >= common_hal_displayio_tilegrid_get_height(self)) { + mp_raise_IndexError(translate("tile index out of bounds")); + } + + if (value_obj == MP_OBJ_SENTINEL) { + // load + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_tilegrid_get_tile(self, x, y)); + } else if (value_obj == mp_const_none) { + return MP_OBJ_NULL; // op not supported + } else { + mp_int_t value = mp_obj_get_int(value_obj); + if (value < 0 || value > 255) { + mp_raise_ValueError(translate("Tile indices must be 0 - 255")); + } + common_hal_displayio_tilegrid_set_tile(self, x, y, value); + } + } + return mp_const_none; +} + STATIC const mp_rom_map_elem_t displayio_tilegrid_locals_dict_table[] = { // Properties - { MP_ROM_QSTR(MP_QSTR_position), MP_ROM_PTR(&displayio_tilegrid_position_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&displayio_tilegrid_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&displayio_tilegrid_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&displayio_tilegrid_flip_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&displayio_tilegrid_flip_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_transpose_xy), MP_ROM_PTR(&displayio_tilegrid_transpose_xy_obj) }, { MP_ROM_QSTR(MP_QSTR_pixel_shader), MP_ROM_PTR(&displayio_tilegrid_pixel_shader_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_tilegrid_locals_dict, displayio_tilegrid_locals_dict_table); @@ -220,5 +380,6 @@ const mp_obj_type_t displayio_tilegrid_type = { { &mp_type_type }, .name = MP_QSTR_TileGrid, .make_new = displayio_tilegrid_make_new, + .subscr = tilegrid_subscr, .locals_dict = (mp_obj_dict_t*)&displayio_tilegrid_locals_dict, }; diff --git a/shared-bindings/displayio/TileGrid.h b/shared-bindings/displayio/TileGrid.h index 2260db413..1f9995a94 100644 --- a/shared-bindings/displayio/TileGrid.h +++ b/shared-bindings/displayio/TileGrid.h @@ -35,13 +35,28 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_ uint16_t bitmap_width_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); -void common_hal_displayio_tilegrid_get_position(displayio_tilegrid_t *self, int16_t* x, int16_t* y); -void common_hal_displayio_tilegrid_set_position(displayio_tilegrid_t *self, int16_t x, int16_t y); - +mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self); +void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x); +mp_int_t common_hal_displayio_tilegrid_get_y(displayio_tilegrid_t *self); +void common_hal_displayio_tilegrid_set_y(displayio_tilegrid_t *self, mp_int_t y); mp_obj_t common_hal_displayio_tilegrid_get_pixel_shader(displayio_tilegrid_t *self); void common_hal_displayio_tilegrid_set_pixel_shader(displayio_tilegrid_t *self, mp_obj_t pixel_shader); -void common_hal_displayio_textgrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index); -void common_hal_displayio_textgrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y); + +bool common_hal_displayio_tilegrid_get_flip_x(displayio_tilegrid_t *self); +void common_hal_displayio_tilegrid_set_flip_x(displayio_tilegrid_t *self, bool flip_x); +bool common_hal_displayio_tilegrid_get_flip_y(displayio_tilegrid_t *self); +void common_hal_displayio_tilegrid_set_flip_y(displayio_tilegrid_t *self, bool flip_y); +bool common_hal_displayio_tilegrid_get_transpose_xy(displayio_tilegrid_t *self); +void common_hal_displayio_tilegrid_set_transpose_xy(displayio_tilegrid_t *self, bool transpose_xy); + +uint16_t common_hal_displayio_tilegrid_get_width(displayio_tilegrid_t *self); +uint16_t common_hal_displayio_tilegrid_get_height(displayio_tilegrid_t *self); + +uint8_t common_hal_displayio_tilegrid_get_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y); +void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t x, uint16_t y, uint8_t tile_index); + +// Private API for scrolling the TileGrid. +void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_TILEGRID_H diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index 1ee755014..fd3dc4233 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -31,12 +31,11 @@ #include "shared-bindings/displayio/__init__.h" #include "shared-bindings/displayio/Bitmap.h" -#include "shared-bindings/displayio/BuiltinFont.h" #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/Display.h" #include "shared-bindings/displayio/FourWire.h" -#include "shared-bindings/displayio/Glyph.h" #include "shared-bindings/displayio/Group.h" +#include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/OnDiskBitmap.h" #include "shared-bindings/displayio/Palette.h" #include "shared-bindings/displayio/ParallelBus.h" @@ -59,28 +58,28 @@ //| :maxdepth: 3 //| //| Bitmap -//| BuiltinFont //| ColorConverter //| Display //| FourWire -//| Glyph //| Group +//| I2CDisplay //| OnDiskBitmap //| Palette //| ParallelBus //| Shape //| TileGrid //| -//| All libraries change hardware state but are never deinit -//| -//| .. method:: release_displays() +//| .. function:: release_displays() //| //| Releases any actively used displays so their busses and pins can be used again. This will also //| release the builtin display on boards that have one. You will need to reinitialize it yourself //| afterwards. //| +//| Use this once in your code.py if you initialize a display. Place it right before the +//| initialization so the display is active as long as possible. +//| STATIC mp_obj_t displayio_release_displays(void) { common_hal_displayio_release_displays(); return mp_const_none; @@ -90,10 +89,8 @@ MP_DEFINE_CONST_FUN_OBJ_0(displayio_release_displays_obj, displayio_release_disp STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_displayio) }, { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) }, - { MP_ROM_QSTR(MP_QSTR_BuiltinFont), MP_ROM_PTR(&displayio_builtinfont_type) }, { MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) }, { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&displayio_display_type) }, - { MP_ROM_QSTR(MP_QSTR_Glyph), MP_ROM_PTR(&displayio_glyph_type) }, { MP_ROM_QSTR(MP_QSTR_Group), MP_ROM_PTR(&displayio_group_type) }, { MP_ROM_QSTR(MP_QSTR_OnDiskBitmap), MP_ROM_PTR(&displayio_ondiskbitmap_type) }, { MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) }, @@ -101,6 +98,7 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_TileGrid), MP_ROM_PTR(&displayio_tilegrid_type) }, { MP_ROM_QSTR(MP_QSTR_FourWire), MP_ROM_PTR(&displayio_fourwire_type) }, + { MP_ROM_QSTR(MP_QSTR_I2CDisplay), MP_ROM_PTR(&displayio_i2cdisplay_type) }, { MP_ROM_QSTR(MP_QSTR_ParallelBus), MP_ROM_PTR(&displayio_parallelbus_type) }, { MP_ROM_QSTR(MP_QSTR_release_displays), MP_ROM_PTR(&displayio_release_displays_obj) }, diff --git a/shared-bindings/displayio/BuiltinFont.c b/shared-bindings/fontio/BuiltinFont.c index 55d38458e..74bc4d29e 100644 --- a/shared-bindings/displayio/BuiltinFont.c +++ b/shared-bindings/fontio/BuiltinFont.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "shared-bindings/displayio/BuiltinFont.h" +#include "shared-bindings/fontio/BuiltinFont.h" #include <stdint.h> @@ -36,7 +36,7 @@ #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" -//| .. currentmodule:: displayio +//| .. currentmodule:: fontio //| //| :class:`BuiltinFont` -- A font built into CircuitPython //| ========================================================================================= @@ -56,15 +56,15 @@ //| `get_glyph` in most cases. This is useful for use with `displayio.TileGrid` and //| `terminalio.Terminal`. //| -STATIC mp_obj_t displayio_builtinfont_obj_get_bitmap(mp_obj_t self_in) { - displayio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_displayio_builtinfont_get_bitmap(self); +STATIC mp_obj_t fontio_builtinfont_obj_get_bitmap(mp_obj_t self_in) { + fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_fontio_builtinfont_get_bitmap(self); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_builtinfont_get_bitmap_obj, displayio_builtinfont_obj_get_bitmap); +MP_DEFINE_CONST_FUN_OBJ_1(fontio_builtinfont_get_bitmap_obj, fontio_builtinfont_obj_get_bitmap); -const mp_obj_property_t displayio_builtinfont_bitmap_obj = { +const mp_obj_property_t fontio_builtinfont_bitmap_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&displayio_builtinfont_get_bitmap_obj, + .proxy = {(mp_obj_t)&fontio_builtinfont_get_bitmap_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; @@ -73,38 +73,38 @@ const mp_obj_property_t displayio_builtinfont_bitmap_obj = { //| //| Returns the maximum bounds of all glyphs in the font in a tuple of two values: width, height. //| -STATIC mp_obj_t displayio_builtinfont_obj_get_bounding_box(mp_obj_t self_in) { - displayio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t fontio_builtinfont_obj_get_bounding_box(mp_obj_t self_in) { + fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_displayio_builtinfont_get_bounding_box(self); + return common_hal_fontio_builtinfont_get_bounding_box(self); } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_builtinfont_get_bounding_box_obj, displayio_builtinfont_obj_get_bounding_box); +MP_DEFINE_CONST_FUN_OBJ_1(fontio_builtinfont_get_bounding_box_obj, fontio_builtinfont_obj_get_bounding_box); //| .. method:: get_glyph(codepoint) //| -//| Returns a `displayio.Glyph` for the given codepoint or None if no glyph is available. +//| Returns a `fontio.Glyph` for the given codepoint or None if no glyph is available. //| -STATIC mp_obj_t displayio_builtinfont_obj_get_glyph(mp_obj_t self_in, mp_obj_t codepoint_obj) { - displayio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t fontio_builtinfont_obj_get_glyph(mp_obj_t self_in, mp_obj_t codepoint_obj) { + fontio_builtinfont_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t codepoint; if (!mp_obj_get_int_maybe(codepoint_obj, &codepoint)) { mp_raise_ValueError_varg(translate("%q should be an int"), MP_QSTR_codepoint); } - return common_hal_displayio_builtinfont_get_glyph(self, codepoint); + return common_hal_fontio_builtinfont_get_glyph(self, codepoint); } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_builtinfont_get_glyph_obj, displayio_builtinfont_obj_get_glyph); +MP_DEFINE_CONST_FUN_OBJ_2(fontio_builtinfont_get_glyph_obj, fontio_builtinfont_obj_get_glyph); -STATIC const mp_rom_map_elem_t displayio_builtinfont_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&displayio_builtinfont_bitmap_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_bounding_box), MP_ROM_PTR(&displayio_builtinfont_get_bounding_box_obj) }, - { MP_ROM_QSTR(MP_QSTR_get_glyph), MP_ROM_PTR(&displayio_builtinfont_get_glyph_obj) }, +STATIC const mp_rom_map_elem_t fontio_builtinfont_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&fontio_builtinfont_bitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_bounding_box), MP_ROM_PTR(&fontio_builtinfont_get_bounding_box_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_glyph), MP_ROM_PTR(&fontio_builtinfont_get_glyph_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(displayio_builtinfont_locals_dict, displayio_builtinfont_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(fontio_builtinfont_locals_dict, fontio_builtinfont_locals_dict_table); -const mp_obj_type_t displayio_builtinfont_type = { +const mp_obj_type_t fontio_builtinfont_type = { { &mp_type_type }, .name = MP_QSTR_BuiltinFont, - .locals_dict = (mp_obj_dict_t*)&displayio_builtinfont_locals_dict, + .locals_dict = (mp_obj_dict_t*)&fontio_builtinfont_locals_dict, }; diff --git a/shared-bindings/displayio/BuiltinFont.h b/shared-bindings/fontio/BuiltinFont.h index 766013158..e87445e6b 100644 --- a/shared-bindings/displayio/BuiltinFont.h +++ b/shared-bindings/fontio/BuiltinFont.h @@ -24,15 +24,15 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BUILTINFONT_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BUILTINFONT_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H -#include "shared-module/displayio/BuiltinFont.h" +#include "shared-module/fontio/BuiltinFont.h" -extern const mp_obj_type_t displayio_builtinfont_type; +extern const mp_obj_type_t fontio_builtinfont_type; -mp_obj_t common_hal_displayio_builtinfont_get_bitmap(const displayio_builtinfont_t *self); -mp_obj_t common_hal_displayio_builtinfont_get_bounding_box(const displayio_builtinfont_t *self); -mp_obj_t common_hal_displayio_builtinfont_get_glyph(const displayio_builtinfont_t *self, mp_uint_t codepoint); +mp_obj_t common_hal_fontio_builtinfont_get_bitmap(const fontio_builtinfont_t *self); +mp_obj_t common_hal_fontio_builtinfont_get_bounding_box(const fontio_builtinfont_t *self); +mp_obj_t common_hal_fontio_builtinfont_get_glyph(const fontio_builtinfont_t *self, mp_uint_t codepoint); -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_BUILTINFONT_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_BUILTINFONT_H diff --git a/shared-bindings/displayio/Glyph.c b/shared-bindings/fontio/Glyph.c index 1a4a75522..a23284152 100644 --- a/shared-bindings/displayio/Glyph.c +++ b/shared-bindings/fontio/Glyph.c @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#include "shared-bindings/displayio/Glyph.h" +#include "shared-bindings/fontio/Glyph.h" #include <stdint.h> -//| .. currentmodule:: displayio +//| .. currentmodule:: fontio //| //| :class:`Glyph` -- Storage of glyph info //| ========================================================================== @@ -46,7 +46,7 @@ //| :param int shift_x: the x difference to the next glyph //| :param int shift_y: the y difference to the next glyph //| -const mp_obj_namedtuple_type_t displayio_glyph_type = { +const mp_obj_namedtuple_type_t fontio_glyph_type = { .base = { .base = { .type = &mp_type_type diff --git a/shared-bindings/displayio/Glyph.h b/shared-bindings/fontio/Glyph.h index d26a4b9e4..c58d812dd 100644 --- a/shared-bindings/displayio/Glyph.h +++ b/shared-bindings/fontio/Glyph.h @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GLYPH_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GLYPH_H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H #include "py/objnamedtuple.h" -extern const mp_obj_namedtuple_type_t displayio_glyph_type; +extern const mp_obj_namedtuple_type_t fontio_glyph_type; -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_GLYPH_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO_GLYPH_H diff --git a/shared-bindings/fontio/__init__.c b/shared-bindings/fontio/__init__.c new file mode 100644 index 000000000..cd0f5ab0f --- /dev/null +++ b/shared-bindings/fontio/__init__.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/fontio/__init__.h" +#include "shared-bindings/fontio/BuiltinFont.h" +#include "shared-bindings/fontio/Glyph.h" + +//| :mod:`fontio` --- Core font related data structures +//| ========================================================================= +//| +//| .. module:: fontio +//| :synopsis: Core font related data structures +//| :platform: SAMD21, SAMD51, nRF52 +//| +//| The `fontio` module contains classes to store font related information. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| BuiltinFont +//| Glyph +//| + +STATIC const mp_rom_map_elem_t fontio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fontio) }, + { MP_ROM_QSTR(MP_QSTR_BuiltinFont), MP_ROM_PTR(&fontio_builtinfont_type) }, + { MP_ROM_QSTR(MP_QSTR_Glyph), MP_ROM_PTR(&fontio_glyph_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(fontio_module_globals, fontio_module_globals_table); + +const mp_obj_module_t fontio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&fontio_module_globals, +}; diff --git a/shared-bindings/fontio/__init__.h b/shared-bindings/fontio/__init__.h new file mode 100644 index 000000000..209919777 --- /dev/null +++ b/shared-bindings/fontio/__init__.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 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_FONTIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO___INIT___H + + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_FONTIO___INIT___H diff --git a/shared-bindings/frequencyio/FrequencyIn.c b/shared-bindings/frequencyio/FrequencyIn.c index 908cb307d..e2b924c07 100644 --- a/shared-bindings/frequencyio/FrequencyIn.c +++ b/shared-bindings/frequencyio/FrequencyIn.c @@ -109,6 +109,12 @@ STATIC mp_obj_t frequencyio_frequencyin_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_deinit_obj, frequencyio_frequencyin_deinit); +STATIC void check_for_deinit(frequencyio_frequencyin_obj_t *self) { + if (common_hal_frequencyio_frequencyin_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -133,7 +139,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(frequencyio_frequencyin___exit___obj, //| STATIC mp_obj_t frequencyio_frequencyin_obj_pause(mp_obj_t self_in) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); common_hal_frequencyio_frequencyin_pause(self); return mp_const_none; @@ -146,7 +152,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_pause_obj, frequencyio_frequen //| STATIC mp_obj_t frequencyio_frequencyin_obj_resume(mp_obj_t self_in) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); common_hal_frequencyio_frequencyin_resume(self); return mp_const_none; @@ -160,7 +166,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_resume_obj, frequencyio_freque STATIC mp_obj_t frequencyio_frequencyin_obj_clear(mp_obj_t self_in) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); common_hal_frequencyio_frequencyin_clear(self); return mp_const_none; @@ -178,7 +184,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequencyin_clear_obj, frequencyio_frequen //| STATIC mp_obj_t frequencyio_frequencyin_obj_get_capture_period(mp_obj_t self_in) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_frequencyio_frequencyin_get_capture_period(self)); } @@ -186,7 +192,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(frequencyio_frequency_get_capture_period_obj, frequenc STATIC mp_obj_t frequencyio_frequencyin_obj_set_capture_period(mp_obj_t self_in, mp_obj_t capture_period) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); common_hal_frequencyio_frequencyin_set_capture_period(self, mp_obj_get_int(capture_period)); return mp_const_none; @@ -206,7 +212,7 @@ const mp_obj_property_t frequencyio_frequencyin_capture_period_obj = { //| STATIC mp_obj_t frequencyio_frequencyin_obj_get_value(mp_obj_t self_in) { frequencyio_frequencyin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_frequencyio_frequencyin_deinited(self)); + check_for_deinit(self); //return MP_OBJ_NEW_SMALL_INT(common_hal_frequencyio_frequencyin_get_item(self)); return mp_obj_new_int_from_float(common_hal_frequencyio_frequencyin_get_item(self)); diff --git a/shared-bindings/gamepad/GamePad.c b/shared-bindings/gamepad/GamePad.c index 4458c972f..d3c29019a 100644 --- a/shared-bindings/gamepad/GamePad.c +++ b/shared-bindings/gamepad/GamePad.c @@ -23,17 +23,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "shared-bindings/gamepad/GamePad.h" + #include "py/obj.h" #include "py/runtime.h" #include "py/mphal.h" #include "py/gc.h" #include "py/mpstate.h" -#include "shared-module/gamepad/__init__.h" -#include "shared-module/gamepad/GamePad.h" +#include "shared-bindings/gamepad/__init__.h" #include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/util.h" #include "supervisor/shared/translate.h" -#include "GamePad.h" //| .. currentmodule:: gamepad @@ -78,7 +77,8 @@ //| Initializes button scanning routines. //| //| The ``b1``-``b8`` parameters are ``DigitalInOut`` objects, which -//| immediately get switched to input with a pull-up, and then scanned +//| immediately get switched to input with a pull-up, (unless they already +//| were set to pull-down, in which case they remain so), and then scanned //| regularly for button presses. The order is the same as the order of //| bits returned by the ``get_pressed`` function. You can re-initialize //| it with different keys, then the new object will replace the previous @@ -96,27 +96,24 @@ //| STATIC mp_obj_t gamepad_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - if (n_args > 8) { - mp_raise_TypeError(translate("too many arguments")); + if (n_args > 8 || n_args == 0) { + mp_raise_TypeError(translate("argument num/types mismatch")); } for (size_t i = 0; i < n_args; ++i) { - if (!MP_OBJ_IS_TYPE(args[i], &digitalio_digitalinout_type)) { - mp_raise_TypeError(translate("expected a DigitalInOut")); - } - digitalio_digitalinout_obj_t *pin = MP_OBJ_TO_PTR(args[i]); - raise_error_if_deinited( - common_hal_digitalio_digitalinout_deinited(pin)); + assert_digitalinout(args[i]); } - if (!MP_STATE_VM(gamepad_singleton)) { - gamepad_obj_t* gamepad_singleton = m_new_obj(gamepad_obj_t); + gamepad_obj_t* gamepad_singleton = MP_STATE_VM(gamepad_singleton); + if (!gamepad_singleton || + !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(gamepad_singleton), &gamepad_type)) { + gamepad_singleton = m_new_obj(gamepad_obj_t); gamepad_singleton->base.type = &gamepad_type; - MP_STATE_VM(gamepad_singleton) = gc_make_long_lived(gamepad_singleton); + gamepad_singleton = gc_make_long_lived(gamepad_singleton); + MP_STATE_VM(gamepad_singleton) = gamepad_singleton; } - gamepad_init(n_args, args); - return MP_OBJ_FROM_PTR(MP_STATE_VM(gamepad_singleton)); + common_hal_gamepad_gamepad_init(gamepad_singleton, args, n_args); + return MP_OBJ_FROM_PTR(gamepad_singleton); } - //| .. method:: get_pressed() //| //| Get the status of buttons pressed since the last call and clear it. @@ -129,9 +126,9 @@ STATIC mp_obj_t gamepad_make_new(const mp_obj_type_t *type, size_t n_args, //| STATIC mp_obj_t gamepad_get_pressed(mp_obj_t self_in) { gamepad_obj_t* gamepad_singleton = MP_STATE_VM(gamepad_singleton); - mp_obj_t gamepad = MP_OBJ_NEW_SMALL_INT(gamepad_singleton->pressed); - gamepad_singleton->pressed = 0; - return gamepad; + mp_obj_t pressed = MP_OBJ_NEW_SMALL_INT(gamepad_singleton->pressed); + gamepad_singleton->pressed = gamepad_singleton->last; + return pressed; } MP_DEFINE_CONST_FUN_OBJ_1(gamepad_get_pressed_obj, gamepad_get_pressed); @@ -141,7 +138,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(gamepad_get_pressed_obj, gamepad_get_pressed); //| Disable button scanning. //| STATIC mp_obj_t gamepad_deinit(mp_obj_t self_in) { - gamepad_reset(); + common_hal_gamepad_gamepad_deinit(self_in); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(gamepad_deinit_obj, gamepad_deinit); diff --git a/shared-bindings/gamepad/GamePad.h b/shared-bindings/gamepad/GamePad.h index 172c95ace..3bbad4c97 100644 --- a/shared-bindings/gamepad/GamePad.h +++ b/shared-bindings/gamepad/GamePad.h @@ -28,6 +28,11 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H #define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H +#include "shared-module/gamepad/GamePad.h" + extern const mp_obj_type_t gamepad_type; +void common_hal_gamepad_gamepad_init(gamepad_obj_t *gamepad, const mp_obj_t pins[], size_t n_pins); +void common_hal_gamepad_gamepad_deinit(gamepad_obj_t *gamepad); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD_GAMEPAD_H diff --git a/shared-bindings/gamepad/__init__.c b/shared-bindings/gamepad/__init__.c index 0c99d0d52..cea0b4ee9 100644 --- a/shared-bindings/gamepad/__init__.c +++ b/shared-bindings/gamepad/__init__.c @@ -26,8 +26,8 @@ #include "py/obj.h" #include "py/runtime.h" #include "py/mphal.h" -#include "GamePad.h" - +#include "shared-bindings/gamepad/GamePad.h" +#include "shared-bindings/util.h" //| :mod:`gamepad` --- Button handling //| ================================== diff --git a/shared-bindings/gamepad/__init__.h b/shared-bindings/gamepad/__init__.h new file mode 100644 index 000000000..2ae5efb3a --- /dev/null +++ b/shared-bindings/gamepad/__init__.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski 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_GAMEPAD___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD___INIT___H + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPAD___INIT___H diff --git a/shared-bindings/gamepadshift/GamePadShift.c b/shared-bindings/gamepadshift/GamePadShift.c new file mode 100644 index 000000000..91203ad20 --- /dev/null +++ b/shared-bindings/gamepadshift/GamePadShift.c @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski 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/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/gc.h" +#include "py/mpstate.h" +#include "shared-bindings/gamepadshift/GamePadShift.h" +#include "shared-bindings/gamepadshift/__init__.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: gamepadshift +//| +//| :class:`GamePadShift` -- Scan buttons for presses through a shift register +//| =========================================================================== +//| +//| .. class:: GamePadShift(clock, data, latch) +//| +//| Initializes button scanning routines. +//| +//| The ``clock``, ``data`` and ``latch`` parameters are ``DigitalInOut`` +//| objects connected to the shift register controlling the buttons. +//| +//| They button presses are accumulated, until the ``get_pressed`` method +//| is called, at which point the button state is cleared, and the new +//| button presses start to be recorded. +//| +//| Only one gamepad (`gamepad.GamePad` or `gamepadshift.GamePadShift`) +//| may be used at a time. +//| +STATIC mp_obj_t gamepadshift_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_clock, ARG_data, ARG_latch }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ}, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_latch, MP_ARG_REQUIRED | MP_ARG_OBJ}, + }; + 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); + + digitalio_digitalinout_obj_t *clock_pin = assert_digitalinout(args[ARG_clock].u_obj); + digitalio_digitalinout_obj_t *data_pin = assert_digitalinout(args[ARG_data].u_obj); + digitalio_digitalinout_obj_t *latch_pin = assert_digitalinout(args[ARG_latch].u_obj); + + gamepadshift_obj_t* gamepad_singleton = MP_STATE_VM(gamepad_singleton); + if (!gamepad_singleton || + !MP_OBJ_IS_TYPE(MP_OBJ_FROM_PTR(gamepad_singleton), + &gamepadshift_type)) { + gamepad_singleton = m_new_obj(gamepadshift_obj_t); + gamepad_singleton->base.type = &gamepadshift_type; + gamepad_singleton = gc_make_long_lived(gamepad_singleton); + MP_STATE_VM(gamepad_singleton) = gamepad_singleton; + } + common_hal_gamepadshift_gamepadshift_init(gamepad_singleton, clock_pin, data_pin, latch_pin); + return MP_OBJ_FROM_PTR(gamepad_singleton); +} + +//| .. method:: get_pressed() +//| +//| Get the status of buttons pressed since the last call and clear it. +//| +//| Returns an 8-bit number, with bits that correspond to buttons, +//| which have been pressed (or held down) since the last call to this +//| function set to 1, and the remaining bits set to 0. Then it clears +//| the button state, so that new button presses (or buttons that are +//| held down) can be recorded for the next call. +//| +STATIC mp_obj_t gamepadshift_get_pressed(mp_obj_t self_in) { + gamepadshift_obj_t* gamepad_singleton = MP_STATE_VM(gamepad_singleton); + mp_obj_t pressed = MP_OBJ_NEW_SMALL_INT(gamepad_singleton->pressed); + gamepad_singleton->pressed = gamepad_singleton->last; + return pressed; +} +MP_DEFINE_CONST_FUN_OBJ_1(gamepadshift_get_pressed_obj, gamepadshift_get_pressed); + +//| .. method:: deinit() +//| +//| Disable button scanning. +//| +STATIC mp_obj_t gamepadshift_deinit(mp_obj_t self_in) { + common_hal_gamepadshift_gamepadshift_deinit(self_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gamepadshift_deinit_obj, gamepadshift_deinit); + + +STATIC const mp_rom_map_elem_t gamepadshift_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_get_pressed), MP_ROM_PTR(&gamepadshift_get_pressed_obj)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gamepadshift_deinit_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gamepadshift_locals_dict, gamepadshift_locals_dict_table); +const mp_obj_type_t gamepadshift_type = { + { &mp_type_type }, + .name = MP_QSTR_GamePadShift, + .make_new = gamepadshift_make_new, + .locals_dict = (mp_obj_dict_t*)&gamepadshift_locals_dict, +}; diff --git a/shared-bindings/gamepadshift/GamePadShift.h b/shared-bindings/gamepadshift/GamePadShift.h new file mode 100644 index 000000000..3e8ea9693 --- /dev/null +++ b/shared-bindings/gamepadshift/GamePadShift.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski 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_GAMEPADSHIFT_GAMEPADSHIFT_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT_GAMEPADSHIFT_H + +#include "shared-module/gamepadshift/GamePadShift.h" + +extern const mp_obj_type_t gamepadshift_type; + +void common_hal_gamepadshift_gamepadshift_init(gamepadshift_obj_t *gamepadshift, + digitalio_digitalinout_obj_t *clock_pin, + digitalio_digitalinout_obj_t *data_pin, + digitalio_digitalinout_obj_t *latch_pin); + +void common_hal_gamepadshift_gamepadshift_deinit(gamepadshift_obj_t *gamepadshift); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT_GAMEPADSHIFT_H diff --git a/shared-bindings/gamepadshift/__init__.c b/shared-bindings/gamepadshift/__init__.c new file mode 100644 index 000000000..2d3667726 --- /dev/null +++ b/shared-bindings/gamepadshift/__init__.c @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Radomir Dopieralski 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/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-bindings/gamepadshift/GamePadShift.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/util.h" + +//| :mod:`gamepadshift` --- Tracks button presses read through a shift register +//| =========================================================================== +//| +//| .. module:: gamepadshift +//| :synopsis: Tracks button presses read through a shift register +//| :platform: SAMD21, SAMD51 +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| GamePadShift +//| +STATIC const mp_rom_map_elem_t gamepadshift_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gamepadshift) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GamePadShift), MP_ROM_PTR(&gamepadshift_type)}, +}; +STATIC MP_DEFINE_CONST_DICT(gamepadshift_module_globals, gamepadshift_module_globals_table); + +const mp_obj_module_t gamepadshift_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&gamepadshift_module_globals, +}; diff --git a/shared-bindings/bleio/Broadcaster.h b/shared-bindings/gamepadshift/__init__.h index 8aa125af9..4b4be756a 100644 --- a/shared-bindings/bleio/Broadcaster.h +++ b/shared-bindings/gamepadshift/__init__.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018 Artur Pacholec + * Copyright (c) 2016 Radomir Dopieralski 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 @@ -24,15 +24,8 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_BROADCASTER_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_BROADCASTER_H -#include "common-hal/bleio/Broadcaster.h" +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H -extern const mp_obj_type_t bleio_broadcaster_type; - -extern void common_hal_bleio_broadcaster_construct(bleio_broadcaster_obj_t *self, mp_float_t interval); -extern void common_hal_bleio_broadcaster_start_advertising(bleio_broadcaster_obj_t *self, mp_buffer_info_t *data); -extern void common_hal_bleio_broadcaster_stop_advertising(bleio_broadcaster_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_BROADCASTER_H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GAMEPADSHIFT___INIT___H diff --git a/shared-bindings/help.c b/shared-bindings/help.c index e0770ff3c..4e7c3a78b 100644 --- a/shared-bindings/help.c +++ b/shared-bindings/help.c @@ -27,7 +27,7 @@ //| :func:`help` - Built-in method to provide helpful information //| ============================================================== //| -//| .. method:: help(object=None) +//| .. function:: help(object=None) //| //| Prints a help method about the given object. When ``object`` is none, //| prints general port information. diff --git a/shared-bindings/i2cslave/I2CSlave.c b/shared-bindings/i2cslave/I2CSlave.c index 090a53581..2598accbb 100644 --- a/shared-bindings/i2cslave/I2CSlave.c +++ b/shared-bindings/i2cslave/I2CSlave.c @@ -150,7 +150,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cslave_i2c_slave___exit___obj, 4, 4 STATIC mp_obj_t i2cslave_i2c_slave_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cslave_i2c_slave_type)); i2cslave_i2c_slave_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_i2cslave_i2c_slave_deinited(self)); + if(common_hal_i2cslave_i2c_slave_deinited(self)) { + raise_deinited_error(); + } enum { ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, diff --git a/shared-bindings/index.rst b/shared-bindings/index.rst index 4f2e28702..cbffdb614 100644 --- a/shared-bindings/index.rst +++ b/shared-bindings/index.rst @@ -1,11 +1,11 @@ Core Modules ======================================== -These core modules are intended on being consistent across ports. Currently -they are only implemented in the SAMD21 and ESP8266 ports. A module may not exist -in a port if no underlying hardware support is present or if flash space is -limited. For example, a microcontroller without analog features will not have -`analogio`. +These core modules are intended on being consistent across ports and boards. +A module may not exist on a port/board if no underlying hardware support is +present or if flash space is limited. For example, a microcontroller without +analog features will not have `analogio`. See the `support_matrix` page for +a list of modules supported on each board. Modules --------- @@ -14,54 +14,6 @@ Modules :glob: :maxdepth: 3 + support_matrix */__init__ help - -.. _module-support-matrix: - -Support Matrix ---------------- -NOTE 1: **All Supported** means the following ports are supported: SAMD21, SAMD21 Express, -SAMD51, SAMD51 Express, and ESP8266. - -NOTE 2: **SAMD** and/or **SAMD Express** without additional numbers, means both SAMD21 & SAMD51 versions -are supported. - -NOTE 3: The `pIRkey SAMD21 board <https://www.adafruit.com/product/3364>`_ is specialized and may not -have modules as listed below. - -================= ============================== -Module Supported Ports -================= ============================== -`analogio` **All Supported** -`audiobusio` **SAMD/SAMD Express** -`audioio` **SAMD Express** -`binascii` **ESP8266** -`bitbangio` **SAMD Express, ESP8266** -`board` **All Supported** -`bleio` **nRF** -`busio` **All Supported** -`digitalio` **All Supported** -`frequencyio` **SAMD51** -`gamepad` **SAMD Express, nRF** -`hashlib` **ESP8266** -`i2cslave` **SAMD Express** -`math` **All Supported** -`microcontroller` **All Supported** -`multiterminal` **ESP8266** -`neopixel_write` **All Supported** -`nvm` **SAMD Express** -`os` **All Supported** -`pulseio` **SAMD/SAMD Express** -`random` **All Supported** -`rotaryio` **SAMD51, SAMD Express** -`storage` **All Supported** -`struct` **All Supported** -`supervisor` **SAMD/SAMD Express** -`time` **All Supported** -`touchio` **SAMD/SAMD Express** -`uheap` **Debug (All)** -`usb_hid` **SAMD/SAMD Express** -`_pixelbuf` **SAMD Express** -`_stage` **SAMD/SAMD Express** -================= ============================== diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index e79663107..3635f0afb 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -40,7 +40,7 @@ //| //| Identifies an IO pin on the microcontroller. //| -//| .. class:: Pin +//| .. class:: Pin() //| //| Identifies an IO pin on the microcontroller. They are fixed by the //| hardware so they cannot be constructed on demand. Instead, use diff --git a/shared-bindings/microcontroller/RunMode.c b/shared-bindings/microcontroller/RunMode.c index 7c3f84fca..913242ad2 100644 --- a/shared-bindings/microcontroller/RunMode.c +++ b/shared-bindings/microcontroller/RunMode.c @@ -31,24 +31,30 @@ //| :class:`RunMode` -- run state of the microcontroller //| ============================================================= //| -//| .. class:: microcontroller.RunMode +//| .. class:: RunMode() //| //| Enum-like class to define the run mode of the microcontroller and //| CircuitPython. //| -//| .. data:: NORMAL +//| .. attribute:: NORMAL //| //| Run CircuitPython as normal. //| -//| .. data:: SAFE_MODE +//| :type microcontroller.RunMode: +//| +//| .. attribute:: SAFE_MODE //| //| Run CircuitPython in safe mode. User code will not be run and the //| file system will be writeable over USB. //| -//| .. data:: BOOTLOADER +//| :type microcontroller.RunMode: +//| +//| .. attribute:: BOOTLOADER //| //| Run the bootloader. //| +//| :type microcontroller.RunMode: +//| const mp_obj_type_t mcu_runmode_type; const mcu_runmode_obj_t mcu_runmode_normal_obj = { diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c index da8d0bd94..090c4564d 100644 --- a/shared-bindings/microcontroller/__init__.c +++ b/shared-bindings/microcontroller/__init__.c @@ -62,14 +62,14 @@ //| RunMode //| -//| .. attribute:: cpu +//| .. data:: cpu //| //| CPU information and control, such as ``cpu.temperature`` and ``cpu.frequency`` //| (clock frequency). //| This object is the sole instance of `microcontroller.Processor`. //| -//| .. method:: delay_us(delay) +//| .. function:: delay_us(delay) //| //| Dedicated delay method used for very short delays. **Do not** do long delays //| because this stops all other functions from completing. Think of this as an empty @@ -87,7 +87,7 @@ STATIC mp_obj_t mcu_delay_us(mp_obj_t delay_obj) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_delay_us_obj, mcu_delay_us); -//| .. method:: disable_interrupts() +//| .. function:: disable_interrupts() //| //| Disable all interrupts. Be very careful, this can stall everything. //| @@ -97,7 +97,7 @@ STATIC mp_obj_t mcu_disable_interrupts(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_disable_interrupts_obj, mcu_disable_interrupts); -//| .. method:: enable_interrupts() +//| .. function:: enable_interrupts() //| //| Enable the interrupts that were enabled at the last disable. //| @@ -107,7 +107,7 @@ STATIC mp_obj_t mcu_enable_interrupts(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts); -//| .. method:: on_next_reset(run_mode) +//| .. function:: on_next_reset(run_mode) //| //| Configure the run mode used the next time the microcontroller is reset but //| not powered down. @@ -132,7 +132,7 @@ STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset); -//| .. method:: reset() +//| .. function:: reset() //| //| Reset the microcontroller. After reset, the microcontroller will enter the //| run mode last set by `on_next_reset`. @@ -148,11 +148,13 @@ STATIC mp_obj_t mcu_reset(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset); -//| .. attribute:: nvm +//| .. data:: nvm //| //| Available non-volatile memory. //| This object is the sole instance of `nvm.ByteArray` when available or ``None`` otherwise. //| +//| :type: nvm.ByteArray or None +//| //| :mod:`microcontroller.pin` --- Microcontroller pin names //| -------------------------------------------------------- diff --git a/shared-bindings/neopixel_write/__init__.c b/shared-bindings/neopixel_write/__init__.c index 05d6fd97a..1ee66337b 100644 --- a/shared-bindings/neopixel_write/__init__.c +++ b/shared-bindings/neopixel_write/__init__.c @@ -55,11 +55,11 @@ //| pixel_off = bytearray([0, 0, 0]) //| neopixel_write.neopixel_write(pin, pixel_off) //| -//| .. method:: neopixel_write.neopixel_write(digitalinout, buf) +//| .. function:: neopixel_write(digitalinout, buf) //| //| Write buf out on the given DigitalInOut. //| -//| :param ~digitalio.DigitalInOut gpio: the DigitalInOut to output with +//| :param ~digitalio.DigitalInOut digitalinout: the DigitalInOut to output with //| :param bytearray buf: The bytes to clock out. No assumption is made about color order //| STATIC mp_obj_t neopixel_write_neopixel_write_(mp_obj_t digitalinout_obj, mp_obj_t buf) { diff --git a/shared-bindings/network/__init__.c b/shared-bindings/network/__init__.c index 1067ea549..01763a73c 100644 --- a/shared-bindings/network/__init__.c +++ b/shared-bindings/network/__init__.c @@ -49,7 +49,7 @@ //| It is used by the 'socket' module to look up a suitable //| NIC when a socket is created. //| -//| .. function:: route +//| .. function:: route() //| //| Returns a list of all configured NICs. //| diff --git a/shared-bindings/nvm/ByteArray.c b/shared-bindings/nvm/ByteArray.c index 22cd838b1..31bedeacc 100644 --- a/shared-bindings/nvm/ByteArray.c +++ b/shared-bindings/nvm/ByteArray.c @@ -124,7 +124,8 @@ STATIC mp_obj_t nvm_bytearray_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj #endif } else { // Single index rather than slice. - size_t index = mp_get_index(self->base.type, self->len, index_in, false); + size_t index = mp_get_index(self->base.type, common_hal_nvm_bytearray_get_length(self), + index_in, false); if (value == MP_OBJ_SENTINEL) { // load uint8_t value_out; diff --git a/shared-bindings/ps2io/Ps2.c b/shared-bindings/ps2io/Ps2.c new file mode 100644 index 000000000..fb5c24b85 --- /dev/null +++ b/shared-bindings/ps2io/Ps2.c @@ -0,0 +1,243 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/ps2io/Ps2.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| .. currentmodule:: ps2io +//| +//| :class:`Ps2` -- Communicate with a PS/2 keyboard or mouse +//| ========================================================= +//| +//| Ps2 implements the PS/2 keyboard/mouse serial protocol, used in +//| legacy devices. It is similar to UART but there are only two +//| lines (Data and Clock). PS/2 devices are 5V, so bidirectional +//| level converters must be used to connect the I/O lines to pins +//| of 3.3V boards. +//| +//| .. class:: Ps2(data_pin, clock_pin) +//| +//| Create a Ps2 object associated with the given pins. +//| +//| :param ~microcontroller.Pin data_pin: Pin tied to data wire. +//| :param ~microcontroller.Pin clock_pin: Pin tied to clock wire. +//| This pin must support interrupts. +//| +//| Read one byte from PS/2 keyboard and turn on Scroll Lock LED:: +//| +//| import ps2io +//| import board +//| +//| kbd = ps2io.Ps2(board.D10, board.D11) +//| +//| while len(kbd) == 0: +//| pass +//| +//| print(kbd.popleft()) +//| print(kbd.sendcmd(0xed)) +//| print(kbd.sendcmd(0x01)) +//| +STATIC mp_obj_t ps2io_ps2_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_datapin, ARG_clkpin }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_datapin, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_clkpin, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + 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); + assert_pin(args[ARG_clkpin].u_obj, false); + assert_pin(args[ARG_datapin].u_obj, false); + const mcu_pin_obj_t* clkpin = MP_OBJ_TO_PTR(args[ARG_clkpin].u_obj); + assert_pin_free(clkpin); + const mcu_pin_obj_t* datapin = MP_OBJ_TO_PTR(args[ARG_datapin].u_obj); + assert_pin_free(datapin); + + ps2io_ps2_obj_t *self = m_new_obj(ps2io_ps2_obj_t); + self->base.type = &ps2io_ps2_type; + + common_hal_ps2io_ps2_construct(self, datapin, clkpin); + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialises the Ps2 and releases any hardware resources for reuse. +//| +STATIC mp_obj_t ps2io_ps2_deinit(mp_obj_t self_in) { + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_ps2io_ps2_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_deinit_obj, ps2io_ps2_deinit); + +STATIC void check_for_deinit(ps2io_ps2_obj_t *self) { + if (common_hal_ps2io_ps2_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 ps2io_ps2_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_ps2io_ps2_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ps2io_ps2___exit___obj, 4, 4, ps2io_ps2_obj___exit__); + +//| .. method:: popleft() +//| +//| Removes and returns the oldest received byte. When buffer +//| is empty, raises an IndexError exception. +//| +STATIC mp_obj_t ps2io_ps2_obj_popleft(mp_obj_t self_in) { + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + int b = common_hal_ps2io_ps2_popleft(self); + if (b < 0) { + mp_raise_IndexError(translate("Pop from an empty Ps2 buffer")); + } + return MP_OBJ_NEW_SMALL_INT(b); +} +MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_popleft_obj, ps2io_ps2_obj_popleft); + +//| .. method:: sendcmd(byte) +//| +//| Sends a command byte to PS/2. Returns the response byte, typically +//| the general ack value (0xFA). Some commands return additional data +//| which is available through :py:func:`popleft()`. +//| +//| Raises a RuntimeError in case of failure. The root cause can be found +//| by calling :py:func:`clear_errors()`. It is advisable to call +//| :py:func:`clear_errors()` before :py:func:`sendcmd()` to flush any +//| previous errors. +//| +//| :param int byte: byte value of the command +//| +STATIC mp_obj_t ps2io_ps2_obj_sendcmd(mp_obj_t self_in, mp_obj_t ob) { + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + mp_int_t cmd = mp_obj_get_int(ob) & 0xff; + int resp = common_hal_ps2io_ps2_sendcmd(self, cmd); + if (resp < 0) { + mp_raise_RuntimeError(translate("Failed sending command.")); + } + return MP_OBJ_NEW_SMALL_INT(resp); +} +MP_DEFINE_CONST_FUN_OBJ_2(ps2io_ps2_sendcmd_obj, ps2io_ps2_obj_sendcmd); + +//| .. method:: clear_errors() +//| +//| Returns and clears a bitmap with latest recorded communication errors. +//| +//| Reception errors (arise asynchronously, as data is received): +//| +//| 0x01: start bit not 0 +//| +//| 0x02: timeout +//| +//| 0x04: parity bit error +//| +//| 0x08: stop bit not 1 +//| +//| 0x10: buffer overflow, newest data discarded +//| +//| Transmission errors (can only arise in the course of sendcmd()): +//| +//| 0x100: clock pin didn't go to LO in time +//| +//| 0x200: clock pin didn't go to HI in time +//| +//| 0x400: data pin didn't ACK +//| +//| 0x800: clock pin didn't ACK +//| +//| 0x1000: device didn't respond to RTS +//| +//| 0x2000: device didn't send a response byte in time +//| +STATIC mp_obj_t ps2io_ps2_obj_clear_errors(mp_obj_t self_in) { + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + return MP_OBJ_NEW_SMALL_INT(common_hal_ps2io_ps2_clear_errors(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(ps2io_ps2_clear_errors_obj, ps2io_ps2_obj_clear_errors); + +//| .. method:: __len__() +//| +//| Returns the number of received bytes in buffer, available +//| to :py:func:`popleft()`. +//| +STATIC mp_obj_t ps2_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + uint16_t len = common_hal_ps2io_ps2_get_len(self); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); + default: return MP_OBJ_NULL; // op not supported + } +} + +STATIC const mp_rom_map_elem_t ps2io_ps2_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&ps2io_ps2_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&ps2io_ps2___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_popleft), MP_ROM_PTR(&ps2io_ps2_popleft_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendcmd), MP_ROM_PTR(&ps2io_ps2_sendcmd_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_errors), MP_ROM_PTR(&ps2io_ps2_clear_errors_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(ps2io_ps2_locals_dict, ps2io_ps2_locals_dict_table); + +const mp_obj_type_t ps2io_ps2_type = { + { &mp_type_type }, + .name = MP_QSTR_Ps2, + .make_new = ps2io_ps2_make_new, + .unary_op = ps2_unary_op, + .locals_dict = (mp_obj_dict_t*)&ps2io_ps2_locals_dict, +}; diff --git a/shared-bindings/ps2io/Ps2.h b/shared-bindings/ps2io/Ps2.h new file mode 100644 index 000000000..523869d55 --- /dev/null +++ b/shared-bindings/ps2io/Ps2.h @@ -0,0 +1,45 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co> + * + * 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_PS2IO_PS2_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO_PS2_H + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/ps2io/Ps2.h" + +extern const mp_obj_type_t ps2io_ps2_type; + +extern void common_hal_ps2io_ps2_construct(ps2io_ps2_obj_t* self, + const mcu_pin_obj_t* data_pin, const mcu_pin_obj_t* clk_pin); +extern void common_hal_ps2io_ps2_deinit(ps2io_ps2_obj_t* self); +extern bool common_hal_ps2io_ps2_deinited(ps2io_ps2_obj_t* self); +extern uint16_t common_hal_ps2io_ps2_get_len(ps2io_ps2_obj_t* self); +extern int16_t common_hal_ps2io_ps2_popleft(ps2io_ps2_obj_t* self); +extern int16_t common_hal_ps2io_ps2_sendcmd(ps2io_ps2_obj_t* self, uint8_t b); +extern uint16_t common_hal_ps2io_ps2_clear_errors(ps2io_ps2_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO_PS2_H diff --git a/shared-bindings/ps2io/__init__.c b/shared-bindings/ps2io/__init__.c new file mode 100644 index 000000000..ec7c43e51 --- /dev/null +++ b/shared-bindings/ps2io/__init__.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/ps2io/Ps2.h" + +//| :mod:`ps2io` --- Support for PS/2 protocol +//| ===================================================== +//| +//| .. module:: ps2io +//| :synopsis: Support for PS/2 based devices +//| :platform: SAMD21 +//| +//| The `ps2io` module contains classes to provide PS/2 communication. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| Ps2 +//| + +//| .. warning:: This module is not available in some SAMD21 builds. See the +//| :ref:`module-support-matrix` for more info. +//| + +//| 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. +//| + +STATIC const mp_rom_map_elem_t ps2io_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ps2io) }, + { MP_ROM_QSTR(MP_QSTR_Ps2), MP_ROM_PTR(&ps2io_ps2_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ps2io_module_globals, ps2io_module_globals_table); + +const mp_obj_module_t ps2io_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&ps2io_module_globals, +}; diff --git a/shared-bindings/ps2io/__init__.h b/shared-bindings/ps2io/__init__.h new file mode 100644 index 000000000..1ff3d97b5 --- /dev/null +++ b/shared-bindings/ps2io/__init__.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * Copyright (c) 2019 Elvis Pfutzenreuter <epxx@epxx.co> + * + * 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_PS2IO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PS2IO___INIT___H diff --git a/shared-bindings/pulseio/PWMOut.c b/shared-bindings/pulseio/PWMOut.c index bba5fe883..40981e0a8 100644 --- a/shared-bindings/pulseio/PWMOut.c +++ b/shared-bindings/pulseio/PWMOut.c @@ -42,7 +42,7 @@ //| //| PWMOut can be used to output a PWM signal on a given pin. //| -//| .. class:: PWMOut(pin, \*, duty_cycle=0, frequency=500, variable_frequency=False) +//| .. class:: PWMOut(pin, *, duty_cycle=0, frequency=500, variable_frequency=False) //| //| Create a PWM object associated with the given pin. This allows you to //| write PWM signals out on the given pin. Frequency is fixed after init @@ -103,7 +103,7 @@ STATIC mp_obj_t pulseio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args uint16_t duty_cycle = parsed_args[ARG_duty_cycle].u_int; uint32_t frequency = parsed_args[ARG_frequency].u_int; - bool variable_frequency = parsed_args[ARG_variable_frequency].u_int; + bool variable_frequency = parsed_args[ARG_variable_frequency].u_bool; // create PWM object from the given pin pulseio_pwmout_obj_t *self = m_new_obj(pulseio_pwmout_obj_t); @@ -133,6 +133,12 @@ STATIC mp_obj_t pulseio_pwmout_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_deinit_obj, pulseio_pwmout_deinit); +STATIC void check_for_deinit(pulseio_pwmout_obj_t *self) { + if (common_hal_pulseio_pwmout_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -158,14 +164,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pwmout___exit___obj, 4, 4, pu //| be half high and then half low. STATIC mp_obj_t pulseio_pwmout_obj_get_duty_cycle(mp_obj_t self_in) { pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pwmout_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pwmout_get_duty_cycle(self)); } MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_get_duty_cycle_obj, pulseio_pwmout_obj_get_duty_cycle); STATIC mp_obj_t pulseio_pwmout_obj_set_duty_cycle(mp_obj_t self_in, mp_obj_t duty_cycle) { pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pwmout_deinited(self)); + check_for_deinit(self); mp_int_t duty = mp_obj_get_int(duty_cycle); if (duty < 0 || duty > 0xffff) { mp_raise_ValueError(translate("PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)")); @@ -189,14 +195,14 @@ const mp_obj_property_t pulseio_pwmout_duty_cycle_obj = { //| STATIC mp_obj_t pulseio_pwmout_obj_get_frequency(mp_obj_t self_in) { pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pwmout_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pwmout_get_frequency(self)); } MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_get_frequency_obj, pulseio_pwmout_obj_get_frequency); STATIC mp_obj_t pulseio_pwmout_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency) { pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pwmout_deinited(self)); + check_for_deinit(self); if (!common_hal_pulseio_pwmout_get_variable_frequency(self)) { mp_raise_AttributeError(translate( "PWM frequency not writable when variable_frequency is False on " diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c index 426ac4384..8b69109f0 100644 --- a/shared-bindings/pulseio/PulseIn.c +++ b/shared-bindings/pulseio/PulseIn.c @@ -45,7 +45,7 @@ //| The pulsed signal consists of timed active and idle periods. Unlike PWM, //| there is no set duration for active and idle pairs. //| -//| .. class:: PulseIn(pin, maxlen=2, \*, idle_state=False) +//| .. class:: PulseIn(pin, maxlen=2, *, idle_state=False) //| //| Create a PulseIn object associated with the given pin. The object acts as //| a read-only sequence of pulse lengths with a given max length. When it is @@ -114,6 +114,12 @@ STATIC mp_obj_t pulseio_pulsein_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_deinit_obj, pulseio_pulsein_deinit); +STATIC void check_for_deinit(pulseio_pulsein_obj_t *self) { + if (common_hal_pulseio_pulsein_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -138,7 +144,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pulsein___exit___obj, 4, 4, p //| STATIC mp_obj_t pulseio_pulsein_obj_pause(mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); common_hal_pulseio_pulsein_pause(self); return mp_const_none; @@ -162,7 +168,7 @@ STATIC mp_obj_t pulseio_pulsein_obj_resume(size_t n_args, const mp_obj_t *pos_ar { MP_QSTR_trigger_duration, MP_ARG_INT, {.u_int = 0} }, }; pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + 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); @@ -178,7 +184,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(pulseio_pulsein_resume_obj, 1, pulseio_pulsein_obj_re //| STATIC mp_obj_t pulseio_pulsein_obj_clear(mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); common_hal_pulseio_pulsein_clear(self); return mp_const_none; @@ -191,7 +197,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_clear_obj, pulseio_pulsein_obj_clear); //| STATIC mp_obj_t pulseio_pulsein_obj_popleft(mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pulsein_popleft(self)); } @@ -204,7 +210,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pulsein_popleft_obj, pulseio_pulsein_obj_pople //| STATIC mp_obj_t pulseio_pulsein_obj_get_maxlen(mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pulsein_get_maxlen(self)); } @@ -224,7 +230,7 @@ const mp_obj_property_t pulseio_pulsein_maxlen_obj = { //| STATIC mp_obj_t pulseio_pulsein_obj_get_paused(mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_pulseio_pulsein_get_paused(self)); } @@ -248,7 +254,7 @@ const mp_obj_property_t pulseio_pulsein_paused_obj = { //| STATIC mp_obj_t pulsein_unary_op(mp_unary_op_t op, mp_obj_t self_in) { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); uint16_t len = common_hal_pulseio_pulsein_get_len(self); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); @@ -272,7 +278,7 @@ STATIC mp_obj_t pulsein_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t va mp_raise_AttributeError(translate("Cannot delete values")); } else { pulseio_pulsein_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulsein_deinited(self)); + check_for_deinit(self); if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { mp_raise_NotImplementedError(translate("Slices not supported")); diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 493b7e2ff..172459e5d 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -127,7 +127,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pulseout___exit___obj, 4, 4, //| STATIC mp_obj_t pulseio_pulseout_obj_send(mp_obj_t self_in, mp_obj_t pulses) { pulseio_pulseout_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_pulseio_pulseout_deinited(self)); + if (common_hal_pulseio_pulseout_deinited(self)) { + raise_deinited_error(); + } mp_buffer_info_t bufinfo; mp_get_buffer_raise(pulses, &bufinfo, MP_BUFFER_READ); diff --git a/shared-bindings/pulseio/__init__.c b/shared-bindings/pulseio/__init__.c index 1114b604b..a3cec3dca 100644 --- a/shared-bindings/pulseio/__init__.c +++ b/shared-bindings/pulseio/__init__.c @@ -54,10 +54,6 @@ //| PWMOut //| -//| .. warning:: This module is not available in some SAMD21 builds. See the -//| :ref:`module-support-matrix` for more info. -//| - //| 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 diff --git a/shared-bindings/rotaryio/IncrementalEncoder.c b/shared-bindings/rotaryio/IncrementalEncoder.c index 5d2264ffc..f2f157847 100644 --- a/shared-bindings/rotaryio/IncrementalEncoder.c +++ b/shared-bindings/rotaryio/IncrementalEncoder.c @@ -100,6 +100,12 @@ STATIC mp_obj_t rotaryio_incrementalencoder_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_deinit_obj, rotaryio_incrementalencoder_deinit); +STATIC void check_for_deinit(rotaryio_incrementalencoder_obj_t *self) { + if (common_hal_rotaryio_incrementalencoder_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -126,7 +132,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(rotaryio_incrementalencoder___exit___ //| STATIC mp_obj_t rotaryio_incrementalencoder_obj_get_position(mp_obj_t self_in) { rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_rotaryio_incrementalencoder_deinited(self)); + check_for_deinit(self); return mp_obj_new_int(common_hal_rotaryio_incrementalencoder_get_position(self)); } @@ -134,7 +140,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(rotaryio_incrementalencoder_get_position_obj, rotaryio STATIC mp_obj_t rotaryio_incrementalencoder_obj_set_position(mp_obj_t self_in, mp_obj_t new_position) { rotaryio_incrementalencoder_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_rotaryio_incrementalencoder_deinited(self)); + check_for_deinit(self); common_hal_rotaryio_incrementalencoder_set_position(self, mp_obj_get_int(new_position)); return mp_const_none; diff --git a/shared-bindings/rtc/RTC.c b/shared-bindings/rtc/RTC.c index 474d4a399..17dccdb03 100644 --- a/shared-bindings/rtc/RTC.c +++ b/shared-bindings/rtc/RTC.c @@ -36,22 +36,6 @@ #include "shared-bindings/time/__init__.h" #include "supervisor/shared/translate.h" -void MP_WEAK common_hal_rtc_get_time(timeutils_struct_time_t *tm) { - mp_raise_NotImplementedError(translate("RTC is not supported on this board")); -} - -void MP_WEAK common_hal_rtc_set_time(timeutils_struct_time_t *tm) { - mp_raise_NotImplementedError(translate("RTC is not supported on this board")); -} - -int MP_WEAK common_hal_rtc_get_calibration(void) { - return 0; -} - -void MP_WEAK common_hal_rtc_set_calibration(int calibration) { - mp_raise_NotImplementedError(translate("RTC calibration is not supported on this board")); -} - const rtc_rtc_obj_t rtc_rtc_obj = {{&rtc_rtc_type}}; //| .. currentmodule:: rtc diff --git a/shared-bindings/socket/__init__.c b/shared-bindings/socket/__init__.c index 29d47de56..6d04a9893 100644 --- a/shared-bindings/socket/__init__.c +++ b/shared-bindings/socket/__init__.c @@ -51,7 +51,7 @@ STATIC const mp_obj_type_t socket_type; //| .. currentmodule:: socket //| -//| .. class:: socket(family, type, proto, ...) +//| .. class:: socket(family, type, proto) //| //| Create a new socket //| @@ -240,6 +240,53 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +// helper function for socket_recv and socket_recv_into to handle common operations of both +STATIC mp_int_t _socket_recv_into(mod_network_socket_obj_t *sock, byte *buf, mp_int_t len) { + int _errno; + mp_int_t ret = sock->nic_type->recv(sock, buf, len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + return ret; +} + + +//| .. method:: recv_into(buffer[, bufsize]) +//| +//| Reads some bytes from the connected remote address, writing +//| into the provided buffer. If bufsize <= len(buffer) is given, +//| a maximum of bufsize bytes will be read into the buffer. If no +//| valid value is given for bufsize, the default is the length of +//| the given buffer. +//| +//| Suits sockets of type SOCK_STREAM +//| Returns an int of number of bytes read. +//| +//| :param bytearray buffer: buffer to receive into +//| :param int bufsize: optionally, a maximum number of bytes to read. + +STATIC mp_obj_t socket_recv_into(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + mp_int_t len = bufinfo.len; + if (n_args == 3) { + mp_int_t given_len = mp_obj_get_int(args[2]); + if (given_len < len) { + len = given_len; + } + } + + mp_int_t ret = _socket_recv_into(self, (byte*)bufinfo.buf, len); + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_into_obj, 2, 3, socket_recv_into); + //| .. method:: recv(bufsize) //| //| Reads some bytes from the connected remote address. @@ -257,11 +304,7 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t len = mp_obj_get_int(len_in); vstr_t vstr; vstr_init_len(&vstr, len); - int _errno; - mp_int_t ret = self->nic_type->recv(self, (byte*)vstr.buf, len, &_errno); - if (ret == -1) { - mp_raise_OSError(_errno); - } + mp_int_t ret = _socket_recv_into(self, (byte*)vstr.buf, len); if (ret == 0) { return mp_const_empty_bytes; } @@ -436,6 +479,7 @@ STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socket_recv_into_obj) }, { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 4db3a9fec..ba439b951 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -48,7 +48,7 @@ //| directly. //| -//| .. function:: mount(filesystem, mount_path, \*, readonly=False) +//| .. function:: mount(filesystem, mount_path, *, readonly=False) //| //| Mounts the given filesystem object at the given path. //| @@ -183,7 +183,7 @@ STATIC const mp_rom_map_elem_t storage_module_globals_table[] = { //| this property can only be set when the device is writable by the //| microcontroller. //| - //| .. method:: mkfs + //| .. method:: mkfs() //| //| Format the block device, deleting any data that may have been there //| @@ -216,7 +216,7 @@ STATIC const mp_rom_map_elem_t storage_module_globals_table[] = { //| //| Don't call this directly, call `storage.mount`. //| - //| .. method:: umount + //| .. method:: umount() //| //| Don't call this directly, call `storage.umount`. //| diff --git a/shared-bindings/struct/__init__.c b/shared-bindings/struct/__init__.c index 9240a15bb..ea14b3763 100644 --- a/shared-bindings/struct/__init__.c +++ b/shared-bindings/struct/__init__.c @@ -67,9 +67,9 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { } MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize); -//| .. function:: pack(fmt, v1, v2, ...) +//| .. function:: pack(fmt, *values) //| -//| Pack the values v1, v2, ... according to the format string fmt. +//| Pack the values according to the format string fmt. //| The return value is a bytes object encoding the values. //| @@ -85,9 +85,9 @@ STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack); -//| .. function:: pack_into(fmt, buffer, offset, v1, v2, ...) +//| .. function:: pack_into(fmt, buffer, offset, *values) //| -//| Pack the values v1, v2, ... according to the format string fmt into a buffer +//| Pack the values according to the format string fmt into a buffer //| starting at offset. offset may be negative to count from the end of buffer. //| diff --git a/shared-bindings/support_matrix.rst b/shared-bindings/support_matrix.rst new file mode 100644 index 000000000..124f3a810 --- /dev/null +++ b/shared-bindings/support_matrix.rst @@ -0,0 +1,16 @@ +.. _module-support-matrix: + +Support Matrix +=============== + +The following table lists the available built-in modules for each CircuitPython +capable board. + +.. csv-table:: + :header-rows: 1 + :widths: 7, 50 + + "Board", "Modules Available" + {% for key, value in support_matrix|dictsort -%} + "{{ key }}", "{{ '`' ~ value|join("`, `") ~ '`' }}" + {% endfor -%} diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index e3822d858..cdde672d3 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -34,7 +34,7 @@ #include "py/objstr.h" #include "py/runtime.h" #include "py/stream.h" -#include "shared-bindings/displayio/BuiltinFont.h" +#include "shared-bindings/fontio/BuiltinFont.h" #include "supervisor/shared/translate.h" @@ -46,7 +46,7 @@ //| .. class:: Terminal(tilegrid, font) //| //| Terminal manages tile indices and cursor position based on VT100 commands. The font should be -//| a `displayio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap. +//| a `fontio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap. //| STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -64,8 +64,8 @@ STATIC mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n } mp_obj_t font = args[ARG_font].u_obj; - if (!MP_OBJ_IS_TYPE(font, &displayio_builtinfont_type)) { - mp_raise_TypeError_varg(translate("Expected a %q"), displayio_builtinfont_type.name); + if (!MP_OBJ_IS_TYPE(font, &fontio_builtinfont_type)) { + mp_raise_TypeError_varg(translate("Expected a %q"), fontio_builtinfont_type.name); } terminalio_terminal_obj_t *self = m_new_obj(terminalio_terminal_obj_t); self->base.type = &terminalio_terminal_type; diff --git a/shared-bindings/terminalio/Terminal.h b/shared-bindings/terminalio/Terminal.h index a5dadac89..7ae0bf1b0 100644 --- a/shared-bindings/terminalio/Terminal.h +++ b/shared-bindings/terminalio/Terminal.h @@ -34,7 +34,7 @@ extern const mp_obj_type_t terminalio_terminal_type; extern void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, - displayio_tilegrid_t* tilegrid, const displayio_builtinfont_t* font); + displayio_tilegrid_t* tilegrid, const fontio_builtinfont_t* font); // Write characters. len is in characters NOT bytes! extern size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 3babe2db4..70c01c2d8 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -47,7 +47,7 @@ //| written in MicroPython will work in CPython but not necessarily the other //| way around. //| -//| .. method:: monotonic() +//| .. function:: monotonic() //| //| Returns an always increasing value of time with an unknown reference //| point. Only use it to compare against other values from `monotonic`. @@ -62,7 +62,7 @@ STATIC mp_obj_t time_monotonic(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_obj, time_monotonic); -//| .. method:: sleep(seconds) +//| .. function:: sleep(seconds) //| //| Sleep for a given number of seconds. //| @@ -95,19 +95,20 @@ mp_obj_t struct_time_make_new(const mp_obj_type_t *type, size_t n_args, const mp return namedtuple_make_new(type, 9, tuple->items, NULL); } -//| .. class:: struct_time((tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)) +//| .. class:: struct_time(time_tuple) //| //| Structure used to capture a date and time. Note that it takes a tuple! //| -//| :param int tm_year: the year, 2017 for example -//| :param int tm_mon: the month, range [1, 12] -//| :param int tm_mday: the day of the month, range [1, 31] -//| :param int tm_hour: the hour, range [0, 23] -//| :param int tm_min: the minute, range [0, 59] -//| :param int tm_sec: the second, range [0, 61] -//| :param int tm_wday: the day of the week, range [0, 6], Monday is 0 -//| :param int tm_yday: the day of the year, range [1, 366], -1 indicates not known -//| :param int tm_isdst: 1 when in daylight savings, 0 when not, -1 if unknown. +//| :param Tuple[tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst] time_tuple: Tuple of time info. +//| * the year, 2017 for example +//| * the month, range [1, 12] +//| * the day of the month, range [1, 31] +//| * the hour, range [0, 23] +//| * the minute, range [0, 59] +//| * the second, range [0, 61] +//| * the day of the week, range [0, 6], Monday is 0 +//| * the day of the year, range [1, 366], -1 indicates not known +//| * 1 when in daylight savings, 0 when not, -1 if unknown. //| const mp_obj_namedtuple_type_t struct_time_type_obj = { .base = { @@ -190,7 +191,7 @@ mp_obj_t MP_WEAK rtc_get_time_source_time(void) { mp_raise_RuntimeError(translate("RTC is not supported on this board")); } -//| .. method:: time() +//| .. function:: time() //| //| Return the current time in seconds since since Jan 1, 1970. //| @@ -206,7 +207,7 @@ STATIC mp_obj_t time_time(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); -//| .. method:: monotonic_ns() +//| .. function:: monotonic_ns() //| //| Return the time of the specified clock clk_id in nanoseconds. //| @@ -219,7 +220,7 @@ STATIC mp_obj_t time_monotonic_ns(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_ns_obj, time_monotonic_ns); -//| .. method:: localtime([secs]) +//| .. function:: localtime([secs]) //| //| Convert a time expressed in seconds since Jan 1, 1970 to a struct_time in //| local time. If secs is not provided or None, the current time as returned @@ -245,7 +246,7 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); -//| .. method:: mktime(t) +//| .. function:: mktime(t) //| //| This is the inverse function of localtime(). Its argument is the //| struct_time or full 9-tuple (since the dst flag is needed; use -1 as the diff --git a/shared-bindings/touchio/TouchIn.c b/shared-bindings/touchio/TouchIn.c index 3b26aca8c..78fceef41 100644 --- a/shared-bindings/touchio/TouchIn.c +++ b/shared-bindings/touchio/TouchIn.c @@ -88,6 +88,12 @@ STATIC mp_obj_t touchio_touchin_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_deinit_obj, touchio_touchin_deinit); +STATIC void check_for_deinit(touchio_touchin_obj_t *self) { + if (common_hal_touchio_touchin_deinited(self)) { + raise_deinited_error(); + } +} + //| .. method:: __enter__() //| //| No-op used by Context Managers. @@ -114,7 +120,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(touchio_touchin___exit___obj, 4, 4, t //| STATIC mp_obj_t touchio_touchin_obj_get_value(mp_obj_t self_in) { touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_touchio_touchin_deinited(self)); + check_for_deinit(self); return mp_obj_new_bool(common_hal_touchio_touchin_get_value(self)); } MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_get_value_obj, touchio_touchin_obj_get_value); @@ -133,7 +139,7 @@ const mp_obj_property_t touchio_touchin_value_obj = { //| STATIC mp_obj_t touchio_touchin_obj_get_raw_value(mp_obj_t self_in) { touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_touchio_touchin_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_touchio_touchin_get_raw_value(self)); } @@ -158,7 +164,7 @@ const mp_obj_property_t touchio_touchin_raw_value_obj = { //| STATIC mp_obj_t touchio_touchin_obj_get_threshold(mp_obj_t self_in) { touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_touchio_touchin_deinited(self)); + check_for_deinit(self); return MP_OBJ_NEW_SMALL_INT(common_hal_touchio_touchin_get_threshold(self)); } @@ -166,7 +172,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(touchio_touchin_get_threshold_obj, touchio_touchin_obj STATIC mp_obj_t touchio_touchin_obj_set_threshold(mp_obj_t self_in, mp_obj_t threshold_obj) { touchio_touchin_obj_t *self = MP_OBJ_TO_PTR(self_in); - raise_error_if_deinited(common_hal_touchio_touchin_deinited(self)); + check_for_deinit(self); uint32_t new_threshold = mp_obj_get_int(threshold_obj); if (new_threshold < 0 || new_threshold > UINT16_MAX) { // I would use MP_STRINGIFY(UINT16_MAX), but that prints "0xffff" instead of 65536. diff --git a/shared-bindings/uheap/__init__.c b/shared-bindings/uheap/__init__.c index df18237ac..0d699cd28 100644 --- a/shared-bindings/uheap/__init__.c +++ b/shared-bindings/uheap/__init__.c @@ -38,7 +38,7 @@ //| :synopsis: Heap size analysis //| -//| .. method:: info(object) +//| .. function:: info(object) //| //| Prints memory debugging info for the given object and returns the //| estimated size. diff --git a/shared-bindings/ustack/__init__.c b/shared-bindings/ustack/__init__.c index c4391c132..08b772e41 100644 --- a/shared-bindings/ustack/__init__.c +++ b/shared-bindings/ustack/__init__.c @@ -39,7 +39,7 @@ //| #if MICROPY_MAX_STACK_USAGE -//| .. method:: max_stack_usage() +//| .. function:: max_stack_usage() //| //| Return the maximum excursion of the stack so far. //| @@ -50,7 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(max_stack_usage_obj, max_stack_usage); #endif // MICROPY_MAX_STACK_USAGE -//| .. method:: stack_size() +//| .. function:: stack_size() //| //| Return the size of the entire stack. //| Same as in micropython.mem_info(), but returns a value instead @@ -61,7 +61,7 @@ STATIC mp_obj_t stack_size(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(stack_size_obj, stack_size); -//| .. method:: stack_usage() +//| .. function:: stack_usage() //| //| Return how much stack is currently in use. //| Same as micropython.stack_use(); duplicated here for convenience. diff --git a/shared-bindings/util.c b/shared-bindings/util.c index 80a0bdaeb..c1ca01e0a 100644 --- a/shared-bindings/util.c +++ b/shared-bindings/util.c @@ -32,11 +32,9 @@ #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" -// Check if pin is None. If so, deinit() has already been called on the object, so complain. -void raise_error_if_deinited(bool deinited) { - if (deinited) { - mp_raise_ValueError(translate("Object has been deinitialized and can no longer be used. Create a new object.")); - } +// If so, deinit() has already been called on the object, so complain. +void raise_deinited_error(void) { + mp_raise_ValueError(translate("Object has been deinitialized and can no longer be used. Create a new object.")); } diff --git a/shared-bindings/util.h b/shared-bindings/util.h index b26ed7e93..33454f10e 100644 --- a/shared-bindings/util.h +++ b/shared-bindings/util.h @@ -27,7 +27,7 @@ #ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H #define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H -void raise_error_if_deinited(bool deinited); +void raise_deinited_error(void); #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_UTIL_H diff --git a/shared-bindings/wiznet/wiznet5k.c b/shared-bindings/wiznet/wiznet5k.c index 6d43e8992..ac89cc691 100644 --- a/shared-bindings/wiznet/wiznet5k.c +++ b/shared-bindings/wiznet/wiznet5k.c @@ -41,6 +41,7 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/digitalio/DriveMode.h" #include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-module/network/__init__.h" #include "shared-module/wiznet/wiznet5k.h" @@ -50,25 +51,44 @@ //| :class:`WIZNET5K` -- wrapper for Wiznet 5500 Ethernet interface //| =============================================================== //| -//| .. class:: WIZNET5K(spi, cs, rst) +//| .. class:: WIZNET5K(spi, cs, rst, dhcp=True) //| //| Create a new WIZNET5500 interface using the specified pins //| -//| :param spi: spi bus to use -//| :param cs: pin to use for Chip Select -//| :param rst: pin to sue for Reset +//| :param ~busio.SPI spi: spi bus to use +//| :param ~microcontroller.Pin cs: pin to use for Chip Select +//| :param ~microcontroller.Pin rst: pin to use for Reset (optional) +//| :param bool dhcp: boolean flag, whether to start DHCP automatically (optional, keyword only, default True) +//| +//| * The reset pin is optional: if supplied it is used to reset the +//| wiznet board before initialization. +//| * The SPI bus will be initialized appropriately by this library. +//| * At present, the WIZNET5K object is a singleton, so only one WizNet +//| interface is supported at a time. //| -STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - // check arguments - mp_arg_check_num(n_args, kw_args, 3, 3, false); - - return wiznet5k_create(args[0], args[1], args[2]); +STATIC mp_obj_t wiznet5k_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_spi, ARG_cs, ARG_rst, ARG_dhcp }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_cs, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rst, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_dhcp, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = true } }, + }; + 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); + // TODO check type of ARG_spi? + assert_pin(args[ARG_cs].u_obj, false); + assert_pin(args[ARG_rst].u_obj, true); // may be NULL + + mp_obj_t ret = wiznet5k_create(args[ARG_spi].u_obj, args[ARG_cs].u_obj, args[ARG_rst].u_obj); + if (args[ARG_dhcp].u_bool) wiznet5k_start_dhcp(); + return ret; } //| .. attribute:: connected //| -//| is this device physically connected? +//| (boolean, readonly) is this device physically connected? //| STATIC mp_obj_t wiznet5k_connected_get_value(mp_obj_t self_in) { @@ -86,7 +106,9 @@ const mp_obj_property_t wiznet5k_connected_obj = { //| .. attribute:: dhcp //| -//| is DHCP active on this device? (set to true to activate DHCP, false to turn it off) +//| (boolean, readwrite) is DHCP active on this device? +//| +//| * set to True to activate DHCP, False to turn it off //| STATIC mp_obj_t wiznet5k_dhcp_get_value(mp_obj_t self_in) { @@ -99,9 +121,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_dhcp_get_value_obj, wiznet5k_dhcp_get_ STATIC mp_obj_t wiznet5k_dhcp_set_value(mp_obj_t self_in, mp_obj_t value) { (void)self_in; if (mp_obj_is_true(value)) { - wiznet5k_start_dhcp(); + int ret = wiznet5k_start_dhcp(); + if (ret) mp_raise_OSError(ret); } else { - wiznet5k_stop_dhcp(); + int ret = wiznet5k_stop_dhcp(); + if (ret) mp_raise_OSError(ret); } return mp_const_none; } @@ -114,12 +138,13 @@ const mp_obj_property_t wiznet5k_dhcp_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| .. method:: ifconfig(...) +//| .. method:: ifconfig(params=None) //| //| Called without parameters, returns a tuple of //| (ip_address, subnet_mask, gateway_address, dns_server) //| //| Or can be called with the same tuple to set those parameters. +//| Setting ifconfig parameters turns DHCP off, if it was on. //| STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { @@ -136,6 +161,7 @@ STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(4, tuple); } else { // set + wiznet5k_stop_dhcp(); mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 4, &items); netutils_parse_ipv4_addr(items[0], netinfo.ip, NETUTILS_BIG); @@ -178,6 +204,7 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = { .settimeout = wiznet5k_socket_settimeout, .ioctl = wiznet5k_socket_ioctl, .timer_tick = wiznet5k_socket_timer_tick, + .deinit = wiznet5k_socket_deinit, }; #endif // MICROPY_PY_WIZNET5K |
