diff options
Diffstat (limited to 'shared-bindings')
62 files changed, 2659 insertions, 139 deletions
diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 682177093..81277fd70 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -33,8 +33,8 @@ #include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Adapter.h" -#define ADV_INTERVAL_MIN (0.0020f) -#define ADV_INTERVAL_MIN_STRING "0.0020" +#define ADV_INTERVAL_MIN (0.02f) +#define ADV_INTERVAL_MIN_STRING "0.02" #define ADV_INTERVAL_MAX (10.24f) #define ADV_INTERVAL_MAX_STRING "10.24" // 20ms is recommended by Apple @@ -204,7 +204,7 @@ const mp_obj_property_t bleio_adapter_name_obj = { //| :param ~_typing.ReadableBuffer 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 bool anonymous: If `True` then this device's MAC address is randomized before advertising. -//| :param int timeout: If set, we will only advertise for this many seconds. +//| :param int timeout: If set, we will only advertise for this many seconds. Zero means no timeout. //| :param float interval: advertising interval, in seconds""" //| ... //| @@ -237,7 +237,7 @@ STATIC mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT); } - const mp_float_t interval = mp_obj_float_get(args[ARG_interval].u_obj); + const mp_float_t interval = mp_obj_get_float(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); @@ -279,7 +279,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_advertising_obj, bleio_adapt //| ignored. Format is one byte for length (n) and n bytes of prefix and can be repeated. //| :param int buffer_size: the maximum number of advertising bytes to buffer. //| :param bool extended: When True, support extended advertising packets. Increasing buffer_size is recommended when this is set. -//| :param float timeout: the scan timeout in seconds. If None, will scan until `stop_scan` is called. +//| :param float timeout: the scan timeout in seconds. If None or zero, will scan until `stop_scan` is called. //| :param float interval: the interval (in seconds) between the start of two consecutive scan windows //| Must be in the range 0.0025 - 40.959375 seconds. //| :param float window: the duration (in seconds) to scan a single BLE channel. @@ -307,7 +307,7 @@ STATIC mp_obj_t bleio_adapter_start_scan(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); - mp_float_t timeout = 0; + mp_float_t timeout = 0.0f; if (args[ARG_timeout].u_obj != mp_const_none) { timeout = mp_obj_get_float(args[ARG_timeout].u_obj); } @@ -320,12 +320,19 @@ STATIC mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args 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); + const mp_float_t interval = mp_obj_get_float(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); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" + if (timeout != 0.0f && timeout < interval) { + mp_raise_ValueError(translate("non-zero timeout must be >= interval")); + } +#pragma GCC diagnostic pop + + const mp_float_t window = mp_obj_get_float(args[ARG_window].u_obj); if (window > interval) { mp_raise_ValueError(translate("window must be <= interval")); } diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index 5e384a44c..a0751b7e3 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -110,8 +110,8 @@ STATIC mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ common_hal_bleio_attribute_security_mode_check_valid(write_perm); const mp_int_t max_length_int = args[ARG_max_length].u_int; - if (max_length_int <= 0) { - mp_raise_ValueError(translate("max_length must be > 0")); + if (max_length_int < 0) { + mp_raise_ValueError(translate("max_length must be >= 0")); } const size_t max_length = (size_t) max_length_int; const bool fixed_length = args[ARG_fixed_length].u_bool; diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index c313007c6..60f0acf44 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -101,8 +101,8 @@ STATIC mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o common_hal_bleio_attribute_security_mode_check_valid(write_perm); const mp_int_t max_length_int = args[ARG_max_length].u_int; - if (max_length_int <= 0) { - mp_raise_ValueError(translate("max_length must be > 0")); + if (max_length_int < 0) { + mp_raise_ValueError(translate("max_length must be >= 0")); } const size_t max_length = (size_t) max_length_int; const bool fixed_length = args[ARG_fixed_length].u_bool; diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 88e8aa801..a4b5b5b1b 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -185,7 +185,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_pixelbuf_get_brightness_obj, pixelbuf_pixelbu STATIC mp_obj_t pixelbuf_pixelbuf_obj_set_brightness(mp_obj_t self_in, mp_obj_t value) { - mp_float_t brightness = mp_obj_float_get(value); + mp_float_t brightness = mp_obj_get_float(value); if (brightness > 1) { brightness = 1; } else if (brightness < 0) { diff --git a/shared-bindings/_pixelbuf/__init__.c b/shared-bindings/_pixelbuf/__init__.c index c61acc939..fdd02509c 100644 --- a/shared-bindings/_pixelbuf/__init__.c +++ b/shared-bindings/_pixelbuf/__init__.c @@ -51,7 +51,7 @@ //| STATIC mp_obj_t pixelbuf_colorwheel(mp_obj_t n) { - return MP_OBJ_NEW_SMALL_INT(colorwheel(MP_OBJ_IS_SMALL_INT(n) ? MP_OBJ_SMALL_INT_VALUE(n) : mp_obj_float_get(n))); + return MP_OBJ_NEW_SMALL_INT(colorwheel(MP_OBJ_IS_SMALL_INT(n) ? MP_OBJ_SMALL_INT_VALUE(n) : mp_obj_get_float(n))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pixelbuf_colorwheel_obj, pixelbuf_colorwheel); diff --git a/shared-bindings/_typing/__init__.pyi b/shared-bindings/_typing/__init__.pyi index 48e68a8d5..cc4a0a439 100644 --- a/shared-bindings/_typing/__init__.pyi +++ b/shared-bindings/_typing/__init__.pyi @@ -2,6 +2,9 @@ from typing import Union +import alarm +import alarm.pin +import alarm.time import array import audiocore import audiomixer @@ -52,3 +55,14 @@ FrameBuffer = Union[rgbmatrix.RGBMatrix] - `rgbmatrix.RGBMatrix` """ + +Alarm = Union[ + alarm.pin.PinAlarm, alarm.time.TimeAlarm +] +"""Classes that implement alarms for sleeping and asynchronous notification. + + - `alarm.pin.PinAlarm` + - `alarm.time.TimeAlarm` + + You can use these alarms to wake up from light or deep sleep. +""" diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.c b/shared-bindings/adafruit_bus_device/I2CDevice.c new file mode 100644 index 000000000..a4c04e198 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/I2CDevice.c @@ -0,0 +1,259 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// This file contains all of the Python API definitions for the +// busio.I2C class. + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/adafruit_bus_device/I2CDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/adafruit_bus_device/I2CDevice.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class I2CDevice: +//| """I2C Device Manager""" +//| +//| def __init__(self, i2c: busio.I2C, device_address: int, probe: bool = True) -> None: +//| +//| """Represents a single I2C device and manages locking the bus and the device +//| address. +//| :param ~busio.I2C i2c: The I2C bus the device is on +//| :param int device_address: The 7 bit device address +//| :param bool probe: Probe for the device upon object creation, default is true +//| +//| Example:: +//| +//| import busio +//| from board import * +//| from adafruit_bus_device.i2c_device import I2CDevice +//| with busio.I2C(SCL, SDA) as i2c: +//| device = I2CDevice(i2c, 0x70) +//| bytes_read = bytearray(4) +//| with device: +//| device.readinto(bytes_read) +//| # A second transaction +//| with device: +//| device.write(bytes_read)""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + adafruit_bus_device_i2cdevice_obj_t *self = m_new_obj(adafruit_bus_device_i2cdevice_obj_t); + self->base.type = &adafruit_bus_device_i2cdevice_type; + enum { ARG_i2c, ARG_device_address, ARG_probe }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_probe, 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); + + busio_i2c_obj_t* i2c = args[ARG_i2c].u_obj; + + common_hal_adafruit_bus_device_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); + if (args[ARG_probe].u_bool == true) { + common_hal_adafruit_bus_device_i2cdevice_probe_for_device(self); + } + + return (mp_obj_t)self; +} + +//| def __enter__(self) -> I2CDevice: +//| """Context manager entry to lock bus.""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___enter__(mp_obj_t self_in) { + adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_adafruit_bus_device_i2cdevice_lock(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_i2cdevice___enter___obj, adafruit_bus_device_i2cdevice_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically unlocks the bus on exit.""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_adafruit_bus_device_i2cdevice_unlock(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_i2cdevice___exit___obj, 4, 4, adafruit_bus_device_i2cdevice_obj___exit__); + +//| def readinto(self, buf: WriteableBuffer, *, start: int = 0, end: int = 0) -> None: +//| """Read into ``buf`` from the device. The number of bytes read will be the +//| length of ``buf``. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buf[start:end]``. This will not cause an allocation like +//| ``buf[start:end]`` will so it saves memory. +//| :param bytearray buf: buffer to write into +//| :param int start: Index to start writing at +//| :param int end: Index to write up to but not include; if None, use ``len(buf)``""" +//| ... +//| +STATIC void readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_readinto(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t adafruit_bus_device_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + adafruit_bus_device_i2cdevice_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); + + readinto(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_readinto_obj, 2, adafruit_bus_device_i2cdevice_readinto); + +//| def write(self, buf: ReadableBuffer, *, start: int = 0, end: int = 0) -> None: +//| """Write the bytes from ``buffer`` to the device, then transmit a stop bit. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]``. This will not cause an allocation like +//| ``buffer[start:end]`` will so it saves memory. +//| :param bytearray buf: 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; if None, use ``len(buf)`` +//| """ +//| ... +//| +STATIC void write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end, bool transmit_stop_bit) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length, transmit_stop_bit); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t adafruit_bus_device_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + adafruit_bus_device_i2cdevice_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); + + write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int, true); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_obj, 2, adafruit_bus_device_i2cdevice_write); + + +//| def write_then_readinto(self, out_buffer: WriteableBuffer, in_buffer: ReadableBuffer, *, out_start: int = 0, out_end: int = 0, in_start: int = 0, in_end: int = 0) -> None: +//| """Write the bytes from ``out_buffer`` to the device, then immediately +//| reads into ``in_buffer`` from the device. The number of bytes read +//| will be the length of ``in_buffer``. +//| If ``out_start`` or ``out_end`` is provided, then the output buffer +//| will be sliced as if ``out_buffer[out_start:out_end]``. This will +//| not cause an allocation like ``buffer[out_start:out_end]`` will so +//| it saves memory. +//| If ``in_start`` or ``in_end`` is provided, then the input buffer +//| will be sliced as if ``in_buffer[in_start:in_end]``. This will not +//| cause an allocation like ``in_buffer[in_start:in_end]`` will so +//| it saves memory. +//| :param bytearray out_buffer: buffer containing the bytes to write +//| :param bytearray in_buffer: buffer containing the bytes to read into +//| :param int out_start: Index to start writing from +//| :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)`` +//| :param int in_start: Index to start writing at +//| :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)`` +//| """ +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { 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} }, + }; + adafruit_bus_device_i2cdevice_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); + + write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int, false); + + readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_then_readinto_obj, 3, adafruit_bus_device_i2cdevice_write_then_readinto); + +STATIC const mp_rom_map_elem_t adafruit_bus_device_i2cdevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_then_readinto_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2cdevice_locals_dict, adafruit_bus_device_i2cdevice_locals_dict_table); + +const mp_obj_type_t adafruit_bus_device_i2cdevice_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDevice, + .make_new = adafruit_bus_device_i2cdevice_make_new, + .locals_dict = (mp_obj_dict_t*)&adafruit_bus_device_i2cdevice_locals_dict, +}; diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.h b/shared-bindings/adafruit_bus_device/I2CDevice.h new file mode 100644 index 000000000..cf7b1321a --- /dev/null +++ b/shared-bindings/adafruit_bus_device/I2CDevice.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" + +#include "shared-module/adafruit_bus_device/I2CDevice.h" +//#include "shared-bindings/busio/I2C.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t adafruit_bus_device_i2cdevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address); +extern uint8_t common_hal_adafruit_bus_device_i2cdevice_readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length, bool transmit_stop_bit); +extern void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self); +extern void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevice_obj_t *self); +extern void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-bindings/adafruit_bus_device/SPIDevice.c b/shared-bindings/adafruit_bus_device/SPIDevice.c new file mode 100644 index 000000000..e127e39b8 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/SPIDevice.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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/Pin.h" +#include "shared-bindings/adafruit_bus_device/SPIDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/adafruit_bus_device/SPIDevice.h" +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class SPIDevice: +//| """SPI Device Manager""" +//| +//| def __init__(self, spi: busio.SPI, chip_select: microcontroller.Pin, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, extra_clocks : int = 0) -> None: +//| +//| """ +//| Represents a single SPI device and manages locking the bus and the device address. +//| :param ~busio.SPI spi: The SPI bus the device is on +//| :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the DigitalInOut API. +//| :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high. (Used for SD cards.) +//| +//| Example:: +//| +//| import busio +//| import digitalio +//| from board import * +//| from adafruit_bus_device.spi_device import SPIDevice +//| with busio.SPI(SCK, MOSI, MISO) as spi_bus: +//| cs = digitalio.DigitalInOut(D10) +//| device = SPIDevice(spi_bus, cs) +//| bytes_read = bytearray(4) +//| # The object assigned to spi in the with statements below +//| # is the original spi_bus object. We are using the busio.SPI +//| # operations busio.SPI.readinto() and busio.SPI.write(). +//| with device as spi: +//| spi.readinto(bytes_read) +//| # A second transaction +//| with device as spi: +//| spi.write(bytes_read)""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + adafruit_bus_device_spidevice_obj_t *self = m_new_obj(adafruit_bus_device_spidevice_obj_t); + self->base.type = &adafruit_bus_device_spidevice_type; + enum { ARG_spi, ARG_chip_select, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_chip_select, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extra_clocks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + busio_spi_obj_t* spi = args[ARG_spi].u_obj; + + common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, + args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); + + if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) { + digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), + true, DRIVE_MODE_PUSH_PULL); + if (result == DIGITALINOUT_INPUT_ONLY) { + mp_raise_NotImplementedError(translate("Pin is input only")); + } + } + + return (mp_obj_t)self; +} + +STATIC mp_obj_t adafruit_bus_device_spidevice_obj___enter__(mp_obj_t self_in) { + adafruit_bus_device_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_adafruit_bus_device_spidevice_enter(self); + return self->spi; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_spidevice___enter___obj, adafruit_bus_device_spidevice_obj___enter__); + +STATIC mp_obj_t adafruit_bus_device_spidevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_adafruit_bus_device_spidevice_exit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_spidevice___exit___obj, 4, 4, adafruit_bus_device_spidevice_obj___exit__); + +STATIC const mp_rom_map_elem_t adafruit_bus_device_spidevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_spidevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_spidevice___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spidevice_locals_dict, adafruit_bus_device_spidevice_locals_dict_table); + +const mp_obj_type_t adafruit_bus_device_spidevice_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIDevice, + .make_new = adafruit_bus_device_spidevice_make_new, + .locals_dict = (mp_obj_dict_t*)&adafruit_bus_device_spidevice_locals_dict, +}; diff --git a/shared-bindings/adafruit_bus_device/SPIDevice.h b/shared-bindings/adafruit_bus_device/SPIDevice.h new file mode 100644 index 000000000..5596b157f --- /dev/null +++ b/shared-bindings/adafruit_bus_device/SPIDevice.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H + +#include "py/obj.h" + +#include "shared-module/adafruit_bus_device/SPIDevice.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t adafruit_bus_device_spidevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_adafruit_bus_device_spidevice_construct(adafruit_bus_device_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks); +extern void common_hal_adafruit_bus_device_spidevice_enter(adafruit_bus_device_spidevice_obj_t *self); +extern void common_hal_adafruit_bus_device_spidevice_exit(adafruit_bus_device_spidevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H diff --git a/shared-bindings/adafruit_bus_device/__init__.c b/shared-bindings/adafruit_bus_device/__init__.c new file mode 100644 index 000000000..e01abcab3 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/__init__.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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 "py/mphal.h" +#include "py/objproperty.h" + +#include "shared-bindings/adafruit_bus_device/__init__.h" +#include "shared-bindings/adafruit_bus_device/I2CDevice.h" +#include "shared-bindings/adafruit_bus_device/SPIDevice.h" + +STATIC const mp_rom_map_elem_t adafruit_bus_device_i2c_device_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2c_device) }, + { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2c_device_globals, adafruit_bus_device_i2c_device_globals_table); + +const mp_obj_module_t adafruit_bus_device_i2c_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_i2c_device_globals, +}; + +STATIC const mp_rom_map_elem_t adafruit_bus_device_spi_device_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spi_device) }, + { MP_ROM_QSTR(MP_QSTR_SPIDevice), MP_ROM_PTR(&adafruit_bus_device_spidevice_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spi_device_globals, adafruit_bus_device_spi_device_globals_table); + +const mp_obj_module_t adafruit_bus_device_spi_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_spi_device_globals, +}; + +//| """Hardware accelerated external bus access +//| +//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy. +//| For example, they manage locking the bus to prevent other concurrent access. For SPI +//| devices, it manages the chip select and protocol changes such as mode. For I2C, it +//| manages the device address.""" +//| +STATIC const mp_rom_map_elem_t adafruit_bus_device_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_adafruit_bus_device) }, + { MP_ROM_QSTR(MP_QSTR_i2c_device), MP_ROM_PTR(&adafruit_bus_device_i2c_device_module) }, + { MP_ROM_QSTR(MP_QSTR_spi_device), MP_ROM_PTR(&adafruit_bus_device_spi_device_module) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_module_globals, adafruit_bus_device_module_globals_table); + +const mp_obj_module_t adafruit_bus_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_module_globals, +}; diff --git a/shared-bindings/adafruit_bus_device/__init__.h b/shared-bindings/adafruit_bus_device/__init__.h new file mode 100644 index 000000000..4a669807b --- /dev/null +++ b/shared-bindings/adafruit_bus_device/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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_BUSDEVICE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c new file mode 100644 index 000000000..aed24827a --- /dev/null +++ b/shared-bindings/alarm/SleepMemory.c @@ -0,0 +1,179 @@ +/* + * 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) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" + +#include "shared-bindings/alarm/SleepMemory.h" +#include "supervisor/shared/translate.h" + +//| class SleepMemory: +//| """Store raw bytes in RAM that persists during deep sleep. +//| The class acts as a ``bytearray``. +//| If power is lost, the memory contents are lost. +//| +//| Note that this class can't be imported and used directly. The sole +//| instance of :class:`SleepMemory` is available at +//| :attr:`alarm.sleep_memory`. +//| +//| Usage:: +//| +//| import alarm +//| alarm.sleep_memory[0] = True +//| alarm.sleep_memory[1] = 12 +//| """ + +//| def __init__(self) -> None: +//| """Not used. Access the sole instance through `alarm.sleep_memory`.""" +//| ... +//| +//| def __bool__(self) -> bool: +//| """``sleep_memory`` is ``True`` if its length is greater than zero. +//| This is an easy way to check for its existence. +//| """ +//| ... +//| +//| def __len__(self) -> int: +//| """Return the length. This is used by (`len`)""" +//| ... +//| +STATIC mp_obj_t alarm_sleep_memory_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + alarm_sleep_memory_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint16_t len = common_hal_alarm_sleep_memory_get_length(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 alarm_sleep_memory_locals_dict_table[] = { +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_sleep_memory_locals_dict, alarm_sleep_memory_locals_dict_table); + +//| @overload +//| def __getitem__(self, index: slice) -> bytearray: ... +//| @overload +//| def __getitem__(self, index: int) -> int: +//| """Returns the value at the given index.""" +//| ... +//| +//| @overload +//| def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ... +//| @overload +//| def __setitem__(self, index: int, value: int) -> None: +//| """Set the value at the given index.""" +//| ... +//| +STATIC mp_obj_t alarm_sleep_memory_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { + if (value == MP_OBJ_NULL) { + // delete item + // slice deletion + return MP_OBJ_NULL; // op not supported + } else { + alarm_sleep_memory_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (0) { +#if MICROPY_PY_BUILTINS_SLICE + } else if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + mp_bound_slice_t slice; + if (!mp_seq_get_fast_slice_indexes(common_hal_alarm_sleep_memory_get_length(self), index_in, &slice)) { + mp_raise_NotImplementedError(translate("only slices with step=1 (aka None) are supported")); + } + if (value != MP_OBJ_SENTINEL) { + #if MICROPY_PY_ARRAY_SLICE_ASSIGN + // Assign + size_t src_len = slice.stop - slice.start; + uint8_t* src_items; + if (MP_OBJ_IS_TYPE(value, &mp_type_array) || + MP_OBJ_IS_TYPE(value, &mp_type_bytearray) || + MP_OBJ_IS_TYPE(value, &mp_type_memoryview) || + MP_OBJ_IS_TYPE(value, &mp_type_bytes)) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); + if (bufinfo.len != src_len) { + mp_raise_ValueError(translate("Slice and value different lengths.")); + } + src_len = bufinfo.len; + src_items = bufinfo.buf; + if (1 != mp_binary_get_size('@', bufinfo.typecode, NULL)) { + mp_raise_ValueError(translate("Array values should be single bytes.")); + } + } else { + mp_raise_NotImplementedError(translate("array/bytes required on right side")); + } + + if (!common_hal_alarm_sleep_memory_set_bytes(self, slice.start, src_items, src_len)) { + mp_raise_RuntimeError(translate("Unable to write to sleep_memory.")); + } + return mp_const_none; + #else + return MP_OBJ_NULL; // op not supported + #endif + } else { + // Read slice. + size_t len = slice.stop - slice.start; + uint8_t *items = m_new(uint8_t, len); + common_hal_alarm_sleep_memory_get_bytes(self, slice.start, items, len); + return mp_obj_new_bytearray_by_ref(len, items); + } +#endif + } else { + // Single index rather than slice. + size_t index = mp_get_index(self->base.type, common_hal_alarm_sleep_memory_get_length(self), + index_in, false); + if (value == MP_OBJ_SENTINEL) { + // load + uint8_t value_out; + common_hal_alarm_sleep_memory_get_bytes(self, index, &value_out, 1); + return MP_OBJ_NEW_SMALL_INT(value_out); + } else { + // store + mp_int_t byte_value = mp_obj_get_int(value); + if (byte_value > 0xff || byte_value < 0) { + mp_raise_ValueError(translate("Bytes must be between 0 and 255.")); + } + uint8_t short_value = byte_value; + if (!common_hal_alarm_sleep_memory_set_bytes(self, index, &short_value, 1)) { + mp_raise_RuntimeError(translate("Unable to write to sleep_memory.")); + } + return mp_const_none; + } + } + } +} + +const mp_obj_type_t alarm_sleep_memory_type = { + { &mp_type_type }, + .name = MP_QSTR_SleepMemory, + .subscr = alarm_sleep_memory_subscr, + .unary_op = alarm_sleep_memory_unary_op, + .print = NULL, + .locals_dict = (mp_obj_t)&alarm_sleep_memory_locals_dict, +}; diff --git a/shared-bindings/alarm/SleepMemory.h b/shared-bindings/alarm/SleepMemory.h new file mode 100644 index 000000000..e7a56521b --- /dev/null +++ b/shared-bindings/alarm/SleepMemory.h @@ -0,0 +1,40 @@ +/* + * 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) 2020 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_ALARM_SLEEPMEMORY_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_SLEEPMEMORY_H + +#include "common-hal/alarm/SleepMemory.h" + +extern const mp_obj_type_t alarm_sleep_memory_type; + +uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self); + +bool common_hal_alarm_sleep_memory_set_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, const uint8_t* values, uint32_t len); +void common_hal_alarm_sleep_memory_get_bytes(alarm_sleep_memory_obj_t *self, uint32_t start_index, uint8_t* values, uint32_t len); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_SLEEPMEMORY_H diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c new file mode 100644 index 000000000..7023c70e5 --- /dev/null +++ b/shared-bindings/alarm/__init__.c @@ -0,0 +1,244 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" +#include "py/reload.h" +#include "py/runtime.h" + +#include "shared-bindings/alarm/__init__.h" +#include "shared-bindings/alarm/SleepMemory.h" +#include "shared-bindings/alarm/pin/PinAlarm.h" +#include "shared-bindings/alarm/time/TimeAlarm.h" +#include "shared-bindings/alarm/touch/TouchAlarm.h" +#include "shared-bindings/supervisor/Runtime.h" +#include "shared-bindings/time/__init__.h" +#include "supervisor/shared/autoreload.h" +#include "supervisor/shared/workflow.h" + +//| """Alarms and sleep +//| +//| Provides alarms that trigger based on time intervals or on external events, such as pin +//| changes. +//| The program can simply wait for these alarms, or go to sleep and be awoken when they trigger. +//| +//| There are two supported levels of sleep: light sleep and deep sleep. +//| +//| Light sleep keeps sufficient state so the program can resume after sleeping. +//| It does not shut down WiFi, BLE, or other communications, or ongoing activities such +//| as audio playback. It reduces power consumption to the extent possible that leaves +//| these continuing activities running. In some cases there may be no decrease in power consumption. +//| +//| Deep sleep shuts down power to nearly all of the microcontroller including the CPU and RAM. This can save +//| a more significant amount of power, but CircuitPython must restart ``code.py`` from the beginning when +//| awakened. +//| +//| For both light sleep and deep sleep, if CircuitPython is connected to a host computer, +//| maintaining the connection takes priority and power consumption may not be reduced. +//| """ + +//| sleep_memory: SleepMemory +//| """Memory that persists during deep sleep. +//| This object is the sole instance of `alarm.SleepMemory`.""" +//| + +//| wake_alarm: Alarm +//| """The most recently triggered alarm. If CircuitPython was sleeping, the alarm the woke it from sleep.""" +//| + +// wake_alarm is implemented as a dictionary entry, so there's no code here. + +void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) { + for (size_t i = 0; i < n_args; i++) { + if (MP_OBJ_IS_TYPE(objs[i], &alarm_pin_pinalarm_type) || + MP_OBJ_IS_TYPE(objs[i], &alarm_time_timealarm_type) || + MP_OBJ_IS_TYPE(objs[i], &alarm_touch_touchalarm_type)) { + continue; + } + mp_raise_TypeError_varg(translate("Expected an alarm")); + } +} + +//| def light_sleep_until_alarms(*alarms: Alarm) -> Alarm: +//| """Go into a light sleep until awakened one of the alarms. The alarm causing the wake-up +//| is returned, and is also available as `alarm.wake_alarm`. +//| +//| If no alarms are specified, return immediately. +//| +//| **If CircuitPython is connected to a host computer, the connection will be maintained, +//| and the microcontroller may not actually go into a light sleep.** +//| This allows the user to interrupt an existing program with ctrl-C, +//| and to edit the files in CIRCUITPY, which would not be possible in true light sleep. +//| Thus, to use light sleep and save significant power, +// it may be necessary to disconnect from the host. +//| """ +//| ... +//| +STATIC mp_obj_t alarm_light_sleep_until_alarms(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return mp_const_none; + } + + validate_objs_are_alarms(n_args, args); + + return common_hal_alarm_light_sleep_until_alarms(n_args, args); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_light_sleep_until_alarms); + +//| def exit_and_deep_sleep_until_alarms(*alarms: Alarm) -> None: +//| """Exit the program and go into a deep sleep, until awakened by one of the alarms. +//| This function does not return. +//| +//| When awakened, the microcontroller will restart and will run ``boot.py`` and ``code.py`` +//| from the beginning. +//| +//| After restart, an alarm *equivalent* to the one that caused the wake-up +//| will be available as `alarm.wake_alarm`. +//| Its type and/or attributes may not correspond exactly to the original alarm. +//| For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created. +//| +//| If no alarms are specified, the microcontroller will deep sleep until reset. +//| +//| **If CircuitPython is connected to a host computer, the connection will be maintained, +//| and the system will not go into deep sleep.** +//| This allows the user to interrupt an existing program with ctrl-C, +//| and to edit the files in CIRCUITPY, which would not be possible in true deep sleep. +//| Thus, to use deep sleep and save significant power, you will need to disconnect from the host. +//| +//| Here is skeletal example that deep-sleeps and restarts every 60 seconds: +//| +//| .. code-block:: python +//| +//| import alarm +//| import time +//| +//| print("Waking up") +//| +//| # Set an alarm for 60 seconds from now. +//| time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60) +//| +//| # Deep sleep until the alarm goes off. Then restart the program. +//| alarm.exit_and_deep_sleep_until_alarms(time_alarm) +//| """ +//| ... +//| +STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *args) { + validate_objs_are_alarms(n_args, args); + + // Validate the alarms and set them. + common_hal_alarm_set_deep_sleep_alarms(n_args, args); + + // Raise an exception, which will be processed in main.c. + mp_raise_arg1(&mp_type_DeepSleepRequest, NULL); + + // Doesn't get here. + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_exit_and_deep_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_exit_and_deep_sleep_until_alarms); + +STATIC const mp_map_elem_t alarm_pin_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pin) }, + + { MP_ROM_QSTR(MP_QSTR_PinAlarm), MP_OBJ_FROM_PTR(&alarm_pin_pinalarm_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_pin_globals, alarm_pin_globals_table); + +STATIC const mp_obj_module_t alarm_pin_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&alarm_pin_globals, +}; + +STATIC const mp_map_elem_t alarm_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) }, + + { MP_ROM_QSTR(MP_QSTR_TimeAlarm), MP_OBJ_FROM_PTR(&alarm_time_timealarm_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_time_globals, alarm_time_globals_table); + +STATIC const mp_obj_module_t alarm_time_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&alarm_time_globals, +}; + +STATIC const mp_map_elem_t alarm_touch_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_touch) }, + { MP_ROM_QSTR(MP_QSTR_TouchAlarm), MP_OBJ_FROM_PTR(&alarm_touch_touchalarm_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_touch_globals, alarm_touch_globals_table); + +STATIC const mp_obj_module_t alarm_touch_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&alarm_touch_globals, +}; + +// The module table is mutable because .wake_alarm is a mutable attribute. +STATIC mp_map_elem_t alarm_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_alarm) }, + + // wake_alarm is a mutable attribute. + { MP_ROM_QSTR(MP_QSTR_wake_alarm), mp_const_none }, + + { MP_ROM_QSTR(MP_QSTR_light_sleep_until_alarms), MP_OBJ_FROM_PTR(&alarm_light_sleep_until_alarms_obj) }, + { MP_ROM_QSTR(MP_QSTR_exit_and_deep_sleep_until_alarms), + MP_OBJ_FROM_PTR(&alarm_exit_and_deep_sleep_until_alarms_obj) }, + + { MP_ROM_QSTR(MP_QSTR_pin), MP_OBJ_FROM_PTR(&alarm_pin_module) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_OBJ_FROM_PTR(&alarm_time_module) }, + { MP_ROM_QSTR(MP_QSTR_touch), MP_OBJ_FROM_PTR(&alarm_touch_module) }, + + { MP_ROM_QSTR(MP_QSTR_SleepMemory), MP_OBJ_FROM_PTR(&alarm_sleep_memory_type) }, + { MP_ROM_QSTR(MP_QSTR_sleep_memory), MP_OBJ_FROM_PTR(&alarm_sleep_memory_obj) }, +}; +STATIC MP_DEFINE_MUTABLE_DICT(alarm_module_globals, alarm_module_globals_table); + +// Fetch value from module dict. +mp_obj_t alarm_get_wake_alarm(void) { + mp_map_elem_t *elem = + mp_map_lookup(&alarm_module_globals.map, MP_ROM_QSTR(MP_QSTR_wake_alarm), MP_MAP_LOOKUP); + if (elem) { + return elem->value; + } else { + return NULL; + } +} + +// Initialize .wake_alarm value. +void alarm_save_wake_alarm(void) { + // Equivalent of: + // alarm.wake_alarm = alarm + mp_map_elem_t *elem = + mp_map_lookup(&alarm_module_globals.map, MP_ROM_QSTR(MP_QSTR_wake_alarm), MP_MAP_LOOKUP); + if (elem) { + elem->value = common_hal_alarm_get_wake_alarm(); + } +} + +const mp_obj_module_t alarm_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&alarm_module_globals, +}; diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h new file mode 100644 index 000000000..154f91e26 --- /dev/null +++ b/shared-bindings/alarm/__init__.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H + +#include "py/obj.h" + +#include "common-hal/alarm/__init__.h" + +extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms); + +// Deep sleep is a two step process. Alarms are set when the VM is valid but +// everything is reset before entering deep sleep. Furthermore, deep sleep may +// not actually happen if the user is connected to the device. In this case, the +// supervisor will idle using `port_wait_for_interrupt`. After each call, it will +// call alarm_woken_from_sleep to see if we've been woken by an alarm and if so, +// it will exit idle as if deep sleep was exited. +extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms); +// Deep sleep is entered outside of the VM so we omit the `common_hal_` prefix. +extern NORETURN void alarm_enter_deep_sleep(void); + +// Fetches value from module dict. +extern mp_obj_t alarm_get_wake_alarm(void); + +extern void common_hal_alarm_gc_collect(void); +extern mp_obj_t common_hal_alarm_get_wake_alarm(void); + +// Used by wake-up code. +void alarm_save_wake_alarm(void); + + +// True if an alarm is alerting. This is most useful for pretend deep sleep. +extern bool alarm_woken_from_sleep(void); + + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H diff --git a/shared-bindings/alarm/pin/PinAlarm.c b/shared-bindings/alarm/pin/PinAlarm.c new file mode 100644 index 000000000..89de016bc --- /dev/null +++ b/shared-bindings/alarm/pin/PinAlarm.c @@ -0,0 +1,135 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/alarm/pin/PinAlarm.h" + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +//| class PinAlarm: +//| """Trigger an alarm when a pin changes state.""" +//| +//| def __init__(self, pin: microcontroller.Pin, value: bool, edge: bool = False, pull: bool = False) -> None: +//| """Create an alarm triggered by a `microcontroller.Pin` level. The alarm is not active +//| until it is passed to an `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or +//| `alarm.exit_and_deep_sleep_until_alarms()`. +//| +//| :param microcontroller.Pin pin: The pin to monitor. On some ports, the choice of pin +//| may be limited due to hardware restrictions, particularly for deep-sleep alarms. +//| :param bool value: When active, trigger when the pin value is high (``True``) or low (``False``). +//| On some ports, multiple `PinAlarm` objects may need to have coordinated values +//| for deep-sleep alarms. +//| :param bool edge: If ``True``, trigger only when there is a transition to the specified +//| value of ``value``. If ``True``, if the alarm becomes active when the pin value already +//| matches ``value``, the alarm is not triggered: the pin must transition from ``not value`` +//| to ``value`` to trigger the alarm. On some ports, edge-triggering may not be available, +//| particularly for deep-sleep alarms. +//| :param bool pull: Enable a pull-up or pull-down which pulls the pin to the level opposite +//| that of ``value``. For instance, if ``value`` is set to ``True``, setting ``pull`` +//| to ``True`` will enable a pull-down, to hold the pin low normally until an outside signal +//| pulls it high. +//| """ +//| ... +//| +STATIC mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + alarm_pin_pinalarm_obj_t *self = m_new_obj(alarm_pin_pinalarm_obj_t); + self->base.type = &alarm_pin_pinalarm_type; + enum { ARG_pin, ARG_value, ARG_edge, ARG_pull }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_edge, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(0, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj); + + common_hal_alarm_pin_pinalarm_construct(self, + pin, + args[ARG_value].u_bool, + args[ARG_edge].u_bool, + args[ARG_pull].u_bool); + + return MP_OBJ_FROM_PTR(self); +} + +//| pin: microcontroller.Pin +//| """The trigger pin.""" +//| +STATIC mp_obj_t alarm_pin_pinalarm_obj_get_pin(mp_obj_t self_in) { + alarm_pin_pinalarm_obj_t *self = MP_OBJ_TO_PTR(self_in); + mcu_pin_obj_t* pin = common_hal_alarm_pin_pinalarm_get_pin(self); + if (pin == NULL) { + return mp_const_none; + } + return MP_OBJ_FROM_PTR(pin); +} +MP_DEFINE_CONST_FUN_OBJ_1(alarm_pin_pinalarm_get_pin_obj, alarm_pin_pinalarm_obj_get_pin); + +const mp_obj_property_t alarm_pin_pinalarm_pin_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&alarm_pin_pinalarm_get_pin_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| value: bool +//| """The value on which to trigger.""" +//| +STATIC mp_obj_t alarm_pin_pinalarm_obj_get_value(mp_obj_t self_in) { + alarm_pin_pinalarm_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_alarm_pin_pinalarm_get_value(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(alarm_pin_pinalarm_get_value_obj, alarm_pin_pinalarm_obj_get_value); + +const mp_obj_property_t alarm_pin_pinalarm_value_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&alarm_pin_pinalarm_get_value_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t alarm_pin_pinalarm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&alarm_pin_pinalarm_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&alarm_pin_pinalarm_value_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_pin_pinalarm_locals_dict, alarm_pin_pinalarm_locals_dict_table); + +const mp_obj_type_t alarm_pin_pinalarm_type = { + { &mp_type_type }, + .name = MP_QSTR_PinAlarm, + .make_new = alarm_pin_pinalarm_make_new, + .locals_dict = (mp_obj_t)&alarm_pin_pinalarm_locals_dict, +}; diff --git a/shared-bindings/alarm/pin/PinAlarm.h b/shared-bindings/alarm/pin/PinAlarm.h new file mode 100644 index 000000000..48865009c --- /dev/null +++ b/shared-bindings/alarm/pin/PinAlarm.h @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H + +#include "py/obj.h" +#include "py/objtuple.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/alarm/pin/PinAlarm.h" + +extern const mp_obj_type_t alarm_pin_pinalarm_type; + +void common_hal_alarm_pin_pinalarm_construct(alarm_pin_pinalarm_obj_t *self, mcu_pin_obj_t *pin, bool value, bool edge, bool pull); +extern mcu_pin_obj_t *common_hal_alarm_pin_pinalarm_get_pin(alarm_pin_pinalarm_obj_t *self); +extern bool common_hal_alarm_pin_pinalarm_get_value(alarm_pin_pinalarm_obj_t *self); +extern bool common_hal_alarm_pin_pinalarm_get_edge(alarm_pin_pinalarm_obj_t *self); +extern bool common_hal_alarm_pin_pinalarm_get_pull(alarm_pin_pinalarm_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_PIN_PINALARM_H diff --git a/shared-bindings/alarm/time/TimeAlarm.c b/shared-bindings/alarm/time/TimeAlarm.c new file mode 100644 index 000000000..1c9b8d37c --- /dev/null +++ b/shared-bindings/alarm/time/TimeAlarm.c @@ -0,0 +1,143 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/alarm/time/TimeAlarm.h" + +#include "supervisor/shared/translate.h" + +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE +mp_obj_t MP_WEAK rtc_get_time_source_time(void) { + mp_raise_RuntimeError(translate("RTC is not supported on this board")); +} +#endif + +//| class TimeAlarm: +//| """Trigger an alarm when the specified time is reached.""" +//| +//| def __init__(self, monotonic_time: Optional[float] = None, epoch_time: Optional[int] = None) -> None: +//| """Create an alarm that will be triggered when `time.monotonic()` would equal +//| ``monotonic_time``, or when `time.time()` would equal ``epoch_time``. +//| Only one of the two arguments can be given. +//| The alarm is not active until it is passed to an +//| `alarm`-enabling function, such as `alarm.light_sleep_until_alarms()` or +//| `alarm.exit_and_deep_sleep_until_alarms()`. +//| +//| If the given time is in the past when sleep occurs, the alarm will be triggered +//| immediately. +//| """ +//| ... +//| +STATIC mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, + mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + alarm_time_timealarm_obj_t *self = m_new_obj(alarm_time_timealarm_obj_t); + self->base.type = &alarm_time_timealarm_type; + + enum { ARG_monotonic_time, ARG_epoch_time }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_monotonic_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_epoch_time, 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, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bool have_monotonic = args[ARG_monotonic_time].u_obj != mp_const_none; + bool have_epoch = args[ARG_epoch_time].u_obj != mp_const_none; + + if (!(have_monotonic ^ have_epoch)) { + mp_raise_ValueError(translate("Supply one of monotonic_time or epoch_time")); + } + + mp_float_t monotonic_time = 0; // To avoid compiler warning. + if (have_monotonic) { + monotonic_time = mp_obj_get_float(args[ARG_monotonic_time].u_obj); + } + + mp_float_t monotonic_time_now = common_hal_time_monotonic_ms() / 1000.0; + + if (have_epoch) { +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + mp_raise_ValueError(translate("epoch_time not supported on this board")); +#else + mp_uint_t epoch_time_secs = mp_obj_int_get_checked(args[ARG_epoch_time].u_obj); + + timeutils_struct_time_t tm; + struct_time_to_tm(rtc_get_time_source_time(), &tm); + mp_uint_t epoch_secs_now = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + // How far in the future (in secs) is the requested time? + mp_int_t epoch_diff = epoch_time_secs - epoch_secs_now; + // Convert it to a future monotonic time. + monotonic_time = monotonic_time_now + epoch_diff; +#endif + } + + if (monotonic_time < monotonic_time_now) { + mp_raise_ValueError(translate("Time is in the past.")); + } + + common_hal_alarm_time_timealarm_construct(self, monotonic_time); + + return MP_OBJ_FROM_PTR(self); +} + +//| monotonic_time: float +//| """When this time is reached, the alarm will trigger, based on the `time.monotonic()` clock. +//| The time may be given as ``epoch_time`` in the constructor, but it is returned +//| by this property only as a `time.monotonic()` time. +//| """ +//| +STATIC mp_obj_t alarm_time_timealarm_obj_get_monotonic_time(mp_obj_t self_in) { + alarm_time_timealarm_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_float(common_hal_alarm_time_timealarm_get_monotonic_time(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(alarm_time_timealarm_get_monotonic_time_obj, alarm_time_timealarm_obj_get_monotonic_time); + +const mp_obj_property_t alarm_time_timealarm_monotonic_time_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&alarm_time_timealarm_get_monotonic_time_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t alarm_time_timealarm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_monotonic_time), MP_ROM_PTR(&alarm_time_timealarm_monotonic_time_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(alarm_time_timealarm_locals_dict, alarm_time_timealarm_locals_dict_table); + +const mp_obj_type_t alarm_time_timealarm_type = { + { &mp_type_type }, + .name = MP_QSTR_TimeAlarm, + .make_new = alarm_time_timealarm_make_new, + .locals_dict = (mp_obj_t)&alarm_time_timealarm_locals_dict, +}; diff --git a/shared-bindings/alarm/time/TimeAlarm.h b/shared-bindings/alarm/time/TimeAlarm.h new file mode 100644 index 000000000..0a4b9caf4 --- /dev/null +++ b/shared-bindings/alarm/time/TimeAlarm.h @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Dan Halbert for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H + +#include "py/obj.h" + +#include "common-hal/alarm/time/TimeAlarm.h" + +extern const mp_obj_type_t alarm_time_timealarm_type; + +extern void common_hal_alarm_time_timealarm_construct(alarm_time_timealarm_obj_t *self, mp_float_t monotonic_time); +extern mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timealarm_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TIME_TIMEALARM_H diff --git a/shared-bindings/alarm/touch/TouchAlarm.c b/shared-bindings/alarm/touch/TouchAlarm.c new file mode 100644 index 000000000..4259b71bd --- /dev/null +++ b/shared-bindings/alarm/touch/TouchAlarm.c @@ -0,0 +1,91 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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/alarm/touch/TouchAlarm.h" +#include "shared-bindings/board/__init__.h" + +#include "py/objproperty.h" + +//| class TouchAlarm: +//| """Trigger an alarm when touch is detected.""" +//| +//| def __init__(self, *pin: microcontroller.Pin) -> None: +//| """Create an alarm that will be triggered when the given pin is touched. +//| The alarm is not active until it is passed to an `alarm`-enabling function, such as +//| `alarm.light_sleep_until_alarms()` or `alarm.exit_and_deep_sleep_until_alarms()`. +//| +//| :param microcontroller.Pin pin: The pin to monitor. On some ports, the choice of pin +//| may be limited due to hardware restrictions, particularly for deep-sleep alarms. +//| """ +//| ... +//| +STATIC mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type, + mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + alarm_touch_touchalarm_obj_t *self = m_new_obj(alarm_touch_touchalarm_obj_t); + self->base.type = &alarm_touch_touchalarm_type; + + enum { ARG_pin }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, 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); + + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj); + + common_hal_alarm_touch_touchalarm_construct(self, pin); + + return MP_OBJ_FROM_PTR(self); +} + +//| pin: microcontroller.Pin +//| """The trigger pin.""" +//| +STATIC mp_obj_t alarm_touch_touchalarm_obj_get_pin(mp_obj_t self_in) { + alarm_touch_touchalarm_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(self->pin); +} +MP_DEFINE_CONST_FUN_OBJ_1(alarm_touch_touchalarm_get_pin_obj, alarm_touch_touchalarm_obj_get_pin); + +const mp_obj_property_t alarm_touch_touchalarm_pin_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&alarm_touch_touchalarm_get_pin_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t alarm_touch_touchalarm_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&alarm_touch_touchalarm_pin_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(alarm_touch_touchalarm_locals_dict, alarm_touch_touchalarm_locals_dict_table); + +const mp_obj_type_t alarm_touch_touchalarm_type = { + { &mp_type_type }, + .name = MP_QSTR_TouchAlarm, + .make_new = alarm_touch_touchalarm_make_new, + .locals_dict = (mp_obj_t)&alarm_touch_touchalarm_locals_dict, +}; diff --git a/shared-bindings/alarm/touch/TouchAlarm.h b/shared-bindings/alarm/touch/TouchAlarm.h new file mode 100644 index 000000000..1b70d4dae --- /dev/null +++ b/shared-bindings/alarm/touch/TouchAlarm.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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_ALARM_TOUCH_TOUCHALARM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TOUCH_TOUCHALARM_H + +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/alarm/touch/TouchAlarm.h" + +extern const mp_obj_type_t alarm_touch_touchalarm_type; + +extern void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM_TOUCH_TOUCHALARM_H diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 6c5fa7939..a3cc8b07e 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -84,6 +84,9 @@ //| ... //| STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +#if !CIRCUITPY_AUDIOBUSIO_PDMIN + mp_raise_NotImplementedError(translate("PDMIn not available")); +#else enum { ARG_clock_pin, ARG_data_pin, ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_oversample, ARG_startup_delay }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -132,8 +135,10 @@ STATIC mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar mp_hal_delay_ms(startup_delay * 1000); return MP_OBJ_FROM_PTR(self); +#endif } +#if CIRCUITPY_AUDIOBUSIO_PDMIN //| def deinit(self) -> None: //| """Deinitialises the PDMIn and releases any hardware resources for reuse.""" //| ... @@ -237,10 +242,13 @@ STATIC const mp_rom_map_elem_t audiobusio_pdmin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audiobusio_pdmin_sample_rate_obj) } }; STATIC MP_DEFINE_CONST_DICT(audiobusio_pdmin_locals_dict, audiobusio_pdmin_locals_dict_table); +#endif const mp_obj_type_t audiobusio_pdmin_type = { { &mp_type_type }, .name = MP_QSTR_PDMIn, .make_new = audiobusio_pdmin_make_new, +#if CIRCUITPY_AUDIOBUSIO_PDMIN .locals_dict = (mp_obj_dict_t*)&audiobusio_pdmin_locals_dict, +#endif }; diff --git a/shared-bindings/audiobusio/PDMIn.h b/shared-bindings/audiobusio/PDMIn.h index c2a8bab2f..e89fc7e23 100644 --- a/shared-bindings/audiobusio/PDMIn.h +++ b/shared-bindings/audiobusio/PDMIn.h @@ -33,6 +33,7 @@ extern const mp_obj_type_t audiobusio_pdmin_type; +#if CIRCUITPY_AUDIOBUSIO_PDMIN void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t* self, const mcu_pin_obj_t* clock_pin, const mcu_pin_obj_t* data_pin, uint32_t sample_rate, uint8_t bit_depth, bool mono, uint8_t oversample); @@ -43,5 +44,6 @@ uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t* se uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t* self); uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t* self); // TODO(tannewt): Add record to file +#endif #endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOBUSIO_AUDIOOUT_H diff --git a/shared-bindings/audiopwmio/__init__.h b/shared-bindings/audiopwmio/__init__.h index e4b7067d1..d7956d31e 100644 --- a/shared-bindings/audiopwmio/__init__.h +++ b/shared-bindings/audiopwmio/__init__.h @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H -#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H #include "py/obj.h" // Nothing now. -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOPWMIO___INIT___H diff --git a/shared-bindings/camera/ImageFormat.c b/shared-bindings/camera/ImageFormat.c index d4bdddc56..9f2f9617f 100644 --- a/shared-bindings/camera/ImageFormat.c +++ b/shared-bindings/camera/ImageFormat.c @@ -38,7 +38,6 @@ //| RGB565: ImageFormat //| """RGB565 format.""" //| -const mp_obj_type_t camera_imageformat_type; const camera_imageformat_obj_t camera_imageformat_jpg_obj = { { &camera_imageformat_type }, diff --git a/shared-bindings/camera/ImageFormat.h b/shared-bindings/camera/ImageFormat.h index 8abc88438..32a36354f 100644 --- a/shared-bindings/camera/ImageFormat.h +++ b/shared-bindings/camera/ImageFormat.h @@ -35,7 +35,7 @@ typedef enum { IMAGEFORMAT_RGB565, } camera_imageformat_t; -const mp_obj_type_t camera_imageformat_type; +extern const mp_obj_type_t camera_imageformat_type; camera_imageformat_t camera_imageformat_obj_to_type(mp_obj_t obj); mp_obj_t camera_imageformat_type_to_obj(camera_imageformat_t mode); diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 0e6e9bfd9..88d3a1ba8 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -116,7 +116,7 @@ const mp_obj_property_t displayio_colorconverter_dither_obj = { STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_obj_t transparent_color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - mp_int_t transparent_color = mp_obj_get_int(&transparent_color); + mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj); common_hal_displayio_colorconverter_make_transparent(self, transparent_color); return mp_const_none; } @@ -128,7 +128,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, display STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - mp_int_t transparent_color = mp_obj_get_int(&transparent_color); + mp_int_t transparent_color = mp_obj_get_int(transparent_color_obj); common_hal_displayio_colorconverter_make_opaque(self, transparent_color); return mp_const_none; } diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index ebff64008..4f5c47aca 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -294,6 +294,29 @@ const mp_obj_property_t displayio_epaperdisplay_height_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| rotation: int +//| """The rotation of the display as an int in degrees.""" +//| +STATIC mp_obj_t displayio_epaperdisplay_obj_get_rotation(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_rotation(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_rotation_obj, displayio_epaperdisplay_obj_get_rotation); +STATIC mp_obj_t displayio_epaperdisplay_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + common_hal_displayio_epaperdisplay_set_rotation(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_set_rotation_obj, displayio_epaperdisplay_obj_set_rotation); + + +const mp_obj_property_t displayio_epaperdisplay_rotation_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_rotation_obj, + (mp_obj_t)&displayio_epaperdisplay_set_rotation_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| bus: _DisplayBus //| """The bus being used by the display""" //| @@ -317,6 +340,7 @@ STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_epaperdisplay_rotation_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&displayio_epaperdisplay_busy_obj) }, { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) }, diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index f785203a4..14d4f6aa9 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -56,6 +56,8 @@ bool common_hal_displayio_epaperdisplay_get_busy(displayio_epaperdisplay_obj_t* uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_rotation(displayio_epaperdisplay_obj_t* self); +void common_hal_displayio_epaperdisplay_set_rotation(displayio_epaperdisplay_obj_t* self, int rotation); mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); diff --git a/shared-bindings/dualbank/__init__.c b/shared-bindings/dualbank/__init__.c new file mode 100644 index 000000000..8021ab18b --- /dev/null +++ b/shared-bindings/dualbank/__init__.c @@ -0,0 +1,115 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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/dualbank/__init__.h" + +//| """DUALBANK Module +//| +//| The `dualbank` module adds ability to update and switch +//| between the two app partitions. +//| +//| There are two identical partitions, these contain different +//| firmware versions. +//| Having two partitions enables rollback functionality. +//| +//| The two partitions are defined as boot partition and +//| next-update partition. Calling `dualbank.flash()` writes +//| the next-update partition. +//| +//| After the next-update partition is written a validation +//| check is performed and on a successful validation this +//| partition is set as the boot partition. On next reset, +//| firmware will be loaded from this partition. +//| +//| Here is the sequence of commands to follow: +//| +//| .. code-block:: python +//| +//| import dualbank +//| +//| dualbank.flash(buffer, offset) +//| dualbank.switch() +//| """ +//| ... +//| + +//| def flash(*buffer: ReadableBuffer, offset: int=0) -> None: +//| """Writes one of two app partitions at the given offset. +//| +//| This can be called multiple times when flashing the firmware +//| in small chunks. +//| """ +//| ... +//| +STATIC mp_obj_t dualbank_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_offset }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_offset, MP_ARG_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); + + if (args[ARG_offset].u_int < 0) { + mp_raise_ValueError(translate("offset must be >= 0")); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + + common_hal_dualbank_flash(bufinfo.buf, bufinfo.len, args[ARG_offset].u_int); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dualbank_flash_obj, 0, dualbank_flash); + +//| def switch() -> None: +//| """Switches the boot partition. +//| +//| On next reset, firmware will be loaded from the partition +//| just switched over to. +//| """ +//| ... +//| +STATIC mp_obj_t dualbank_switch(void) { + common_hal_dualbank_switch(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(dualbank_switch_obj, dualbank_switch); + +STATIC const mp_rom_map_elem_t dualbank_module_globals_table[] = { + // module name + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_dualbank) }, + // module functions + { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&dualbank_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_switch), MP_ROM_PTR(&dualbank_switch_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(dualbank_module_globals, dualbank_module_globals_table); + +const mp_obj_module_t dualbank_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&dualbank_module_globals, +}; diff --git a/shared-bindings/dualbank/__init__.h b/shared-bindings/dualbank/__init__.h new file mode 100644 index 000000000..7edbc6d68 --- /dev/null +++ b/shared-bindings/dualbank/__init__.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * 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_DUALBANK___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_DUALBANK___INIT___H + +#include "py/runtime.h" + +extern void common_hal_dualbank_switch(void); +extern void common_hal_dualbank_flash(const void *buf, const size_t len, const size_t offset); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_DUALBANK___INIT___H diff --git a/shared-bindings/i2cperipheral/I2CPeripheral.c b/shared-bindings/i2cperipheral/I2CPeripheral.c index b5ac861b4..b5c268eb5 100644 --- a/shared-bindings/i2cperipheral/I2CPeripheral.c +++ b/shared-bindings/i2cperipheral/I2CPeripheral.c @@ -166,7 +166,7 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj if (timeout_ms == 0) { forever = true; } else if (timeout_ms > 0) { - timeout_end = common_hal_time_monotonic() + timeout_ms; + timeout_end = common_hal_time_monotonic_ms() + timeout_ms; } int last_error = 0; @@ -200,7 +200,7 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj } return mp_obj_new_i2cperipheral_i2c_peripheral_request(self, address, is_read, is_restart); - } while (forever || common_hal_time_monotonic() < timeout_end); + } while (forever || common_hal_time_monotonic_ms() < timeout_end); if (timeout_ms > 0) { mp_raise_OSError(MP_ETIMEDOUT); @@ -322,8 +322,8 @@ STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const m int i = 0; uint8_t *buffer = NULL; - uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000; - while (common_hal_time_monotonic() < timeout_end) { + uint64_t timeout_end = common_hal_time_monotonic_ms() + 10 * 1000; + while (common_hal_time_monotonic_ms() < timeout_end) { RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { break; diff --git a/shared-bindings/microcontroller/Processor.c b/shared-bindings/microcontroller/Processor.c index 8c703891d..90cc02fe3 100644 --- a/shared-bindings/microcontroller/Processor.c +++ b/shared-bindings/microcontroller/Processor.c @@ -67,6 +67,23 @@ const mp_obj_property_t mcu_processor_frequency_obj = { }, }; +//| reset_reason: microcontroller.ResetReason +//| """The reason the microcontroller started up from reset state.""" +//| +STATIC mp_obj_t mcu_processor_get_reset_reason(mp_obj_t self) { + return cp_enum_find(&mcu_reset_reason_type, common_hal_mcu_processor_get_reset_reason()); +} + +MP_DEFINE_CONST_FUN_OBJ_1(mcu_processor_get_reset_reason_obj, mcu_processor_get_reset_reason); + +const mp_obj_property_t mcu_processor_reset_reason_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&mcu_processor_get_reset_reason_obj, // getter + (mp_obj_t)&mp_const_none_obj, // no setter + (mp_obj_t)&mp_const_none_obj, // no deleter + }, +}; + //| temperature: Optional[float] //| """The on-chip temperature, in Celsius, as a float. (read-only) //| @@ -128,6 +145,7 @@ const mp_obj_property_t mcu_processor_voltage_obj = { STATIC const mp_rom_map_elem_t mcu_processor_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&mcu_processor_frequency_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_reason), MP_ROM_PTR(&mcu_processor_reset_reason_obj) }, { MP_ROM_QSTR(MP_QSTR_temperature), MP_ROM_PTR(&mcu_processor_temperature_obj) }, { MP_ROM_QSTR(MP_QSTR_uid), MP_ROM_PTR(&mcu_processor_uid_obj) }, { MP_ROM_QSTR(MP_QSTR_voltage), MP_ROM_PTR(&mcu_processor_voltage_obj) }, diff --git a/shared-bindings/microcontroller/Processor.h b/shared-bindings/microcontroller/Processor.h index 0f520f940..98d479087 100644 --- a/shared-bindings/microcontroller/Processor.h +++ b/shared-bindings/microcontroller/Processor.h @@ -30,10 +30,12 @@ #include "py/obj.h" #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/ResetReason.h" extern const mp_obj_type_t mcu_processor_type; uint32_t common_hal_mcu_processor_get_frequency(void); +mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void); float common_hal_mcu_processor_get_temperature(void); void common_hal_mcu_processor_get_uid(uint8_t raw_id[]); float common_hal_mcu_processor_get_voltage(void); diff --git a/shared-bindings/microcontroller/ResetReason.c b/shared-bindings/microcontroller/ResetReason.c new file mode 100644 index 000000000..1750e5520 --- /dev/null +++ b/shared-bindings/microcontroller/ResetReason.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 "py/obj.h" +#include "py/enum.h" + +#include "shared-bindings/microcontroller/ResetReason.h" + +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, RESET_REASON_POWER_ON); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, RESET_REASON_BROWNOUT); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, RESET_REASON_SOFTWARE); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, RESET_REASON_DEEP_SLEEP_ALARM); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, RESET_REASON_RESET_PIN); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, RESET_REASON_WATCHDOG); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, RESET_REASON_UNKNOWN); + +//| class ResetReason: +//| """The reason the microntroller was last reset""" +//| +//| POWER_ON: object +//| """The microntroller was started from power off.""" +//| +//| BROWNOUT: object +//| """The microntroller was reset due to too low a voltage.""" +//| +//| SOFTWARE: object +//| """The microntroller was reset from software.""" +//| +//| DEEP_SLEEP_ALARM: object +//| """The microntroller was reset for deep sleep and restarted by an alarm.""" +//| +//| RESET_PIN: object +//| """The microntroller was reset by a signal on its reset pin. The pin might be connected to a reset button.""" +//| +//| WATCHDOG: object +//| """The microcontroller was reset by its watchdog timer.""" +//| +//| UNKNOWN: object +//| """The microntroller restarted for an unknown reason.""" +//| +MAKE_ENUM_MAP(mcu_reset_reason) { + MAKE_ENUM_MAP_ENTRY(reset_reason, POWER_ON), + MAKE_ENUM_MAP_ENTRY(reset_reason, BROWNOUT), + MAKE_ENUM_MAP_ENTRY(reset_reason, SOFTWARE), + MAKE_ENUM_MAP_ENTRY(reset_reason, DEEP_SLEEP_ALARM), + MAKE_ENUM_MAP_ENTRY(reset_reason, RESET_PIN), + MAKE_ENUM_MAP_ENTRY(reset_reason, WATCHDOG), + MAKE_ENUM_MAP_ENTRY(reset_reason, UNKNOWN), +}; +STATIC MP_DEFINE_CONST_DICT(mcu_reset_reason_locals_dict, mcu_reset_reason_locals_table); + +MAKE_PRINTER(microcontroller, mcu_reset_reason); + +MAKE_ENUM_TYPE(microcontroller, ResetReason, mcu_reset_reason); diff --git a/shared-bindings/microcontroller/ResetReason.h b/shared-bindings/microcontroller/ResetReason.h new file mode 100644 index 000000000..8ed5e4831 --- /dev/null +++ b/shared-bindings/microcontroller/ResetReason.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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_MCU_RESET_REASON__H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MCU_RESET_REASON__H + +#include "py/obj.h" +#include "py/enum.h" + +typedef enum { + RESET_REASON_POWER_ON, + RESET_REASON_BROWNOUT, + RESET_REASON_SOFTWARE, + RESET_REASON_DEEP_SLEEP_ALARM, + RESET_REASON_RESET_PIN, + RESET_REASON_WATCHDOG, + RESET_REASON_UNKNOWN, +} mcu_reset_reason_t; + +extern const mp_obj_type_t mcu_reset_reason_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MCU_RESET_REASON__H diff --git a/shared-bindings/microcontroller/__init__.c b/shared-bindings/microcontroller/__init__.c index 2e58bdcc2..035587c30 100644 --- a/shared-bindings/microcontroller/__init__.c +++ b/shared-bindings/microcontroller/__init__.c @@ -39,7 +39,6 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" -#include "py/runtime.h" #include "supervisor/shared/translate.h" //| """Pin references and cpu functionality @@ -148,16 +147,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_reset_obj, mcu_reset); //| This object is the sole instance of `watchdog.WatchDogTimer` when available or ``None`` otherwise.""" //| - -//| """:mod:`microcontroller.pin` --- Microcontroller pin names -//| -------------------------------------------------------- -//| -//| .. module:: microcontroller.pin -//| :synopsis: Microcontroller pin names -//| :platform: SAMD21 -//| -//| References to pins as named by the microcontroller""" -//| const mp_obj_module_t mcu_pin_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mcu_pin_globals, @@ -181,6 +170,7 @@ STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = { #else { MP_ROM_QSTR(MP_QSTR_watchdog), MP_ROM_PTR(&mp_const_none_obj) }, #endif + { MP_ROM_QSTR(MP_QSTR_ResetReason), MP_ROM_PTR(&mcu_reset_reason_type) }, { 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) }, diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 8abdff763..0dafc74c7 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -1,4 +1,3 @@ - /* * This file is part of the MicroPython project, http://micropython.org/ * @@ -28,11 +27,11 @@ #ifndef MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H #define MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H -#include "py/mpconfig.h" #include "py/obj.h" +#include "py/mpconfig.h" #include "common-hal/microcontroller/Processor.h" - +#include "shared-bindings/microcontroller/ResetReason.h" #include "shared-bindings/microcontroller/RunMode.h" extern void common_hal_mcu_delay_us(uint32_t); diff --git a/shared-bindings/msgpack/ExtType.c b/shared-bindings/msgpack/ExtType.c new file mode 100644 index 000000000..e9ddd32bc --- /dev/null +++ b/shared-bindings/msgpack/ExtType.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Bernhard Boser + * + * 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 "py/smallint.h" +#include "py/objproperty.h" +#include "shared-bindings/msgpack/ExtType.h" + +//| class ExtType: +//| """ExtType represents ext type in msgpack.""" +//| def __init__(self, code: int, data: bytes) -> None: +//| """Constructor +//| :param int code: type code in range 0~127. +//| :param bytes data: representation.""" +//| +STATIC mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mod_msgpack_extype_obj_t *self = m_new_obj(mod_msgpack_extype_obj_t); + self->base.type = &mod_msgpack_exttype_type; + enum { ARG_code, ARG_data }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_code, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + 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); + + int code = args[ARG_code].u_int; + if (code < 0 || code > 127) { + mp_raise_AttributeError(translate("code outside range 0~127")); + } + self->code = code; + + mp_obj_t data = args[ARG_data].u_obj; + self->data = data; + return MP_OBJ_FROM_PTR(self); +} + + +//| code: int +//| """The type code, in range 0~127.""" +//| ... +//| +STATIC mp_obj_t mod_msgpack_exttype_get_code(mp_obj_t self_in) { + mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->code); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_code_obj, mod_msgpack_exttype_get_code); + +STATIC mp_obj_t mod_msgpack_exttype_set_code(mp_obj_t self_in, mp_obj_t code_in) { + mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in); + int code = mp_obj_get_int(code_in); + if (code < 0 || code > 127) { + mp_raise_AttributeError(translate("code outside range 0~127")); + } + self->code = code; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_code_obj, mod_msgpack_exttype_set_code); + +const mp_obj_property_t mod_msgpack_exttype_code_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&mod_msgpack_exttype_get_code_obj, + (mp_obj_t)&mod_msgpack_exttype_set_code_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| data: bytes +//| """Data.""" +//| ... +//| +STATIC mp_obj_t mod_msgpack_exttype_get_data(mp_obj_t self_in) { + mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->data; +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_msgpack_exttype_get_data_obj, mod_msgpack_exttype_get_data); + +STATIC mp_obj_t mod_msgpack_exttype_set_data(mp_obj_t self_in, mp_obj_t data_in) { + mod_msgpack_extype_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->data = data_in; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mod_msgpack_exttype_set_data_obj, mod_msgpack_exttype_set_data); + +const mp_obj_property_t mod_msgpack_exttype_data_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&mod_msgpack_exttype_get_data_obj, + (mp_obj_t)&mod_msgpack_exttype_set_data_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC mp_rom_map_elem_t mod_msgpack_exttype_locals_dict_table[] = { + // Properties + { MP_ROM_QSTR(MP_QSTR_code), MP_ROM_PTR(&mod_msgpack_exttype_code_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&mod_msgpack_exttype_data_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(mod_msgpack_exttype_locals_dict, mod_msgpack_exttype_locals_dict_table); + +const mp_obj_type_t mod_msgpack_exttype_type = { + { &mp_type_type }, + .name = MP_QSTR_ExtType, + .make_new = mod_msgpack_exttype_make_new, + .locals_dict = (mp_obj_dict_t*)&mod_msgpack_exttype_locals_dict, +}; diff --git a/shared-bindings/msgpack/ExtType.h b/shared-bindings/msgpack/ExtType.h new file mode 100644 index 000000000..64173b221 --- /dev/null +++ b/shared-bindings/msgpack/ExtType.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Bernhard Boser + * + * 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_MSGPACK_EXTTYPE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int32_t code; + mp_obj_t data; +} mod_msgpack_extype_obj_t; + +extern const mp_obj_type_t mod_msgpack_exttype_type; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK_EXTTYPE___INIT___H diff --git a/shared-bindings/msgpack/__init__.c b/shared-bindings/msgpack/__init__.c new file mode 100644 index 000000000..f5c47bb21 --- /dev/null +++ b/shared-bindings/msgpack/__init__.c @@ -0,0 +1,162 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Bernhard Boser + * + * 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 <stdio.h> +#include "py/obj.h" +#include "py/runtime.h" +#include "shared-bindings/msgpack/__init__.h" +#include "shared-module/msgpack/__init__.h" +#include "shared-bindings/msgpack/ExtType.h" + +#define MP_OBJ_IS_METH(o) (MP_OBJ_IS_OBJ(o) && (((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->name == MP_QSTR_bound_method)) + +//| """Pack object in msgpack format +//| +//| The msgpack format is similar to json, except that the encoded data is binary. +//| See https://msgpack.org for details. The module implements a subset of the cpython +//| module msgpack-python. +//| +//| Not implemented: 64-bit int, uint, float. +//| +//| Example 1:: +//| +//| import msgpack +//| from io import BytesIO +//| +//| b = BytesIO() +//| msgpack.pack({'list': [True, False, None, 1, 3.14], 'str': 'blah'}, b) +//| b.seek(0) +//| print(msgpack.unpack(b)) +//| +//| Example 2: handling objects:: +//| +//| from msgpack import pack, unpack, ExtType +//| from io import BytesIO +//| +//| class MyClass: +//| def __init__(self, val): +//| self.value = val +//| def __str__(self): +//| return str(self.value) +//| +//| data = MyClass(b'my_value') +//| +//| def encoder(obj): +//| if isinstance(obj, MyClass): +//| return ExtType(1, obj.value) +//| return f"no encoder for {obj}" +//| +//| def decoder(code, data): +//| if code == 1: +//| return MyClass(data) +//| return f"no decoder for type {code}" +//| +//| buffer = BytesIO() +//| pack(data, buffer, default=encoder) +//| buffer.seek(0) +//| decoded = unpack(buffer, ext_hook=decoder) +//| print(f"{data} -> {buffer.getvalue()} -> {decoded}") +//| +//| """ +//| + +//| def pack(obj: object, buffer: WriteableBuffer, *, default: Union[Callable[[object], None], None] = None) -> None: +//| """Ouput object to buffer in msgpack format. +//| +//| :param object obj: Object to convert to msgpack format. +//| :param ~_typing.WriteableBuffer buffer: buffer to write into +//| :param Optional[~_typing.Callable[[object], None]] default: +//| function called for python objects that do not have +//| a representation in msgpack format. +//| """ +//| ... +//| +STATIC mp_obj_t mod_msgpack_pack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_obj, ARG_buffer, ARG_default }; + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_obj, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_default, 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, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t handler = args[ARG_default].u_obj; + if (handler != mp_const_none && !MP_OBJ_IS_FUN(handler) && !MP_OBJ_IS_METH(handler)) { + mp_raise_ValueError(translate("default is not a function")); + } + + common_hal_msgpack_pack(args[ARG_obj].u_obj, args[ARG_buffer].u_obj, handler); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_pack_obj, 1, mod_msgpack_pack); + + +//| def unpack(buffer: ReadableBuffer, *, ext_hook: Union[Callable[[int, bytes], object], None] = None, use_list: bool=True) -> object: +//| """Unpack and return one object from buffer. +//| +//| :param ~_typing.ReadableBuffer buffer: buffer to read from +//| :param Optional[~_typing.Callable[[int, bytes], object]] ext_hook: function called for objects in +//| msgpack ext format. +//| :param Optional[bool] use_list: return array as list or tuple (use_list=False). +//| +//| :return object: object read from buffer. +//| """ +//| ... +//| +STATIC mp_obj_t mod_msgpack_unpack(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_ext_hook, ARG_use_list }; + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_ext_hook, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_obj = mp_const_none } }, + { MP_QSTR_use_list, 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); + + mp_obj_t hook = args[ARG_ext_hook].u_obj; + if (hook != mp_const_none && !MP_OBJ_IS_FUN(hook) && !MP_OBJ_IS_METH(hook)) { + mp_raise_ValueError(translate("ext_hook is not a function")); + } + + return common_hal_msgpack_unpack(args[ARG_buffer].u_obj, hook, args[ARG_use_list].u_bool); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mod_msgpack_unpack_obj, 1, mod_msgpack_unpack); + + +STATIC const mp_rom_map_elem_t msgpack_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_msgpack) }, + { MP_ROM_QSTR(MP_QSTR_ExtType), MP_ROM_PTR(&mod_msgpack_exttype_type) }, + { MP_ROM_QSTR(MP_QSTR_pack), MP_ROM_PTR(&mod_msgpack_pack_obj) }, + { MP_ROM_QSTR(MP_QSTR_unpack), MP_ROM_PTR(&mod_msgpack_unpack_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(msgpack_module_globals, msgpack_module_globals_table); + +const mp_obj_module_t msgpack_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&msgpack_module_globals, +}; diff --git a/shared-bindings/msgpack/__init__.h b/shared-bindings/msgpack/__init__.h new file mode 100644 index 000000000..a02ead0bd --- /dev/null +++ b/shared-bindings/msgpack/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 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_MSGPACK___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H + +#include "py/obj.h" + +// nothing for now + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MSGPACK___INIT___H diff --git a/shared-bindings/os/__init__.c b/shared-bindings/os/__init__.c index c499df972..8b9b38911 100644 --- a/shared-bindings/os/__init__.c +++ b/shared-bindings/os/__init__.c @@ -160,7 +160,7 @@ mp_obj_t os_stat(mp_obj_t path_in) { MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat); //| def statvfs(path: str) -> Tuple[int, int, int, int, int, int, int, int, int, int]: -//| """Get the status of a fileystem. +//| """Get the status of a filesystem. //| //| Returns a tuple with the filesystem information in the following order: //| @@ -168,10 +168,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat); //| * ``f_frsize`` -- fragment size //| * ``f_blocks`` -- size of fs in f_frsize units //| * ``f_bfree`` -- number of free blocks -//| * ``f_bavail`` -- number of free blocks for unpriviliged users +//| * ``f_bavail`` -- number of free blocks for unprivileged users //| * ``f_files`` -- number of inodes //| * ``f_ffree`` -- number of free inodes -//| * ``f_favail`` -- number of free inodes for unpriviliged users +//| * ``f_favail`` -- number of free inodes for unprivileged users //| * ``f_flag`` -- mount flags //| * ``f_namemax`` -- maximum filename length //| diff --git a/shared-bindings/ps2io/Ps2.c b/shared-bindings/ps2io/Ps2.c index 0977e08ff..07fa5cebb 100644 --- a/shared-bindings/ps2io/Ps2.c +++ b/shared-bindings/ps2io/Ps2.c @@ -116,8 +116,9 @@ STATIC void check_for_deinit(ps2io_ps2_obj_t *self) { //| ... //| 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]); + mp_check_self(MP_OBJ_IS_TYPE(args[0], &ps2io_ps2_type)); + ps2io_ps2_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_ps2io_ps2_deinit(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ps2io_ps2___exit___obj, 4, 4, ps2io_ps2_obj___exit__); diff --git a/shared-bindings/random/__init__.h b/shared-bindings/random/__init__.h index b5011b1a8..9e058051f 100644 --- a/shared-bindings/random/__init__.h +++ b/shared-bindings/random/__init__.h @@ -29,7 +29,7 @@ // This depends on shared_module because nearly all functionality is port // agnostic. The random module only depends on the common_hal_os_urandom or -// common_hal_time_monotonic to seed it initially. +// common_hal_time_monotonic_ms to seed it initially. void shared_modules_random_seed(mp_uint_t seed); mp_uint_t shared_modules_random_getrandbits(uint8_t n); diff --git a/shared-bindings/rotaryio/__init__.c b/shared-bindings/rotaryio/__init__.c index fd8578753..cd967baa4 100644 --- a/shared-bindings/rotaryio/__init__.c +++ b/shared-bindings/rotaryio/__init__.c @@ -39,8 +39,6 @@ //| `Wikipedia's Rotary Encoder page <https://en.wikipedia.org/wiki/Rotary_encoder>`_ for more //| background. //| -//| .. warning:: This module is not available in some SAMD21 (aka M0) 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/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index 362e4d7e8..0e6968d5f 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -36,6 +36,8 @@ #include "py/runtime.h" #include "py/mperrno.h" +#include "lib/netutils/netutils.h" + //| class Socket: //| """TCP, UDP and RAW socket. Cannot be created directly. Instead, call //| `SocketPool.socket()`. @@ -274,79 +276,63 @@ STATIC mp_obj_t socketpool_socket_recv_into(size_t n_args, const mp_obj_t *args) } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket_recv_into_obj, 2, 3, socketpool_socket_recv_into); -// //| def sendto(self, bytes: ReadableBuffer, address: tuple) -> int: -// //| """Send some bytes to a specific address. -// //| Suits sockets of type SOCK_DGRAM -// //| -// //| :param ~bytes bytes: some bytes to send -// //| :param ~tuple address: tuple of (remote_address, remote_port)""" -// //| ... -// //| - -// STATIC mp_obj_t socketpool_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { -// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); +//| def sendto(self, bytes: ReadableBuffer, address: Tuple[str, int]) -> int: +//| """Send some bytes to a specific address. +//| Suits sockets of type SOCK_DGRAM +//| +//| :param ~bytes bytes: some bytes to send +//| :param ~tuple address: tuple of (remote_address, remote_port)""" +//| ... +//| -// // // get the data -// // mp_buffer_info_t bufinfo; -// // mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); +STATIC mp_obj_t socketpool_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); -// // // get address -// // uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; -// // mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + // get the data + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); -// // // check if we need to select a NIC -// // socket_select_nic(self, ip); + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); -// // // call the NIC to sendto -// // int _errno; -// // mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); -// // if (ret == -1) { -// // mp_raise_OSError(_errno); -// // } -// mp_int_t ret = 0; + size_t hostlen; + const char* host = mp_obj_str_get_data(addr_items[0], &hostlen); + mp_int_t port = mp_obj_get_int(addr_items[1]); -// return mp_obj_new_int(ret); -// } -// STATIC MP_DEFINE_CONST_FUN_OBJ_3(socketpool_socket_sendto_obj, socketpool_socket_sendto); + mp_int_t ret = common_hal_socketpool_socket_sendto(self, host, hostlen, port, bufinfo.buf, bufinfo.len); + if (!ret) { + mp_raise_OSError(0); + } -// //| def recvfrom(self, bufsize: int) -> Tuple[bytes, tuple]: -// //| """Reads some bytes from the connected remote address. -// //| Suits sockets of type SOCK_STREAM -// //| -// //| Returns a tuple containing -// //| * a bytes() of length <= bufsize -// //| * a remote_address, which is a tuple of ip address and port number -// //| -// //| :param ~int bufsize: maximum number of bytes to receive""" -// //| ... -// //| + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socketpool_socket_sendto_obj, socketpool_socket_sendto); -// STATIC mp_obj_t socketpool_socket_recvfrom_into(mp_obj_t self_in, mp_obj_t len_in) { -// // mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); -// // if (self->nic == MP_OBJ_NULL) { -// // // not connected -// // mp_raise_OSError(MP_ENOTCONN); -// // } -// // vstr_t vstr; -// // vstr_init_len(&vstr, mp_obj_get_int(len_in)); -// // byte ip[4]; -// // mp_uint_t port; -// // int _errno; -// // mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); -// // if (ret == -1) { -// // mp_raise_OSError(_errno); -// // } -// mp_obj_t tuple[2]; -// // if (ret == 0) { -// // tuple[0] = mp_const_empty_bytes; -// // } else { -// // vstr.len = ret; -// // tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -// // } -// // tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); -// return mp_obj_new_tuple(2, tuple); -// } -// STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_recvfrom_into_obj, socketpool_socket_recvfrom_into); +//| def recvfrom_into(self, buffer: WriteableBuffer) -> Tuple[int, Tuple[str, int]]: +//| """Reads some bytes from a remote address. +//| +//| Returns a tuple containing +//| * the number of bytes received into the given buffer +//| * a remote_address, which is a tuple of ip address and port number +//| +//| :param object buffer: buffer to read into""" +//| ... +//| +STATIC mp_obj_t socketpool_socket_recvfrom_into(mp_obj_t self_in, mp_obj_t data_in) { + socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_WRITE); + + byte ip[4]; + mp_uint_t port; + mp_int_t ret = common_hal_socketpool_socket_recvfrom_into(self, + (byte*)bufinfo.buf, bufinfo.len, ip, &port); + mp_obj_t tuple_contents[2]; + tuple_contents[0] = mp_obj_new_int_from_uint(ret); + tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + return mp_obj_new_tuple(2, tuple_contents); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_recvfrom_into_obj, socketpool_socket_recvfrom_into); // //| def setsockopt(self, level: int, optname: int, value: int) -> None: // //| """Sets socket options""" @@ -449,8 +435,8 @@ STATIC const mp_rom_map_elem_t socketpool_socket_locals_dict_table[] = { // { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socketpool_socket_accept_obj) }, { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socketpool_socket_connect_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socketpool_socket_send_obj) }, - // { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socketpool_socket_sendto_obj) }, - // { MP_ROM_QSTR(MP_QSTR_recvfrom_into), MP_ROM_PTR(&socketpool_socket_recvfrom_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socketpool_socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom_into), MP_ROM_PTR(&socketpool_socket_recvfrom_into_obj) }, { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socketpool_socket_recv_into_obj) }, // { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socketpool_socket_setsockopt_obj) }, { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socketpool_socket_settimeout_obj) }, diff --git a/shared-bindings/socketpool/Socket.h b/shared-bindings/socketpool/Socket.h index f0be95c92..54fbe59b2 100644 --- a/shared-bindings/socketpool/Socket.h +++ b/shared-bindings/socketpool/Socket.h @@ -35,6 +35,10 @@ void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t* self, mp_u bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const char* host, size_t hostlen, mp_int_t port); mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len); mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self, const uint8_t* buf, mp_uint_t len); +mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t* self, + const char* host, size_t hostlen, uint8_t port, const uint8_t* buf, mp_uint_t len); +mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t* self, + uint8_t* buf, mp_uint_t len, uint8_t* ip, uint *port); void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self); bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t* self); bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t* self); diff --git a/shared-bindings/supervisor/RunReason.c b/shared-bindings/supervisor/RunReason.c new file mode 100644 index 000000000..a2a5fe13e --- /dev/null +++ b/shared-bindings/supervisor/RunReason.c @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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 "py/enum.h" + +#include "shared-bindings/supervisor/RunReason.h" + +MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, STARTUP, RUN_REASON_STARTUP); +MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, AUTO_RELOAD, RUN_REASON_AUTO_RELOAD); +MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, SUPERVISOR_RELOAD, RUN_REASON_SUPERVISOR_RELOAD); +MAKE_ENUM_VALUE(supervisor_run_reason_type, run_reason, REPL_RELOAD, RUN_REASON_REPL_RELOAD); + +//| class RunReason: +//| """The reason that CircuitPython started running.""" +//| +//| STARTUP: object +//| """CircuitPython started the microcontroller started up. See `microcontroller.Processor.reset_reason` +//| for more detail on why the microcontroller was started.""" +//| +//| AUTO_RELOAD: object +//| """CircuitPython restarted due to an external write to the filesystem.""" +//| +//| SUPERVISOR_RELOAD: object +//| """CircuitPython restarted due to a call to `supervisor.reload()`.""" +//| +//| REPL_RELOAD: object +//| """CircuitPython started due to the user typing CTRL-D in the REPL.""" +//| +MAKE_ENUM_MAP(supervisor_run_reason) { + MAKE_ENUM_MAP_ENTRY(run_reason, STARTUP), + MAKE_ENUM_MAP_ENTRY(run_reason, AUTO_RELOAD), + MAKE_ENUM_MAP_ENTRY(run_reason, SUPERVISOR_RELOAD), + MAKE_ENUM_MAP_ENTRY(run_reason, REPL_RELOAD), +}; +STATIC MP_DEFINE_CONST_DICT(supervisor_run_reason_locals_dict, supervisor_run_reason_locals_table); + +MAKE_PRINTER(supervisor, supervisor_run_reason); + +MAKE_ENUM_TYPE(supervisor, RunReason, supervisor_run_reason); diff --git a/shared-bindings/supervisor/RunReason.h b/shared-bindings/supervisor/RunReason.h new file mode 100644 index 000000000..391e6d306 --- /dev/null +++ b/shared-bindings/supervisor/RunReason.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 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. + */ + +#pragma once + +typedef enum { + RUN_REASON_STARTUP, + RUN_REASON_AUTO_RELOAD, + RUN_REASON_SUPERVISOR_RELOAD, + RUN_REASON_REPL_RELOAD, +} supervisor_run_reason_t; + +extern const mp_obj_type_t supervisor_run_reason_type; diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index bfca6e7b1..8e0259a3b 100755 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -25,9 +25,16 @@ */ #include <stdbool.h> +#include "py/obj.h" +#include "py/enum.h" +#include "py/runtime.h" #include "py/objproperty.h" + +#include "shared-bindings/supervisor/RunReason.h" #include "shared-bindings/supervisor/Runtime.h" +STATIC supervisor_run_reason_t _run_reason; + //TODO: add USB, REPL to description once they're operational //| class Runtime: //| """Current status of runtime objects. @@ -90,9 +97,29 @@ const mp_obj_property_t supervisor_serial_bytes_available_obj = { }; +//| run_reason: RunReason +//| """Returns why CircuitPython started running this particular time.""" +//| +STATIC mp_obj_t supervisor_get_run_reason(mp_obj_t self) { + return cp_enum_find(&supervisor_run_reason_type, _run_reason); +} +MP_DEFINE_CONST_FUN_OBJ_1(supervisor_get_run_reason_obj, supervisor_get_run_reason); + +const mp_obj_property_t supervisor_run_reason_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&supervisor_get_run_reason_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +void supervisor_set_run_reason(supervisor_run_reason_t run_reason) { + _run_reason = run_reason; +} + STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_serial_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_serial_bytes_available), MP_ROM_PTR(&supervisor_serial_bytes_available_obj) }, + { MP_ROM_QSTR(MP_QSTR_run_reason), MP_ROM_PTR(&supervisor_run_reason_obj) }, }; STATIC MP_DEFINE_CONST_DICT(supervisor_runtime_locals_dict, supervisor_runtime_locals_dict_table); diff --git a/shared-bindings/supervisor/Runtime.h b/shared-bindings/supervisor/Runtime.h index 2dc59c3ab..51ed7604d 100755 --- a/shared-bindings/supervisor/Runtime.h +++ b/shared-bindings/supervisor/Runtime.h @@ -30,9 +30,12 @@ #include <stdbool.h> #include "py/obj.h" +#include "shared-bindings/supervisor/RunReason.h" extern const mp_obj_type_t supervisor_runtime_type; +void supervisor_set_run_reason(supervisor_run_reason_t run_reason); + bool common_hal_get_serial_connected(void); bool common_hal_get_serial_bytes_available(void); diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index bc6fdbff5..ad8603047 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -32,7 +32,9 @@ #include "supervisor/shared/rgb_led_status.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/translate.h" +#include "supervisor/shared/workflow.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/supervisor/Runtime.h" @@ -88,6 +90,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_s //| STATIC mp_obj_t supervisor_reload(void) { reload_requested = true; + supervisor_set_run_reason(RUN_REASON_SUPERVISOR_RELOAD); mp_raise_reload_exception(); return mp_const_none; } @@ -111,11 +114,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_next_stack_limit_obj, supervisor_set_ne STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_disable_autoreload), MP_ROM_PTR(&supervisor_disable_autoreload_obj) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_set_rgb_status_brightness), MP_ROM_PTR(&supervisor_set_rgb_status_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_autoreload), MP_ROM_PTR(&supervisor_disable_autoreload_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_rgb_status_brightness), MP_ROM_PTR(&supervisor_set_rgb_status_brightness_obj) }, { MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) }, { MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) }, + { MP_ROM_QSTR(MP_QSTR_RunReason), MP_ROM_PTR(&supervisor_run_reason_type) }, { MP_ROM_QSTR(MP_QSTR_set_next_stack_limit), MP_ROM_PTR(&supervisor_set_next_stack_limit_obj) }, }; diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 44f82c62e..2624384af 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -51,9 +51,8 @@ //| ... //| STATIC mp_obj_t time_monotonic(void) { - uint64_t time64 = common_hal_time_monotonic(); - // 4294967296 = 2^32 - return mp_obj_new_float(((uint32_t) (time64 >> 32) * 4294967296.0f + (uint32_t) (time64 & 0xffffffff)) / 1000.0f); + uint64_t ticks_ms = common_hal_time_monotonic_ms(); + return mp_obj_new_float(uint64_to_float(ticks_ms) / 1000.0f); } MP_DEFINE_CONST_FUN_OBJ_0(time_monotonic_obj, time_monotonic); diff --git a/shared-bindings/time/__init__.h b/shared-bindings/time/__init__.h index ec96aea24..4e716e9df 100644 --- a/shared-bindings/time/__init__.h +++ b/shared-bindings/time/__init__.h @@ -35,7 +35,7 @@ extern mp_obj_t struct_time_from_tm(timeutils_struct_time_t *tm); extern void struct_time_to_tm(mp_obj_t t, timeutils_struct_time_t *tm); -extern uint64_t common_hal_time_monotonic(void); +extern uint64_t common_hal_time_monotonic_ms(void); extern uint64_t common_hal_time_monotonic_ns(void); extern void common_hal_time_delay_ms(uint32_t); diff --git a/shared-bindings/watchdog/WatchDogTimer.c b/shared-bindings/watchdog/WatchDogTimer.c index 09219f710..575021a21 100644 --- a/shared-bindings/watchdog/WatchDogTimer.c +++ b/shared-bindings/watchdog/WatchDogTimer.c @@ -66,6 +66,7 @@ STATIC mp_obj_t watchdog_watchdogtimer_feed(mp_obj_t self_in) { if (current_mode == WATCHDOGMODE_NONE) { mp_raise_ValueError(translate("WatchDogTimer is not currently running")); } + common_hal_watchdog_feed(self); return mp_const_none; } @@ -78,12 +79,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(watchdog_watchdogtimer_feed_obj, watchdog_watch //| STATIC mp_obj_t watchdog_watchdogtimer_deinit(mp_obj_t self_in) { watchdog_watchdogtimer_obj_t *self = MP_OBJ_TO_PTR(self_in); - watchdog_watchdogmode_t current_mode = common_hal_watchdog_get_mode(self); - - if (current_mode == WATCHDOGMODE_RESET) { - mp_raise_NotImplementedError(translate("WatchDogTimer cannot be deinitialized once mode is set to RESET")); - } - common_hal_watchdog_deinit(self); return mp_const_none; } diff --git a/shared-bindings/wifi/Network.c b/shared-bindings/wifi/Network.c index bf970a9c0..0f3006f2e 100644 --- a/shared-bindings/wifi/Network.c +++ b/shared-bindings/wifi/Network.c @@ -108,12 +108,45 @@ const mp_obj_property_t wifi_network_channel_obj = { (mp_obj_t)&mp_const_none_obj }, }; +//| country: str +//| """String id of the country code""" +//| +STATIC mp_obj_t wifi_network_get_country(mp_obj_t self) { + return common_hal_wifi_network_get_country(self); + +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_country_obj, wifi_network_get_country); + +const mp_obj_property_t wifi_network_country_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_network_get_country_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + +//| authmode: str +//| """String id of the authmode""" +//| +STATIC mp_obj_t wifi_network_get_authmode(mp_obj_t self) { + return common_hal_wifi_network_get_authmode(self); + +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_authmode_obj, wifi_network_get_authmode); + +const mp_obj_property_t wifi_network_authmode_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_network_get_authmode_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; STATIC const mp_rom_map_elem_t wifi_network_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ssid), MP_ROM_PTR(&wifi_network_ssid_obj) }, { MP_ROM_QSTR(MP_QSTR_bssid), MP_ROM_PTR(&wifi_network_bssid_obj) }, { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&wifi_network_rssi_obj) }, { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wifi_network_channel_obj) }, + { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&wifi_network_country_obj) }, + { MP_ROM_QSTR(MP_QSTR_authmode), MP_ROM_PTR(&wifi_network_authmode_obj) }, }; STATIC MP_DEFINE_CONST_DICT(wifi_network_locals_dict, wifi_network_locals_dict_table); diff --git a/shared-bindings/wifi/Network.h b/shared-bindings/wifi/Network.h index c9bbc685e..0f07e7b55 100644 --- a/shared-bindings/wifi/Network.h +++ b/shared-bindings/wifi/Network.h @@ -39,5 +39,7 @@ extern mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self); extern mp_obj_t common_hal_wifi_network_get_bssid(wifi_network_obj_t *self); extern mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self); extern mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self); +extern mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self); +extern mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_NETWORK_H diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index e81e8793c..8181fc4c9 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -48,17 +48,28 @@ //| //| enabled: bool -//| """True when the wifi radio is enabled.""" +//| """``True`` when the wifi radio is enabled. +//| If you set the value to ``False``, any open sockets will be closed. +//| """ //| STATIC mp_obj_t wifi_radio_get_enabled(mp_obj_t self) { return mp_obj_new_bool(common_hal_wifi_radio_get_enabled(self)); } MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_enabled_obj, wifi_radio_get_enabled); +static mp_obj_t wifi_radio_set_enabled(mp_obj_t self, mp_obj_t value) { + const bool enabled = mp_obj_is_true(value); + + common_hal_wifi_radio_set_enabled(self, enabled); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_enabled_obj, wifi_radio_set_enabled); + const mp_obj_property_t wifi_radio_enabled_obj = { .base.type = &mp_type_property, .proxy = { (mp_obj_t)&wifi_radio_get_enabled_obj, - (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&wifi_radio_set_enabled_obj, (mp_obj_t)&mp_const_none_obj }, }; @@ -142,9 +153,25 @@ const mp_obj_property_t wifi_radio_hostname_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| def connect(self, ssid: ReadableBuffer, password: ReadableBuffer = b"", *, channel: Optional[int] = 0, timeout: Optional[float] = None) -> bool: +//| def connect(self, +//| ssid: ReadableBuffer, +//| password: ReadableBuffer = b"", +//| *, +//| channel: Optional[int] = 0, +//| bssid: Optional[ReadableBuffer] = b"", +//| timeout: Optional[float] = None) -> bool: //| """Connects to the given ssid and waits for an ip address. Reconnections are handled -//| automatically once one connection succeeds.""" +//| automatically once one connection succeeds. +//| +//| By default, this will scan all channels and connect to the access point (AP) with the +//| given ``ssid`` and greatest signal strength (rssi). +//| +//| If ``channel`` is given, the scan will begin with the given channel and connect to +//| the first AP with the given ``ssid``. This can speed up the connection time +//| significantly because a full scan doesn't occur. +//| +//| If ``bssid`` is given, the scan will start at the first channel or the one given and +//| connect to the AP with the given ``bssid`` and ``ssid``.""" //| ... //| STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -191,12 +218,12 @@ STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_m } wifi_radio_error_t error = common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, args[ARG_channel].u_int, timeout, bssid.buf, bssid.len); - if (error == WIFI_RADIO_ERROR_AUTH) { + if (error == WIFI_RADIO_ERROR_AUTH_FAIL) { mp_raise_ConnectionError(translate("Authentication failure")); } else if (error == WIFI_RADIO_ERROR_NO_AP_FOUND) { mp_raise_ConnectionError(translate("No network with that ssid")); } else if (error != WIFI_RADIO_ERROR_NONE) { - mp_raise_ConnectionError(translate("Unknown failure")); + mp_raise_msg_varg(&mp_type_ConnectionError, translate("Unknown failure %d"), error); } return mp_const_none; @@ -268,7 +295,7 @@ const mp_obj_property_t wifi_radio_ipv4_dns_obj = { }; //| ap_info: Optional[Network] -//| """Network object containing BSSID, SSID, channel, and RSSI when connected to an access point. None otherwise.""" +//| """Network object containing BSSID, SSID, authmode, channel, country and RSSI when connected to an access point. None otherwise.""" //| STATIC mp_obj_t wifi_radio_get_ap_info(mp_obj_t self) { return common_hal_wifi_radio_get_ap_info(self); diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index 1e8f362e3..64c1052f7 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -36,10 +36,39 @@ const mp_obj_type_t wifi_radio_type; typedef enum { - WIFI_RADIO_ERROR_NONE, - WIFI_RADIO_ERROR_UNKNOWN, - WIFI_RADIO_ERROR_AUTH, - WIFI_RADIO_ERROR_NO_AP_FOUND + // 0 is circuitpython-specific; 1-53 are IEEE; 200+ are Espressif + WIFI_RADIO_ERROR_NONE = 0, + WIFI_RADIO_ERROR_UNSPECIFIED = 1, + WIFI_RADIO_ERROR_AUTH_EXPIRE = 2, + WIFI_RADIO_ERROR_AUTH_LEAVE = 3, + WIFI_RADIO_ERROR_ASSOC_EXPIRE = 4, + WIFI_RADIO_ERROR_ASSOC_TOOMANY = 5, + WIFI_RADIO_ERROR_NOT_AUTHED = 6, + WIFI_RADIO_ERROR_NOT_ASSOCED = 7, + WIFI_RADIO_ERROR_ASSOC_LEAVE = 8, + WIFI_RADIO_ERROR_ASSOC_NOT_AUTHED = 9, + WIFI_RADIO_ERROR_DISASSOC_PWRCAP_BAD = 10, + WIFI_RADIO_ERROR_DISASSOC_SUPCHAN_BAD = 11, + WIFI_RADIO_ERROR_IE_INVALID = 13, + WIFI_RADIO_ERROR_MIC_FAILURE = 14, + WIFI_RADIO_ERROR_4WAY_HANDSHAKE_TIMEOUT = 15, + WIFI_RADIO_ERROR_GROUP_KEY_UPDATE_TIMEOUT = 16, + WIFI_RADIO_ERROR_IE_IN_4WAY_DIFFERS = 17, + WIFI_RADIO_ERROR_GROUP_CIPHER_INVALID = 18, + WIFI_RADIO_ERROR_PAIRWISE_CIPHER_INVALID = 19, + WIFI_RADIO_ERROR_AKMP_INVALID = 20, + WIFI_RADIO_ERROR_UNSUPP_RSN_IE_VERSION = 21, + WIFI_RADIO_ERROR_INVALID_RSN_IE_CAP = 22, + WIFI_RADIO_ERROR_802_1X_AUTH_FAILED = 23, + WIFI_RADIO_ERROR_CIPHER_SUITE_REJECTED = 24, + WIFI_RADIO_ERROR_INVALID_PMKID = 53, + WIFI_RADIO_ERROR_BEACON_TIMEOUT = 200, + WIFI_RADIO_ERROR_NO_AP_FOUND = 201, + WIFI_RADIO_ERROR_AUTH_FAIL = 202, + WIFI_RADIO_ERROR_ASSOC_FAIL = 203, + WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT = 204, + WIFI_RADIO_ERROR_CONNECTION_FAIL = 205, + WIFI_RADIO_ERROR_AP_TSF_RESET = 206, } wifi_radio_error_t; extern bool common_hal_wifi_radio_get_enabled(wifi_radio_obj_t *self); diff --git a/shared-bindings/wifi/__init__.h b/shared-bindings/wifi/__init__.h index c06ee16be..124c0bc49 100644 --- a/shared-bindings/wifi/__init__.h +++ b/shared-bindings/wifi/__init__.h @@ -34,5 +34,6 @@ extern wifi_radio_obj_t common_hal_wifi_radio_obj; void common_hal_wifi_init(void); +void common_hal_wifi_gc_collect(void); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI___INIT___H |
