diff options
| author | Dan Halbert <halbert@halwitz.org> | 2018-01-02 21:25:41 -0500 |
|---|---|---|
| committer | Dan Halbert <halbert@halwitz.org> | 2018-01-02 21:25:41 -0500 |
| commit | 065e82015f0d2bd6732c62b7375fcc7af87fa0cf (patch) | |
| tree | e48fa8caa5675d529d335a2b154e69eba8199cff /shared-bindings | |
| parent | ce81c8dda9686d3cd78d9c5383b6982c148ac7ec (diff) | |
merge from 2.2.0 + fix up board defs
Diffstat (limited to 'shared-bindings')
| -rw-r--r-- | shared-bindings/_stage/Layer.c | 130 | ||||
| -rw-r--r-- | shared-bindings/_stage/Layer.h | 34 | ||||
| -rw-r--r-- | shared-bindings/_stage/Text.c | 109 | ||||
| -rw-r--r-- | shared-bindings/_stage/Text.h | 34 | ||||
| -rw-r--r-- | shared-bindings/_stage/__init__.c | 97 | ||||
| -rw-r--r-- | shared-bindings/_stage/__init__.h | 32 | ||||
| -rw-r--r-- | shared-bindings/audiobusio/PDMIn.c | 53 | ||||
| -rw-r--r-- | shared-bindings/bitbangio/I2C.c | 7 | ||||
| -rw-r--r-- | shared-bindings/bitbangio/SPI.c | 11 | ||||
| -rw-r--r-- | shared-bindings/busio/I2C.c | 8 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.c | 92 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.h | 3 | ||||
| -rw-r--r-- | shared-bindings/digitalio/DigitalInOut.c | 14 | ||||
| -rw-r--r-- | shared-bindings/digitalio/DigitalInOut.h | 14 | ||||
| -rw-r--r-- | shared-bindings/digitalio/Direction.h | 4 | ||||
| -rw-r--r-- | shared-bindings/digitalio/DriveMode.h | 4 | ||||
| -rw-r--r-- | shared-bindings/digitalio/Pull.h | 4 | ||||
| -rw-r--r-- | shared-bindings/microcontroller/RunMode.c | 90 | ||||
| -rw-r--r-- | shared-bindings/microcontroller/RunMode.h | 47 | ||||
| -rw-r--r-- | shared-bindings/microcontroller/__init__.c | 44 | ||||
| -rw-r--r-- | shared-bindings/microcontroller/__init__.h | 5 |
21 files changed, 790 insertions, 46 deletions
diff --git a/shared-bindings/_stage/Layer.c b/shared-bindings/_stage/Layer.c new file mode 100644 index 000000000..3e615c497 --- /dev/null +++ b/shared-bindings/_stage/Layer.c @@ -0,0 +1,130 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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/runtime.h> + +#include "__init__.h" +#include "Layer.h" + +//| .. currentmodule:: _stage +//| +//| :class:`Layer` -- Keep information about a single layer of graphics +//| =================================================================== +//| +//| .. class:: Layer(width, height, graphic, palette, [grid]) +//| +//| Keep internal information about a layer of graphics (either a +//| ``Grid`` or a ``Sprite``) in a format suitable for fast rendering +//| with the ``render()`` function. +//| +//| :param int width: The width of the grid in tiles, or 1 for sprites. +//| :param int height: The height of the grid in tiles, or 1 for sprites. +//| :param bytearray graphic: The graphic data of the tiles. +//| :param bytearray palette: The color palette to be used. +//| :param bytearray grid: The contents of the grid map. +//| +//| This class is intended for internal use in the ``stage`` library and +//| it shouldn't be used on its own. +//| +STATIC mp_obj_t layer_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 4, 5, false); + + layer_obj_t *self = m_new_obj(layer_obj_t); + self->base.type = type; + + self->width = mp_obj_get_int(args[0]); + self->height = mp_obj_get_int(args[1]); + self->x = 0; + self->y = 0; + self->frame = 0; + self->rotation = false; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + self->graphic = bufinfo.buf; + if (bufinfo.len != 2048) { + mp_raise_ValueError("graphic must be 2048 bytes long"); + } + + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + self->palette = bufinfo.buf; + if (bufinfo.len != 32) { + mp_raise_ValueError("palette must be 32 bytes long"); + } + + if (n_args > 4) { + mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); + self->map = bufinfo.buf; + if (bufinfo.len < (self->width * self->height) / 2) { + mp_raise_ValueError("map buffer too small"); + } + } else { + self-> map = NULL; + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: move(x, y) +//| +//| Set the offset of the layer to the specified values. +//| +STATIC mp_obj_t layer_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + layer_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = mp_obj_get_int(x_in); + self->y = mp_obj_get_int(y_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_move_obj, layer_move); + +//| .. method:: frame(frame, rotation) +//| +//| Set the animation frame of the sprite, and optionally rotation its +//| graphic. +//| +STATIC mp_obj_t layer_frame(mp_obj_t self_in, mp_obj_t frame_in, + mp_obj_t rotation_in) { + layer_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->frame = mp_obj_get_int(frame_in); + self->rotation = mp_obj_get_int(rotation_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(layer_frame_obj, layer_frame); + + +STATIC const mp_rom_map_elem_t layer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&layer_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&layer_frame_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(layer_locals_dict, layer_locals_dict_table); + +const mp_obj_type_t mp_type_layer = { + { &mp_type_type }, + .name = MP_QSTR_Layer, + .make_new = layer_make_new, + .locals_dict = (mp_obj_dict_t*)&layer_locals_dict, +}; diff --git a/shared-bindings/_stage/Layer.h b/shared-bindings/_stage/Layer.h new file mode 100644 index 000000000..6d15dfb28 --- /dev/null +++ b/shared-bindings/_stage/Layer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_LAYER_H +#define MICROPY_INCLUDED__STAGE_LAYER_H + +#include "shared-module/_stage/Layer.h" + +extern const mp_obj_type_t mp_type_layer; + +#endif // MICROPY_INCLUDED__STAGE_LAYER diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c new file mode 100644 index 000000000..c62d22afe --- /dev/null +++ b/shared-bindings/_stage/Text.c @@ -0,0 +1,109 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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/runtime.h> + +#include "__init__.h" +#include "Text.h" + +//| .. currentmodule:: _stage +//| +//| :class:`Text` -- Keep information about a single text of text +//| ============================================================== +//| +//| .. class:: Text(width, height, font, palette, chars) +//| +//| Keep internal information about a text of text +//| in a format suitable for fast rendering +//| with the ``render()`` function. +//| +//| :param int width: The width of the grid in tiles, or 1 for sprites. +//| :param int height: The height of the grid in tiles, or 1 for sprites. +//| :param bytearray font: The font data of the characters. +//| :param bytearray palette: The color palette to be used. +//| :param bytearray chars: The contents of the character grid. +//| +//| This class is intended for internal use in the ``stage`` library and +//| it shouldn't be used on its own. +//| +STATIC mp_obj_t text_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 5, 5, false); + + text_obj_t *self = m_new_obj(text_obj_t); + self->base.type = type; + + self->width = mp_obj_get_int(args[0]); + self->height = mp_obj_get_int(args[1]); + self->x = 0; + self->y = 0; + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); + self->font = bufinfo.buf; + if (bufinfo.len != 2048) { + mp_raise_ValueError("font must be 2048 bytes long"); + } + + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + self->palette = bufinfo.buf; + if (bufinfo.len != 32) { + mp_raise_ValueError("palette must be 32 bytes long"); + } + + mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); + self->chars = bufinfo.buf; + if (bufinfo.len < self->width * self->height) { + mp_raise_ValueError("chars buffer too small"); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: move(x, y) +//| +//| Set the offset of the text to the specified values. +//| +STATIC mp_obj_t text_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + text_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = mp_obj_get_int(x_in); + self->y = mp_obj_get_int(y_in); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(text_move_obj, text_move); + + +STATIC const mp_rom_map_elem_t text_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&text_move_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(text_locals_dict, text_locals_dict_table); + +const mp_obj_type_t mp_type_text = { + { &mp_type_type }, + .name = MP_QSTR_Text, + .make_new = text_make_new, + .locals_dict = (mp_obj_dict_t*)&text_locals_dict, +}; diff --git a/shared-bindings/_stage/Text.h b/shared-bindings/_stage/Text.h new file mode 100644 index 000000000..77de62a11 --- /dev/null +++ b/shared-bindings/_stage/Text.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_TEXT_H +#define MICROPY_INCLUDED__STAGE_TEXT_H + +#include "shared-module/_stage/Text.h" + +extern const mp_obj_type_t mp_type_text; + +#endif // MICROPY_INCLUDED__STAGE_TEXT diff --git a/shared-bindings/_stage/__init__.c b/shared-bindings/_stage/__init__.c new file mode 100644 index 000000000..16e0b58d9 --- /dev/null +++ b/shared-bindings/_stage/__init__.c @@ -0,0 +1,97 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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 "__init__.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-module/_stage/__init__.h" +#include "Layer.h" +#include "Text.h" + +//| .. currentmodule:: _stage +//| +//| .. function:: render(x0, y0, x1, y1, layers, buffer, spi) +//| +//| Render and send to the display a fragment of the screen. +//| +//| :param int x0: Left edge of the fragment. +//| :param int y0: Top edge of the fragment. +//| :param int x1: Right edge of the fragment. +//| :param int y1: Bottom edge of the fragment. +//| :param list layers: A list of the `Layer` objects. +//| :param bytearray buffer: A buffer to use for rendering. +//| :param SPI spi: The SPI device 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. +//| +//| This function is intended for internal use in the ``stage`` library +//| and all the necessary checks are performed there. +STATIC mp_obj_t stage_render(size_t n_args, const mp_obj_t *args) { + uint8_t x0 = mp_obj_get_int(args[0]); + uint8_t y0 = mp_obj_get_int(args[1]); + uint8_t x1 = mp_obj_get_int(args[2]); + uint8_t y1 = mp_obj_get_int(args[3]); + + size_t layers_size = 0; + mp_obj_t *layers; + mp_obj_get_array(args[4], &layers_size, &layers); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[5], &bufinfo, MP_BUFFER_WRITE); + 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]); + + if (!render_stage(x0, y0, x1, y1, layers, layers_size, + buffer, buffer_size, spi)) { + mp_raise_OSError(MP_EIO); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stage_render_obj, 7, 7, stage_render); + + +STATIC const mp_rom_map_elem_t stage_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__stage) }, + { MP_ROM_QSTR(MP_QSTR_Layer), MP_ROM_PTR(&mp_type_layer) }, + { MP_ROM_QSTR(MP_QSTR_Text), MP_ROM_PTR(&mp_type_text) }, + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&stage_render_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(stage_module_globals, stage_module_globals_table); + +const mp_obj_module_t stage_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&stage_module_globals, +}; diff --git a/shared-bindings/_stage/__init__.h b/shared-bindings/_stage/__init__.h new file mode 100644 index 000000000..2df81cb3b --- /dev/null +++ b/shared-bindings/_stage/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Radomir Dopieralski + * + * 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__STAGE_H +#define MICROPY_INCLUDED__STAGE_H + +#include "shared-module/_stage/__init__.h" + +#endif // MICROPY_INCLUDED__STAGE diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index b43adecba..f273c7a3d 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -28,6 +28,7 @@ #include "lib/utils/context_manager_helpers.h" #include "py/binary.h" +#include "py/mphal.h" #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" @@ -41,7 +42,7 @@ //| //| PDMIn can be used to record an input audio signal on a given set of pins. //| -//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=8000, bit_depth=8, mono=True, oversample=64) +//| .. class:: PDMIn(clock_pin, data_pin, \*, frequency=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 @@ -51,11 +52,16 @@ //| //| :param ~microcontroller.Pin clock_pin: The pin to output the clock to //| :param ~microcontroller.Pin data_pin: The pin to read the data from -//| :param int frequency: Target frequency in Hz of the resulting samples. Check `frequency` for real value +//| :param int frequency: Target frequency of the resulting samples. Check `frequency` for actual value. +//| Minimum frequency is about 16000 Hz. //| :param int bit_depth: Final number of bits per sample. Must be divisible by 8 //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise //| :param int oversample: Number of single bit samples to decimate into a final sample. Must be divisible by 8 +//| :param float startup_delay: seconds to wait after starting microphone clock +//| to allow microphone to turn on. Most require only 0.01s; some require 0.1s. Longer is safer. +//| Must be in range 0.0-1.0 seconds. //| + //| Record 8-bit unsigned samples to buffer:: //| //| import audiobusio @@ -81,15 +87,19 @@ //| mic.record(b, len(b)) //| STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { - enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample }; + enum { ARG_frequency, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay }; mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); static const mp_arg_t allowed_args[] = { - { MP_QSTR_frequency, MP_ARG_INT, {.u_int = 8000} }, - { MP_QSTR_bit_depth, MP_ARG_INT, {.u_int = 8} }, - { MP_QSTR_mono, MP_ARG_BOOL,{.u_bool = true} }, - { MP_QSTR_oversample, MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, + { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = true} }, + { MP_QSTR_oversample, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + { MP_QSTR_startup_delay, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; + // Default microphone startup delay is 110msecs. Have seen mics that need 100 msecs plus a bit. + static const float STARTUP_DELAY_DEFAULT = 0.110F; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 2, pos_args + 2, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -118,8 +128,18 @@ STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar } bool mono = args[ARG_mono].u_bool; + float startup_delay = (args[ARG_startup_delay].u_obj == MP_OBJ_NULL) + ? STARTUP_DELAY_DEFAULT + : mp_obj_get_float(args[ARG_startup_delay].u_obj); + if (startup_delay < 0.0 || startup_delay > 1.0) { + mp_raise_ValueError("Microphone startup delay must be in range 0.0 to 1.0"); + } + common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, frequency, - bit_depth, mono, oversample); + bit_depth, mono, oversample); + + // Wait for the microphone to start up. Some start in 10 msecs; some take as much as 100 msecs. + mp_hal_delay_ms(startup_delay * 1000); return MP_OBJ_FROM_PTR(self); } @@ -162,11 +182,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiobusio_pdmin___exit___obj, 4, 4, //| audio at the given rate. For internal flash, writing all 1s to the file //| before recording is recommended to speed up writes. //| +//| :return: The number of samples recorded. If this is less than `destination_length`, +//| some samples were missed due to processing time. +//| 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)); - if (!MP_OBJ_IS_SMALL_INT(destination_length)) { - mp_raise_TypeError("destination_length must be int"); + if (!MP_OBJ_IS_SMALL_INT(destination_length) || MP_OBJ_SMALL_INT_VALUE(destination_length) < 0) { + mp_raise_TypeError("destination_length must be an int >= 0"); } uint32_t length = MP_OBJ_SMALL_INT_VALUE(destination_length); @@ -174,8 +197,8 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat if (MP_OBJ_IS_TYPE(destination, &fatfs_type_fileio)) { mp_raise_NotImplementedError(""); } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { - if (bufinfo.len < length) { - mp_raise_ValueError("Target buffer cannot hold destination_length bytes."); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError("Destination capacity is smaller than destination_length."); } uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); if (bufinfo.typecode != 'H' && bit_depth == 16) { @@ -183,12 +206,10 @@ STATIC mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { mp_raise_ValueError("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8"); } - length *= bit_depth / 8; + // length is the buffer length in slots, not bytes. uint32_t length_written = common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); - if (length_written != length) { - mp_printf(&mp_plat_print, "length mismatch %d %d\n", length_written, length); - } + return MP_OBJ_NEW_SMALL_INT(length_written); } return mp_const_none; } diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index 80718090a..f8f60210e 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -157,6 +157,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock); //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. +//| At least one byte must be read. //| //| If ``start`` or ``end`` is provided, then the buffer will be sliced //| as if ``buffer[start:end]``. This will not cause an allocation like @@ -186,6 +187,9 @@ STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_a int32_t start = args[ARG_start].u_int; uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + mp_raise_ValueError("Buffer must be at least length 1"); + } uint8_t status = shared_module_bitbangio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, @@ -206,6 +210,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 3, bitbangio_i2c_rea //| as if ``buffer[start:end]``. This will not cause an allocation like //| ``buffer[start:end]`` will so it saves memory. //| +//| Writing a buffer or slice of length zero is permitted, as it can be used +//| to poll for the existence of a device. +//| //| :param int address: 7-bit device address //| :param bytearray buffer: buffer containing the bytes to write //| :param int start: Index to start writing from diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index 6c7bac3e5..5442b9ea2 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -191,6 +191,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock); //| .. method:: SPI.write(buf) //| //| Write the data contained in ``buf``. Requires the SPI being locked. +//| If the buffer is empty, nothing happens. //| // 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) { @@ -198,6 +199,9 @@ STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) { raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); mp_buffer_info_t src; mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + if (src.len == 0) { + return mp_const_none; + } check_lock(self); bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len); if (!ok) { @@ -210,7 +214,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write); //| .. method:: SPI.readinto(buf) //| -//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked. +//| Read into the buffer specified by ``buf`` while writing zeroes. +//| Requires the SPI being locked. +//| If the number of bytes to read is 0, nothing happens. //| // 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) { @@ -218,6 +224,9 @@ STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) { raise_error_if_deinited(shared_module_bitbangio_spi_deinited(self)); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len == 0) { + return mp_const_none; + } check_lock(args[0]); bool ok = shared_module_bitbangio_spi_read(self, bufinfo.buf, bufinfo.len); if (!ok) { diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index cdc960f80..b0954d6c8 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -171,6 +171,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock); //| //| Read into ``buffer`` from the slave specified by ``address``. //| The number of bytes read will be the length of ``buffer``. +//| At least one byte must be read. //| //| If ``start`` or ``end`` is provided, then the buffer will be sliced //| as if ``buffer[start:end]``. This will not cause an allocation like @@ -201,6 +202,10 @@ STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, int32_t start = args[ARG_start].u_int; uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + mp_raise_ValueError("Buffer must be at least length 1"); + } + uint8_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, length); if (status != 0) { mp_raise_OSError(status); @@ -219,6 +224,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_in //| as if ``buffer[start:end]``. This will not cause an allocation like //| ``buffer[start:end]`` will so it saves memory. //| +//| Writing a buffer or slice of length zero is permitted, as it can be used +//| to poll for the existence of a device. +//| //| :param int address: 7-bit device address //| :param bytearray buffer: buffer containing the bytes to write //| :param int start: Index to start writing from diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 12f888f23..c4c139105 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -206,11 +206,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock); //| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer)) //| -//| Write the data contained in ``buf``. Requires the SPI being locked. +//| Write the data contained in ``buffer``. The SPI object must be locked. +//| If the buffer is empty, nothing happens. //| -//| :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 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 //| 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,6 +232,10 @@ STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_ uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + return mp_const_none; + } + bool ok = common_hal_busio_spi_write(self, ((uint8_t*)bufinfo.buf) + start, length); if (!ok) { mp_raise_OSError(MP_EIO); @@ -242,12 +247,14 @@ 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) //| -//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked. +//| Read into ``buffer`` while writing ``write_value`` for each byte read. +//| The SPI object must be locked. +//| If the number of bytes to read is 0, nothing happens. //| -//| :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 write_value: Value to write reading. (Usually ignored.) +//| :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 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) { enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; @@ -269,6 +276,10 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m uint32_t length = bufinfo.len; normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + if (length == 0) { + return mp_const_none; + } + bool ok = common_hal_busio_spi_read(self, ((uint8_t*)bufinfo.buf) + start, length, args[ARG_write_value].u_int); if (!ok) { mp_raise_OSError(MP_EIO); @@ -277,6 +288,68 @@ 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)) +//| +//| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. +//| The SPI object must be locked. +//| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]`` +//| must be equal. +//| If buffer slice lengths are both 0, nothing happens. +//| +//| :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 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 +//| +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 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { 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_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); + + mp_buffer_info_t buf_out_info; + mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ); + int32_t out_start = args[ARG_out_start].u_int; + uint32_t out_length = buf_out_info.len; + normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE); + int32_t in_start = args[ARG_in_start].u_int; + uint32_t in_length = buf_in_info.len; + normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + + if (out_length != in_length) { + mp_raise_ValueError("buffer slices must be of equal length"); + } + + if (out_length == 0) { + return mp_const_none; + } + + bool ok = common_hal_busio_spi_transfer(self, + ((uint8_t*)buf_out_info.buf) + out_start, + ((uint8_t*)buf_in_info.buf) + in_start, + out_length); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto); + STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, @@ -288,6 +361,7 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table); diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index ac31d5060..b6e5c9b1b 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -55,4 +55,7 @@ extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *dat // Reads in len bytes while outputting zeroes. extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); +// Reads and write len bytes simultaneously. +extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index ea2ba0b89..008883b8b 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -124,7 +124,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_output(size_t n_args, const mp_ 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); - enum digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; + digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; if (args[ARG_drive_mode].u_rom_obj == &digitalio_drive_mode_open_drain_obj) { drive_mode = DRIVE_MODE_OPEN_DRAIN; } @@ -161,7 +161,7 @@ STATIC mp_obj_t digitalio_digitalinout_switch_to_input(size_t n_args, const mp_o 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); - enum digitalio_pull_t pull = PULL_NONE; + digitalio_pull_t pull = PULL_NONE; if (args[ARG_pull].u_rom_obj == &digitalio_pull_up_obj) { pull = PULL_UP; }else if (args[ARG_pull].u_rom_obj == &digitalio_pull_down_obj) { @@ -191,7 +191,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)); - enum digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); + digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); if (direction == DIRECTION_INPUT) { return (mp_obj_t)&digitalio_direction_input_obj; } @@ -262,7 +262,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) { mp_raise_AttributeError("Drive mode not used when direction is input."); return mp_const_none; } - enum digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); + digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); if (drive_mode == DRIVE_MODE_PUSH_PULL) { return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; } @@ -277,7 +277,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_drive_mode(mp_obj_t self_in, mp_o mp_raise_AttributeError("Drive mode not used when direction is input."); return mp_const_none; } - enum digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; + digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; if (drive_mode == &digitalio_drive_mode_open_drain_obj) { c_drive_mode = DRIVE_MODE_OPEN_DRAIN; } @@ -307,7 +307,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_get_pull(mp_obj_t self_in) { mp_raise_AttributeError("Pull not used when direction is output."); return mp_const_none; } - enum digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self); + digitalio_pull_t pull = common_hal_digitalio_digitalinout_get_pull(self); if (pull == PULL_UP) { return (mp_obj_t)&digitalio_pull_up_obj; } else if (pull == PULL_DOWN) { @@ -324,7 +324,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj_set_pull(mp_obj_t self_in, mp_obj_t p mp_raise_AttributeError("Pull not used when direction is output."); return mp_const_none; } - enum digitalio_pull_t pull = PULL_NONE; + digitalio_pull_t pull = PULL_NONE; if (pull_obj == &digitalio_pull_up_obj) { pull = PULL_UP; } else if (pull_obj == &digitalio_pull_down_obj) { diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index 74970881b..2aaa31b7f 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -43,14 +43,14 @@ typedef enum { digitalinout_result_t common_hal_digitalio_digitalinout_construct(digitalio_digitalinout_obj_t* self, const mcu_pin_obj_t* pin); void common_hal_digitalio_digitalinout_deinit(digitalio_digitalinout_obj_t* self); bool common_hal_digitalio_digitalinout_deinited(digitalio_digitalinout_obj_t* self); -void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, enum digitalio_pull_t pull); -void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, enum digitalio_drive_mode_t drive_mode); -enum digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_switch_to_input(digitalio_digitalinout_obj_t* self, digitalio_pull_t pull); +void common_hal_digitalio_digitalinout_switch_to_output(digitalio_digitalinout_obj_t* self, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(digitalio_digitalinout_obj_t* self); void common_hal_digitalio_digitalinout_set_value(digitalio_digitalinout_obj_t* self, bool value); bool common_hal_digitalio_digitalinout_get_value(digitalio_digitalinout_obj_t* self); -void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, enum digitalio_drive_mode_t drive_mode); -enum 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, enum digitalio_pull_t pull); -enum digitalio_pull_t common_hal_digitalio_digitalinout_get_pull(digitalio_digitalinout_obj_t* self); +void common_hal_digitalio_digitalinout_set_drive_mode(digitalio_digitalinout_obj_t* self, digitalio_drive_mode_t drive_mode); +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); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DIGITALIO_DIGITALINOUT_H diff --git a/shared-bindings/digitalio/Direction.h b/shared-bindings/digitalio/Direction.h index e8fbf181d..d71f48c2e 100644 --- a/shared-bindings/digitalio/Direction.h +++ b/shared-bindings/digitalio/Direction.h @@ -29,10 +29,10 @@ #include "py/obj.h" -enum digitalio_direction_t { +typedef enum { DIRECTION_INPUT, DIRECTION_OUTPUT -}; +} digitalio_direction_t; typedef struct { mp_obj_base_t base; } digitalio_direction_obj_t; diff --git a/shared-bindings/digitalio/DriveMode.h b/shared-bindings/digitalio/DriveMode.h index 959885b1b..47d036b3a 100644 --- a/shared-bindings/digitalio/DriveMode.h +++ b/shared-bindings/digitalio/DriveMode.h @@ -29,10 +29,10 @@ #include "py/obj.h" -enum digitalio_drive_mode_t { +typedef enum { DRIVE_MODE_PUSH_PULL, DRIVE_MODE_OPEN_DRAIN -}; +} digitalio_drive_mode_t; typedef struct { mp_obj_base_t base; diff --git a/shared-bindings/digitalio/Pull.h b/shared-bindings/digitalio/Pull.h index 8c88d8673..22fb6cd0e 100644 --- a/shared-bindings/digitalio/Pull.h +++ b/shared-bindings/digitalio/Pull.h @@ -29,11 +29,11 @@ #include "py/obj.h" -enum digitalio_pull_t { +typedef enum _digitalio_pull_t { PULL_NONE, PULL_UP, PULL_DOWN -}; +} digitalio_pull_t; const mp_obj_type_t digitalio_pull_type; diff --git a/shared-bindings/microcontroller/RunMode.c b/shared-bindings/microcontroller/RunMode.c new file mode 100644 index 000000000..b27a3c090 --- /dev/null +++ b/shared-bindings/microcontroller/RunMode.c @@ -0,0 +1,90 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/microcontroller/RunMode.h" + +//| .. currentmodule:: microcontroller +//| +//| :class:`RunMode` -- run state of the microcontroller +//| ============================================================= +//| +//| .. class:: microcontroller.RunMode +//| +//| Enum-like class to define the run mode of the microcontroller and +//| CircuitPython. +//| +//| .. data:: NORMAL +//| +//| Run CircuitPython as normal. +//| +//| .. data:: SAFE_MODE +//| +//| Run CircuitPython in safe mode. User code will not be run and the +//| file system will be writeable over USB. +//| +//| .. data:: BOOTLOADER +//| +//| Run the bootloader. +//| +const mp_obj_type_t mcu_runmode_type; + +const mcu_runmode_obj_t mcu_runmode_normal_obj = { + { &mcu_runmode_type }, +}; + +const mcu_runmode_obj_t mcu_runmode_safe_mode_obj = { + { &mcu_runmode_type }, +}; + +const mcu_runmode_obj_t mcu_runmode_bootloader_obj = { + { &mcu_runmode_type }, +}; + +STATIC const mp_rom_map_elem_t mcu_runmode_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_NORMAL), MP_ROM_PTR(&mcu_runmode_normal_obj)}, + {MP_ROM_QSTR(MP_QSTR_SAFE_MODE), MP_ROM_PTR(&mcu_runmode_safe_mode_obj)}, + {MP_ROM_QSTR(MP_QSTR_BOOTLOADER), MP_ROM_PTR(&mcu_runmode_bootloader_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(mcu_runmode_locals_dict, mcu_runmode_locals_dict_table); + +STATIC void mcu_runmode_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr runmode = MP_QSTR_NORMAL; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&mcu_runmode_safe_mode_obj)) { + runmode = MP_QSTR_SAFE_MODE; + } else if (MP_OBJ_TO_PTR(self_in) == + MP_ROM_PTR(&mcu_runmode_bootloader_obj)) { + runmode = MP_QSTR_SAFE_MODE; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_microcontroller, MP_QSTR_RunMode, + runmode); +} + +const mp_obj_type_t mcu_runmode_type = { + { &mp_type_type }, + .name = MP_QSTR_RunMode, + .print = mcu_runmode_print, + .locals_dict = (mp_obj_t)&mcu_runmode_locals_dict, +}; diff --git a/shared-bindings/microcontroller/RunMode.h b/shared-bindings/microcontroller/RunMode.h new file mode 100644 index 000000000..5e8b6e646 --- /dev/null +++ b/shared-bindings/microcontroller/RunMode.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H + +#include "py/obj.h" + +typedef enum { + RUNMODE_NORMAL, + RUNMODE_SAFE_MODE, + RUNMODE_BOOTLOADER +} mcu_runmode_t; + +const mp_obj_type_t mcu_runmode_type; + +typedef struct { + mp_obj_base_t base; +} mcu_runmode_obj_t; +extern const mcu_runmode_obj_t mcu_runmode_normal_obj; +extern const mcu_runmode_obj_t mcu_runmode_safe_mode_obj; +extern const mcu_runmode_obj_t mcu_runmode_bootloader_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_RUNMODE_H diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c index 58ed876c2..f261178f0 100644 --- a/shared-bindings/microcontroller/__init__.c +++ b/shared-bindings/microcontroller/__init__.c @@ -106,6 +106,47 @@ 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) +//| +//| Configure the run mode used the next time the microcontroller is reset but +//| not powered down. +//| +//| :param ~microcontroller.RunMode run_mode: The next run mode +//| +STATIC mp_obj_t mcu_on_next_reset(mp_obj_t run_mode_obj) { + mcu_runmode_t run_mode; + if (run_mode_obj == &mcu_runmode_normal_obj) { + run_mode = RUNMODE_NORMAL; + } else if (run_mode_obj == &mcu_runmode_safe_mode_obj) { + run_mode = RUNMODE_SAFE_MODE; + } else if (run_mode_obj == &mcu_runmode_bootloader_obj) { + run_mode = RUNMODE_BOOTLOADER; + } else { + mp_raise_ValueError("Invalid run mode."); + } + + common_hal_mcu_on_next_reset(run_mode); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_on_next_reset_obj, mcu_on_next_reset); + +//| .. method:: reset() +//| +//| Reset the microcontroller. After reset, the microcontroller will enter the +//| run mode last set by `one_next_reset`. +//| +//| .. warning:: This may result in file system corruption when connected to a +//| host computer. Be very careful when calling this! Make sure the device +//| "Safely removed" on Windows or "ejected" on Mac OSX and Linux. +//| +STATIC mp_obj_t mcu_reset(void) { + common_hal_mcu_reset(); + // We won't actually get here because we're resetting. + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset); + //| .. attribute:: nvm //| //| Available non-volatile memory. @@ -132,11 +173,14 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) }, { MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) }, { MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) }, + { MP_ROM_QSTR(MP_QSTR_on_next_reset), MP_ROM_PTR(&mcu_on_next_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mcu_reset_obj) }, #if CIRCUITPY_INTERNAL_NVM_SIZE > 0 { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&common_hal_mcu_nvm_obj) }, #else { MP_ROM_QSTR(MP_QSTR_nvm), MP_ROM_PTR(&mp_const_none_obj) }, #endif + { MP_ROM_QSTR(MP_QSTR_RunMode), MP_ROM_PTR(&mcu_runmode_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) }, { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) }, { MP_ROM_QSTR(MP_QSTR_Processor), MP_ROM_PTR(&mcu_processor_type) }, diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index d43db4bf4..e1487c555 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -33,11 +33,16 @@ #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/RunMode.h" + extern void common_hal_mcu_delay_us(uint32_t); extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_enable_interrupts(void); +extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode); +extern void common_hal_mcu_reset(void); + extern const mp_obj_dict_t mcu_pin_globals; extern const mcu_processor_obj_t common_hal_mcu_processor_obj; |
