From 14f5d03b6dd947bd82d2daf88ca398d7d3b44930 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 18:59:00 -0500 Subject: [PATCH] bringing up to date --- extmod/ulab | 2 +- frozen/Adafruit_CircuitPython_BLE | 2 +- ...ircuitPython_BLE_Apple_Notification_Center | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- .../Adafruit_CircuitPython_CircuitPlayground | 2 +- frozen/Adafruit_CircuitPython_Crickit | 2 +- frozen/Adafruit_CircuitPython_DRV2605 | 2 +- frozen/Adafruit_CircuitPython_DS3231 | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_FocalTouch | 2 +- frozen/Adafruit_CircuitPython_HID | 2 +- frozen/Adafruit_CircuitPython_IRRemote | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_Requests | 2 +- frozen/Adafruit_CircuitPython_Thermistor | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- frozen/circuitpython-stage | 2 +- lib/mp3 | 2 +- lib/protomatter | 2 +- lib/tinyusb | 2 +- ports/atmel-samd/asf4 | 2 +- ports/atmel-samd/peripherals | 2 +- ports/cxd56/spresense-exported-sdk | 2 +- ports/esp32s2/esp-idf | 2 +- ports/stm/st_driver | 2 +- shared-bindings/_typing/__init__ 2.pyi | 54 ++ shared-bindings/gnss/GNSS 2.c | 205 ++++++++ shared-bindings/gnss/GNSS 2.h | 27 + shared-bindings/gnss/PositionFix 2.c | 80 +++ shared-bindings/gnss/PositionFix 2.h | 28 ++ shared-bindings/gnss/SatelliteSystem 2.c | 113 +++++ shared-bindings/gnss/SatelliteSystem 2.h | 33 ++ shared-bindings/gnss/__init__ 2.c | 31 ++ .../i2cperipheral/I2CPeripheral 2.c | 436 ++++++++++++++++ .../i2cperipheral/I2CPeripheral 2.h | 60 +++ shared-bindings/i2cperipheral/__init__ 2.c | 106 ++++ .../memorymonitor/AllocationAlarm 2.c | 137 +++++ .../memorymonitor/AllocationAlarm 2.h | 39 ++ .../memorymonitor/AllocationSize 2.c | 183 +++++++ .../memorymonitor/AllocationSize 2.h | 42 ++ shared-bindings/memorymonitor/__init__ 2.c | 76 +++ shared-bindings/memorymonitor/__init__ 2.h | 49 ++ shared-bindings/sdcardio/SDCard 2.c | 183 +++++++ shared-bindings/sdcardio/SDCard 2.h | 30 ++ shared-bindings/sdcardio/__init__ 2.c | 47 ++ shared-bindings/sdcardio/__init__ 2.h | 0 shared-bindings/sdioio/SDCard 2.c | 296 +++++++++++ shared-bindings/sdioio/SDCard 2.h | 66 +++ shared-bindings/sdioio/__init__ 2.c | 47 ++ shared-bindings/sdioio/__init__ 2.h | 0 .../memorymonitor/AllocationAlarm 2.c | 94 ++++ .../memorymonitor/AllocationAlarm 2.h | 51 ++ .../memorymonitor/AllocationSize 2.c | 91 ++++ .../memorymonitor/AllocationSize 2.h | 51 ++ shared-module/memorymonitor/__init__ 2.c | 39 ++ shared-module/memorymonitor/__init__ 2.h | 35 ++ shared-module/sdcardio/SDCard 2.c | 466 ++++++++++++++++++ shared-module/sdcardio/SDCard 2.h | 51 ++ shared-module/sdcardio/__init__ 2.c | 0 shared-module/sdcardio/__init__ 2.h | 0 supervisor/background_callback 2.h | 87 ++++ supervisor/shared/background_callback 2.c | 138 ++++++ 65 files changed, 3499 insertions(+), 28 deletions(-) create mode 100644 shared-bindings/_typing/__init__ 2.pyi create mode 100644 shared-bindings/gnss/GNSS 2.c create mode 100644 shared-bindings/gnss/GNSS 2.h create mode 100644 shared-bindings/gnss/PositionFix 2.c create mode 100644 shared-bindings/gnss/PositionFix 2.h create mode 100644 shared-bindings/gnss/SatelliteSystem 2.c create mode 100644 shared-bindings/gnss/SatelliteSystem 2.h create mode 100644 shared-bindings/gnss/__init__ 2.c create mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.c create mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.h create mode 100644 shared-bindings/i2cperipheral/__init__ 2.c create mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.c create mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.h create mode 100644 shared-bindings/memorymonitor/AllocationSize 2.c create mode 100644 shared-bindings/memorymonitor/AllocationSize 2.h create mode 100644 shared-bindings/memorymonitor/__init__ 2.c create mode 100644 shared-bindings/memorymonitor/__init__ 2.h create mode 100644 shared-bindings/sdcardio/SDCard 2.c create mode 100644 shared-bindings/sdcardio/SDCard 2.h create mode 100644 shared-bindings/sdcardio/__init__ 2.c create mode 100644 shared-bindings/sdcardio/__init__ 2.h create mode 100644 shared-bindings/sdioio/SDCard 2.c create mode 100644 shared-bindings/sdioio/SDCard 2.h create mode 100644 shared-bindings/sdioio/__init__ 2.c create mode 100644 shared-bindings/sdioio/__init__ 2.h create mode 100644 shared-module/memorymonitor/AllocationAlarm 2.c create mode 100644 shared-module/memorymonitor/AllocationAlarm 2.h create mode 100644 shared-module/memorymonitor/AllocationSize 2.c create mode 100644 shared-module/memorymonitor/AllocationSize 2.h create mode 100644 shared-module/memorymonitor/__init__ 2.c create mode 100644 shared-module/memorymonitor/__init__ 2.h create mode 100644 shared-module/sdcardio/SDCard 2.c create mode 100644 shared-module/sdcardio/SDCard 2.h create mode 100644 shared-module/sdcardio/__init__ 2.c create mode 100644 shared-module/sdcardio/__init__ 2.h create mode 100644 supervisor/background_callback 2.h create mode 100644 supervisor/shared/background_callback 2.c diff --git a/extmod/ulab b/extmod/ulab index 11a7ecff6d..cf61d728e7 160000 --- a/extmod/ulab +++ b/extmod/ulab @@ -1 +1 @@ -Subproject commit 11a7ecff6d76a02644ff23a734b792afaa615e44 +Subproject commit cf61d728e70b9ec57e5711b40540793a89296f5d diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 41f7a3530d..5d584576ef 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 41f7a3530d4cacdbf668399d3a015ea29c7e169b +Subproject commit 5d584576ef79ca36506e6c7470e7ac5204cf0a8d diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index 6a034887e3..3ffb3f02d2 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit 6a034887e370caa61fee5f51db8dd393d3e72542 +Subproject commit 3ffb3f02d2046910e09d1f5a74721bd1a4cdf8cf diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index eb4b21e216..e9411c4244 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit eb4b21e216efd8ec0c4862a938e81b56be961724 +Subproject commit e9411c4244984b69ec6928370ede40cec014c10b diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index 3c540329b6..e9f15d6150 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit 3c540329b63163e45f108df4bfebc387d5352c4f +Subproject commit e9f15d61502f34173912ba271aaaf9446dae8da1 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index 809646ba11..0e1230676a 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit 809646ba11366b5aedbc8a90be1da1829304bf62 +Subproject commit 0e1230676a54da17a309d1dfffdd7fa90240191c diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index 209edd164e..7914a63903 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit 209edd164eb640a8ced561a54505792fc99a67b9 +Subproject commit 7914a6390318687bb8e2e9c4119aa932fea01531 diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index 5d81a9ea82..0d49a1fcd9 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit 5d81a9ea822a85e46be4a512ac44abf21e77d816 +Subproject commit 0d49a1fcd96c13a94e8bdf26f92abe79b8517906 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 01f3f6674b..94b03517c1 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 01f3f6674b4493ba29b857e0f43deb69975736ec +Subproject commit 94b03517c1f4ff68cc2bb09b0963f7e7e3ce3d04 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index 1e3312ab1c..72968d3546 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit 1e3312ab1cba0b1d3bb1f559c52acfdc1a6d57b8 +Subproject commit 72968d3546f9d6c5af138d4c179343007cb9662c diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index 829ba0f0a2..65fb213b8c 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit 829ba0f0a2d8a63f7d0215c6c9fc821e14e52a93 +Subproject commit 65fb213b8c554181d54b77f75335e16e2f4c0987 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index fc3a7b4798..d435fc9a9d 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit fc3a7b479874a1ea315ddb3bf6c5e281e16ef097 +Subproject commit d435fc9a9d90cb063608ae037bf5284b33bc5e84 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index 9fe8f314c0..457aba6dd5 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit 9fe8f314c032cee89b9ad7697d61e9cba76431ff +Subproject commit 457aba6dd59ad00502b80c9031655d3d26ecc82b diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index f1cc47f024..ee8f2187d4 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit f1cc47f024b27e670b9bf2a51c89e32f93c1b957 +Subproject commit ee8f2187d4795b08ae4aa60558f564d26c997be9 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 434e5b5346..5fd72fb963 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 434e5b5346cb0a1a9eb15989b00278be87cb2ff1 +Subproject commit 5fd72fb963c4a0318d29282ca2cc988f19787fda diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 6143ec2a96..56358b4494 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 6143ec2a96a6d218041e9cab5968de26702d7bbf +Subproject commit 56358b4494da825cd99a56a854119f926abca670 diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 43017e30a1..41de8b3c05 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 43017e30a1e772b67ac68293a944e863c031e389 +Subproject commit 41de8b3c05dd78d7be8893a0f6cb47a7e9b421a2 diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index fb773e0ed1..b5bbdbd56c 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit fb773e0ed1891cda2ace6271fafc5312e167d275 +Subproject commit b5bbdbd56ca205c581ba2c84d927ef99befce88e diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 88738da275..76c0dd1329 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 88738da275a83acabb14b7140d1c79b33cdc7b02 +Subproject commit 76c0dd13294ce8ae0518cb9882dcad5d3668977e diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 9596a5904e..0d2c083a2f 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223 +Subproject commit 0d2c083a2fb57a1562d4806775f45273abbfbfae diff --git a/lib/mp3 b/lib/mp3 index bc58a65496..c3c664bf4d 160000 --- a/lib/mp3 +++ b/lib/mp3 @@ -1 +1 @@ -Subproject commit bc58a654964c799e972719a63ff12694998f3549 +Subproject commit c3c664bf4db6a36d11808dfcbb5dbf7cff1715b8 diff --git a/lib/protomatter b/lib/protomatter index 761d6437e8..9f71088d2c 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164 +Subproject commit 9f71088d2c32206c6f0495704ae0c040426d5764 diff --git a/lib/tinyusb b/lib/tinyusb index 22100b252f..dc5445e2f4 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9 +Subproject commit dc5445e2f45cb348a44fe24fc1be4bc8b5ba5bab diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4 index 35a1525796..039b5f3bbc 160000 --- a/ports/atmel-samd/asf4 +++ b/ports/atmel-samd/asf4 @@ -1 +1 @@ -Subproject commit 35a1525796c7ef8a3893d90befdad2f267fca20e +Subproject commit 039b5f3bbc3f4ba4421e581db290560d59fef625 diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 0f5f1522d0..6b531fc923 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 0f5f1522d09c8fa7d858edec484a994c21c59668 +Subproject commit 6b531fc923d9f02b14bd731a5f584ddf716e8773 diff --git a/ports/cxd56/spresense-exported-sdk b/ports/cxd56/spresense-exported-sdk index c991d439fa..7f6568c7f4 160000 --- a/ports/cxd56/spresense-exported-sdk +++ b/ports/cxd56/spresense-exported-sdk @@ -1 +1 @@ -Subproject commit c991d439fac9c23cfcac0da16fe8055f818d40a4 +Subproject commit 7f6568c7f4898cdb24a2f06040784a836050686e diff --git a/ports/esp32s2/esp-idf b/ports/esp32s2/esp-idf index 160ba4924d..0daf6e0e41 160000 --- a/ports/esp32s2/esp-idf +++ b/ports/esp32s2/esp-idf @@ -1 +1 @@ -Subproject commit 160ba4924d8b588e718f76e3a0d0e92c11052fa3 +Subproject commit 0daf6e0e41f95d22d193d08941a00df9525bc405 diff --git a/ports/stm/st_driver b/ports/stm/st_driver index 1900834751..3fc2e0f3db 160000 --- a/ports/stm/st_driver +++ b/ports/stm/st_driver @@ -1 +1 @@ -Subproject commit 1900834751fd6754457874b8c971690bab33e0a7 +Subproject commit 3fc2e0f3db155b33177bb0705e0dd65cadb58412 diff --git a/shared-bindings/_typing/__init__ 2.pyi b/shared-bindings/_typing/__init__ 2.pyi new file mode 100644 index 0000000000..48e68a8d57 --- /dev/null +++ b/shared-bindings/_typing/__init__ 2.pyi @@ -0,0 +1,54 @@ +"""Types for the C-level protocols""" + +from typing import Union + +import array +import audiocore +import audiomixer +import audiomp3 +import rgbmatrix +import ulab + +ReadableBuffer = Union[ + bytes, bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix +] +"""Classes that implement the readable buffer protocol + + - `bytes` + - `bytearray` + - `memoryview` + - `array.array` + - `ulab.array` + - `rgbmatrix.RGBMatrix` +""" + +WriteableBuffer = Union[ + bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix +] +"""Classes that implement the writeable buffer protocol + + - `bytearray` + - `memoryview` + - `array.array` + - `ulab.array` + - `rgbmatrix.RGBMatrix` +""" + +AudioSample = Union[ + audiocore.WaveFile, audiocore.RawSample, audiomixer.Mixer, audiomp3.MP3Decoder +] +"""Classes that implement the audiosample protocol + + - `audiocore.WaveFile` + - `audiocore.RawSample` + - `audiomixer.Mixer` + - `audiomp3.MP3Decoder` + + You can play these back with `audioio.AudioOut`, `audiobusio.I2SOut` or `audiopwmio.PWMAudioOut`. +""" + +FrameBuffer = Union[rgbmatrix.RGBMatrix] +"""Classes that implement the framebuffer protocol + + - `rgbmatrix.RGBMatrix` +""" diff --git a/shared-bindings/gnss/GNSS 2.c b/shared-bindings/gnss/GNSS 2.c new file mode 100644 index 0000000000..087c353953 --- /dev/null +++ b/shared-bindings/gnss/GNSS 2.c @@ -0,0 +1,205 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/GNSS.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class GNSS: +//| """Get updated positioning information from Global Navigation Satellite System (GNSS) +//| +//| Usage:: +//| +//| import gnss +//| import time +//| +//| nav = gnss.GNSS([gnss.SatelliteSystem.GPS, gnss.SatelliteSystem.GLONASS]) +//| last_print = time.monotonic() +//| while True: +//| nav.update() +//| current = time.monotonic() +//| if current - last_print >= 1.0: +//| last_print = current +//| if nav.fix is gnss.PositionFix.INVALID: +//| print("Waiting for fix...") +//| continue +//| print("Latitude: {0:.6f} degrees".format(nav.latitude)) +//| print("Longitude: {0:.6f} degrees".format(nav.longitude))""" +//| + +//| def __init__(self, system: Union[SatelliteSystem, List[SatelliteSystem]]) -> None: +//| """Turn on the GNSS. +//| +//| :param system: satellite system to use""" +//| ... +//| +STATIC mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + gnss_obj_t *self = m_new_obj(gnss_obj_t); + self->base.type = &gnss_type; + enum { ARG_system }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_system, 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); + + unsigned long selection = 0; + if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &gnss_satellitesystem_type)) { + selection |= gnss_satellitesystem_obj_to_type(args[ARG_system].u_obj); + } else if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &mp_type_list)) { + size_t systems_size = 0; + mp_obj_t *systems; + mp_obj_list_get(args[ARG_system].u_obj, &systems_size, &systems); + for (size_t i = 0; i < systems_size; ++i) { + if (!MP_OBJ_IS_TYPE(systems[i], &gnss_satellitesystem_type)) { + mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); + } + selection |= gnss_satellitesystem_obj_to_type(systems[i]); + } + } else { + mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); + } + + common_hal_gnss_construct(self, selection); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Turn off the GNSS.""" +//| ... +//| +STATIC mp_obj_t gnss_obj_deinit(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_gnss_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_deinit_obj, gnss_obj_deinit); + +STATIC void check_for_deinit(gnss_obj_t *self) { + if (common_hal_gnss_deinited(self)) { + raise_deinited_error(); + } +} + +//| def update(self) -> None: +//| """Update GNSS positioning information.""" +//| ... +//| +STATIC mp_obj_t gnss_obj_update(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + common_hal_gnss_update(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_update_obj, gnss_obj_update); + +//| latitude: float +//| """Latitude of current position in degrees (float).""" +//| +STATIC mp_obj_t gnss_obj_get_latitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_latitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_latitude_obj, gnss_obj_get_latitude); + +const mp_obj_property_t gnss_latitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_latitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| longitude: float +//| """Longitude of current position in degrees (float).""" +//| +STATIC mp_obj_t gnss_obj_get_longitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_longitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_longitude_obj, gnss_obj_get_longitude); + +const mp_obj_property_t gnss_longitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_longitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| altitude: float +//| """Altitude of current position in meters (float).""" +//| +STATIC mp_obj_t gnss_obj_get_altitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_altitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_altitude_obj, gnss_obj_get_altitude); + +const mp_obj_property_t gnss_altitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_altitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| timestamp: time.struct_time +//| """Time when the position data was updated.""" +//| +STATIC mp_obj_t gnss_obj_get_timestamp(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + timeutils_struct_time_t tm; + common_hal_gnss_get_timestamp(self, &tm); + return struct_time_from_tm(&tm); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_timestamp_obj, gnss_obj_get_timestamp); + +const mp_obj_property_t gnss_timestamp_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_timestamp_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| fix: PositionFix +//| """Fix mode.""" +//| +STATIC mp_obj_t gnss_obj_get_fix(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return gnss_positionfix_type_to_obj(common_hal_gnss_get_fix(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_fix_obj, gnss_obj_get_fix); + +const mp_obj_property_t gnss_fix_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_fix_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t gnss_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gnss_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&gnss_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_latitude), MP_ROM_PTR(&gnss_latitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_longitude), MP_ROM_PTR(&gnss_longitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_altitude), MP_ROM_PTR(&gnss_altitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&gnss_timestamp_obj) }, + { MP_ROM_QSTR(MP_QSTR_fix), MP_ROM_PTR(&gnss_fix_obj) } +}; +STATIC MP_DEFINE_CONST_DICT(gnss_locals_dict, gnss_locals_dict_table); + +const mp_obj_type_t gnss_type = { + { &mp_type_type }, + .name = MP_QSTR_GNSS, + .make_new = gnss_make_new, + .locals_dict = (mp_obj_dict_t*)&gnss_locals_dict, +}; diff --git a/shared-bindings/gnss/GNSS 2.h b/shared-bindings/gnss/GNSS 2.h new file mode 100644 index 0000000000..60069a90a9 --- /dev/null +++ b/shared-bindings/gnss/GNSS 2.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H + +#include "common-hal/gnss/GNSS.h" +#include "shared-bindings/gnss/SatelliteSystem.h" +#include "shared-bindings/gnss/PositionFix.h" + +#include "lib/timeutils/timeutils.h" + +extern const mp_obj_type_t gnss_type; + +void common_hal_gnss_construct(gnss_obj_t *self, unsigned long selection); +void common_hal_gnss_deinit(gnss_obj_t *self); +bool common_hal_gnss_deinited(gnss_obj_t *self); +void common_hal_gnss_update(gnss_obj_t *self); + +mp_float_t common_hal_gnss_get_latitude(gnss_obj_t *self); +mp_float_t common_hal_gnss_get_longitude(gnss_obj_t *self); +mp_float_t common_hal_gnss_get_altitude(gnss_obj_t *self); +void common_hal_gnss_get_timestamp(gnss_obj_t *self, timeutils_struct_time_t *tm); +gnss_positionfix_t common_hal_gnss_get_fix(gnss_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H diff --git a/shared-bindings/gnss/PositionFix 2.c b/shared-bindings/gnss/PositionFix 2.c new file mode 100644 index 0000000000..e60611d705 --- /dev/null +++ b/shared-bindings/gnss/PositionFix 2.c @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/PositionFix.h" + +//| class PositionFix: +//| """Position fix mode""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the position fix mode.""" +//| +//| INVALID: PositionFix +//| """No measurement.""" +//| +//| FIX_2D: PositionFix +//| """2D fix.""" +//| +//| FIX_3D: PositionFix +//| """3D fix.""" +//| +const mp_obj_type_t gnss_positionfix_type; + +const gnss_positionfix_obj_t gnss_positionfix_invalid_obj = { + { &gnss_positionfix_type }, +}; + +const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj = { + { &gnss_positionfix_type }, +}; + +const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj = { + { &gnss_positionfix_type }, +}; + +gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj) { + gnss_positionfix_t posfix = POSITIONFIX_INVALID; + if (obj == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { + posfix = POSITIONFIX_2D; + } else if (obj == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { + posfix = POSITIONFIX_3D; + } + return posfix; +} + +mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t posfix) { + switch (posfix) { + case POSITIONFIX_2D: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix2d_obj); + case POSITIONFIX_3D: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix3d_obj); + case POSITIONFIX_INVALID: + default: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_invalid_obj); + } +} + +STATIC const mp_rom_map_elem_t gnss_positionfix_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_INVALID), MP_ROM_PTR(&gnss_positionfix_invalid_obj)}, + {MP_ROM_QSTR(MP_QSTR_FIX_2D), MP_ROM_PTR(&gnss_positionfix_fix2d_obj)}, + {MP_ROM_QSTR(MP_QSTR_FIX_3D), MP_ROM_PTR(&gnss_positionfix_fix3d_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gnss_positionfix_locals_dict, gnss_positionfix_locals_dict_table); + +STATIC void gnss_positionfix_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr posfix = MP_QSTR_INVALID; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { + posfix = MP_QSTR_FIX_2D; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { + posfix = MP_QSTR_FIX_3D; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_PositionFix, posfix); +} + +const mp_obj_type_t gnss_positionfix_type = { + { &mp_type_type }, + .name = MP_QSTR_PositionFix, + .print = gnss_positionfix_print, + .locals_dict = (mp_obj_t)&gnss_positionfix_locals_dict, +}; diff --git a/shared-bindings/gnss/PositionFix 2.h b/shared-bindings/gnss/PositionFix 2.h new file mode 100644 index 0000000000..34090872cc --- /dev/null +++ b/shared-bindings/gnss/PositionFix 2.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H + +#include "py/obj.h" + +typedef enum { + POSITIONFIX_INVALID, + POSITIONFIX_2D, + POSITIONFIX_3D, +} gnss_positionfix_t; + +const mp_obj_type_t gnss_positionfix_type; + +gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj); +mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t mode); + +typedef struct { + mp_obj_base_t base; +} gnss_positionfix_obj_t; +extern const gnss_positionfix_obj_t gnss_positionfix_invalid_obj; +extern const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj; +extern const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H diff --git a/shared-bindings/gnss/SatelliteSystem 2.c b/shared-bindings/gnss/SatelliteSystem 2.c new file mode 100644 index 0000000000..7d66727b8d --- /dev/null +++ b/shared-bindings/gnss/SatelliteSystem 2.c @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/SatelliteSystem.h" + +//| class SatelliteSystem: +//| """Satellite system type""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the satellite system type.""" +//| +//| GPS: SatelliteSystem +//| """Global Positioning System.""" +//| +//| GLONASS: SatelliteSystem +//| """GLObal NAvigation Satellite System.""" +//| +//| SBAS: SatelliteSystem +//| """Satellite Based Augmentation System.""" +//| +//| QZSS_L1CA: SatelliteSystem +//| """Quasi-Zenith Satellite System L1C/A.""" +//| +//| QZSS_L1S: SatelliteSystem +//| """Quasi-Zenith Satellite System L1S.""" +//| +const mp_obj_type_t gnss_satellitesystem_type; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj = { + { &gnss_satellitesystem_type }, +}; + +gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj) { + if (obj == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { + return SATELLITESYSTEM_GPS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { + return SATELLITESYSTEM_GLONASS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { + return SATELLITESYSTEM_SBAS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { + return SATELLITESYSTEM_QZSS_L1CA; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { + return SATELLITESYSTEM_QZSS_L1S; + } + return SATELLITESYSTEM_NONE; +} + +mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t system) { + switch (system) { + case SATELLITESYSTEM_GPS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_gps_obj); + case SATELLITESYSTEM_GLONASS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_glonass_obj); + case SATELLITESYSTEM_SBAS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_sbas_obj); + case SATELLITESYSTEM_QZSS_L1CA: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj); + case SATELLITESYSTEM_QZSS_L1S: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj); + case SATELLITESYSTEM_NONE: + default: + return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); + } +} + +STATIC const mp_rom_map_elem_t gnss_satellitesystem_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_GPS), MP_ROM_PTR(&gnss_satellitesystem_gps_obj)}, + {MP_ROM_QSTR(MP_QSTR_GLONASS), MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)}, + {MP_ROM_QSTR(MP_QSTR_SBAS), MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)}, + {MP_ROM_QSTR(MP_QSTR_QZSS_L1CA), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)}, + {MP_ROM_QSTR(MP_QSTR_QZSS_L1S), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gnss_satellitesystem_locals_dict, gnss_satellitesystem_locals_dict_table); + +STATIC void gnss_satellitesystem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr system = MP_QSTR_None; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { + system = MP_QSTR_GPS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { + system = MP_QSTR_GLONASS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { + system = MP_QSTR_SBAS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { + system = MP_QSTR_QZSS_L1CA; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { + system = MP_QSTR_QZSS_L1S; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_SatelliteSystem, system); +} + +const mp_obj_type_t gnss_satellitesystem_type = { + { &mp_type_type }, + .name = MP_QSTR_SatelliteSystem, + .print = gnss_satellitesystem_print, + .locals_dict = (mp_obj_t)&gnss_satellitesystem_locals_dict, +}; diff --git a/shared-bindings/gnss/SatelliteSystem 2.h b/shared-bindings/gnss/SatelliteSystem 2.h new file mode 100644 index 0000000000..17f1550028 --- /dev/null +++ b/shared-bindings/gnss/SatelliteSystem 2.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H + +#include "py/obj.h" + +typedef enum { + SATELLITESYSTEM_NONE = 0, + SATELLITESYSTEM_GPS = (1U << 0), + SATELLITESYSTEM_GLONASS = (1U << 1), + SATELLITESYSTEM_SBAS = (1U << 2), + SATELLITESYSTEM_QZSS_L1CA = (1U << 3), + SATELLITESYSTEM_QZSS_L1S = (1U << 4), +} gnss_satellitesystem_t; + +const mp_obj_type_t gnss_satellitesystem_type; + +gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj); +mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t mode); + +typedef struct { + mp_obj_base_t base; +} gnss_satellitesystem_obj_t; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H diff --git a/shared-bindings/gnss/__init__ 2.c b/shared-bindings/gnss/__init__ 2.c new file mode 100644 index 0000000000..4b0d312ae6 --- /dev/null +++ b/shared-bindings/gnss/__init__ 2.c @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-bindings/gnss/GNSS.h" +#include "shared-bindings/gnss/SatelliteSystem.h" +#include "shared-bindings/gnss/PositionFix.h" +#include "shared-bindings/util.h" + +//| """Global Navigation Satellite System +//| +//| The `gnss` module contains classes to control the GNSS and acquire positioning information.""" +//| +STATIC const mp_rom_map_elem_t gnss_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gnss) }, + { MP_ROM_QSTR(MP_QSTR_GNSS), MP_ROM_PTR(&gnss_type) }, + + // Enum-like Classes. + { MP_ROM_QSTR(MP_QSTR_SatelliteSystem), MP_ROM_PTR(&gnss_satellitesystem_type) }, + { MP_ROM_QSTR(MP_QSTR_PositionFix), MP_ROM_PTR(&gnss_positionfix_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(gnss_module_globals, gnss_module_globals_table); + +const mp_obj_module_t gnss_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&gnss_module_globals, +}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.c b/shared-bindings/i2cperipheral/I2CPeripheral 2.c new file mode 100644 index 0000000000..b5ac861b4e --- /dev/null +++ b/shared-bindings/i2cperipheral/I2CPeripheral 2.c @@ -0,0 +1,436 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * 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/i2cperipheral/I2CPeripheral.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "lib/utils/interrupt_char.h" + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +STATIC mp_obj_t mp_obj_new_i2cperipheral_i2c_peripheral_request(i2cperipheral_i2c_peripheral_obj_t *peripheral, uint8_t address, bool is_read, bool is_restart) { + i2cperipheral_i2c_peripheral_request_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_request_obj_t); + self->base.type = &i2cperipheral_i2c_peripheral_request_type; + self->peripheral = peripheral; + self->address = address; + self->is_read = is_read; + self->is_restart = is_restart; + return (mp_obj_t)self; +} + +//| class I2CPeripheral: +//| """Two wire serial protocol peripheral""" +//| +//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, addresses: Sequence[int], smbus: bool = False) -> None: +//| """I2C is a two-wire protocol for communicating between devices. +//| This implements the peripheral (sensor, secondary) side. +//| +//| :param ~microcontroller.Pin scl: The clock pin +//| :param ~microcontroller.Pin sda: The data pin +//| :param addresses: The I2C addresses to respond to (how many is hw dependent). +//| :type addresses: list[int] +//| :param bool smbus: Use SMBUS timings if the hardware supports it""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + i2cperipheral_i2c_peripheral_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_obj_t); + self->base.type = &i2cperipheral_i2c_peripheral_type; + enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_addresses, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_smbus, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t* scl = validate_obj_is_free_pin(args[ARG_scl].u_obj); + const mcu_pin_obj_t* sda = validate_obj_is_free_pin(args[ARG_sda].u_obj); + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[ARG_addresses].u_obj, &iter_buf); + mp_obj_t item; + uint8_t *addresses = NULL; + unsigned int i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_int_t value; + if (!mp_obj_get_int_maybe(item, &value)) { + mp_raise_TypeError_varg(translate("can't convert %q to %q"), MP_QSTR_address, MP_QSTR_int); + } + if (value < 0x00 || value > 0x7f) { + mp_raise_ValueError(translate("address out of bounds")); + } + addresses = m_renew(uint8_t, addresses, i, i + 1); + addresses[i++] = value; + } + if (i == 0) { + mp_raise_ValueError(translate("addresses is empty")); + } + + common_hal_i2cperipheral_i2c_peripheral_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool); + return (mp_obj_t)self; +} + +//| def deinit(self) -> None: +//| """Releases control of the underlying hardware so other classes can use it.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj_deinit(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cperipheral_i2c_peripheral_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_deinit_obj, i2cperipheral_i2c_peripheral_obj_deinit); + +//| def __enter__(self) -> I2CPeripheral: +//| """No-op used in Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware on context exit. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_i2cperipheral_i2c_peripheral_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_obj___exit__); + +//| def request(self, timeout: float = -1) -> I2CPeripheralRequest: +//| """Wait for an I2C request. +//| +//| :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once +//| :return: I2C Slave Request or None if timeout=-1 and there's no request +//| :rtype: ~i2cperipheral.I2CPeripheralRequest""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if(common_hal_i2cperipheral_i2c_peripheral_deinited(self)) { + raise_deinited_error(); + } + enum { ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + #if MICROPY_PY_BUILTINS_FLOAT + float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000; + int timeout_ms = (int)f; + #else + int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000; + #endif + + bool forever = false; + uint64_t timeout_end = 0; + if (timeout_ms == 0) { + forever = true; + } else if (timeout_ms > 0) { + timeout_end = common_hal_time_monotonic() + timeout_ms; + } + + int last_error = 0; + + do { + uint8_t address; + bool is_read; + bool is_restart; + + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return mp_const_none; + } + + int status = common_hal_i2cperipheral_i2c_peripheral_is_addressed(self, &address, &is_read, &is_restart); + if (status < 0) { + // On error try one more time before bailing out + if (last_error) { + mp_raise_OSError(last_error); + } + last_error = -status; + mp_hal_delay_ms(10); + continue; + } + + last_error = 0; + + if (status == 0) { + mp_hal_delay_us(10); + continue; + } + + return mp_obj_new_i2cperipheral_i2c_peripheral_request(self, address, is_read, is_restart); + } while (forever || common_hal_time_monotonic() < timeout_end); + + if (timeout_ms > 0) { + mp_raise_OSError(MP_ETIMEDOUT); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_obj, 1, i2cperipheral_i2c_peripheral_request); + +STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_request), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_obj) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_locals_dict, i2cperipheral_i2c_peripheral_locals_dict_table); + +const mp_obj_type_t i2cperipheral_i2c_peripheral_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CPeripheral, + .make_new = i2cperipheral_i2c_peripheral_make_new, + .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_locals_dict, +}; + +//| class I2CPeripheralRequest: +//| +//| def __init__(self, peripheral: i2cperipheral.I2CPeripheral, address: int, is_read: bool, is_restart: bool) -> None: +//| """Information about an I2C transfer request +//| This cannot be instantiated directly, but is returned by :py:meth:`I2CPeripheral.request`. +//| +//| :param peripheral: The I2CPeripheral object receiving this request +//| :param address: I2C address +//| :param is_read: True if the main peripheral is requesting data +//| :param is_restart: Repeated Start Condition""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 4, 4, false); + return mp_obj_new_i2cperipheral_i2c_peripheral_request(args[0], mp_obj_get_int(args[1]), mp_obj_is_true(args[2]), mp_obj_is_true(args[3])); +} + +//| def __enter__(self) -> I2CPeripheralRequest: +//| """No-op used in Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Close the request.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_obj___exit__(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_request_obj___exit__); + +//| address: int +//| """The I2C address of the request.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_address(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->address); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_address_obj, i2cperipheral_i2c_peripheral_request_get_address); + +//| is_read: bool +//| """The I2C main controller is reading from this peripheral.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_read(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->is_read); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_read_obj, i2cperipheral_i2c_peripheral_request_get_is_read); + +//| is_restart: bool +//| """Is Repeated Start Condition.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_restart(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->is_restart); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_restart_obj, i2cperipheral_i2c_peripheral_request_get_is_restart); + +//| def read(self, n: int = -1, ack: bool = True) -> bytearray: +//| """Read data. +//| If ack=False, the caller is responsible for calling :py:meth:`I2CPeripheralRequest.ack`. +//| +//| :param n: Number of bytes to read (negative means all) +//| :param ack: Whether or not to send an ACK after the n'th byte +//| :return: Bytes read""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + enum { ARG_n, ARG_ack }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_n, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_ack, 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 - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + int n = args[ARG_n].u_int; + if (n == 0) { + return mp_obj_new_bytearray(0, NULL); + } + bool ack = args[ARG_ack].u_bool; + + int i = 0; + uint8_t *buffer = NULL; + uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000; + while (common_hal_time_monotonic() < timeout_end) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + + uint8_t data; + int num = common_hal_i2cperipheral_i2c_peripheral_read_byte(self->peripheral, &data); + if (num == 0) { + break; + } + + buffer = m_renew(uint8_t, buffer, i, i + 1); + buffer[i++] = data; + if (i == n) { + if (ack) { + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); + } + break; + } + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); + } + + return mp_obj_new_bytearray(i, buffer); +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_read_obj, 1, i2cperipheral_i2c_peripheral_request_read); + +//| def write(self, buffer: ReadableBuffer) -> int: +//| """Write the data contained in buffer. +//| +//| :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer +//| :return: Number of bytes written""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_write(mp_obj_t self_in, mp_obj_t buf_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + for (size_t i = 0; i < bufinfo.len; i++) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + + int num = common_hal_i2cperipheral_i2c_peripheral_write_byte(self->peripheral, ((uint8_t *)(bufinfo.buf))[i]); + if (num == 0) { + return mp_obj_new_int(i); + } + } + + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(i2cperipheral_i2c_peripheral_request_write_obj, i2cperipheral_i2c_peripheral_request_write); + +//| def ack(self, ack: bool = True) -> None: +//| """Acknowledge or Not Acknowledge last byte received. +//| Use together with :py:meth:`I2CPeripheralRequest.read` ack=False. +//| +//| :param ack: Whether to send an ACK or NACK""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); + bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]); + + if (self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, ack); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ack_obj, 1, 2, i2cperipheral_i2c_peripheral_request_ack); + +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_close(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_request_close_obj, i2cperipheral_i2c_peripheral_request_close); + +STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_restart), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_ack), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_ack_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_close_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_request_locals_dict, i2cperipheral_i2c_peripheral_request_locals_dict_table); + +const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CPeripheralRequest, + .make_new = i2cperipheral_i2c_peripheral_request_make_new, + .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_request_locals_dict, +}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.h b/shared-bindings/i2cperipheral/I2CPeripheral 2.h new file mode 100644 index 0000000000..3035cfbfe7 --- /dev/null +++ b/shared-bindings/i2cperipheral/I2CPeripheral 2.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * 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_BUSIO_I2C_SLAVE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/i2cperipheral/I2CPeripheral.h" + +typedef struct { + mp_obj_base_t base; + i2cperipheral_i2c_peripheral_obj_t *peripheral; + uint16_t address; + bool is_read; + bool is_restart; +} i2cperipheral_i2c_peripheral_request_obj_t; + +extern const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type; + +extern const mp_obj_type_t i2cperipheral_i2c_peripheral_type; + +extern void common_hal_i2cperipheral_i2c_peripheral_construct(i2cperipheral_i2c_peripheral_obj_t *self, + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, + uint8_t *addresses, unsigned int num_addresses, bool smbus); +extern void common_hal_i2cperipheral_i2c_peripheral_deinit(i2cperipheral_i2c_peripheral_obj_t *self); +extern bool common_hal_i2cperipheral_i2c_peripheral_deinited(i2cperipheral_i2c_peripheral_obj_t *self); + +extern int common_hal_i2cperipheral_i2c_peripheral_is_addressed(i2cperipheral_i2c_peripheral_obj_t *self, + uint8_t *address, bool *is_read, bool *is_restart); +extern int common_hal_i2cperipheral_i2c_peripheral_read_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t *data); +extern int common_hal_i2cperipheral_i2c_peripheral_write_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t data); +extern void common_hal_i2cperipheral_i2c_peripheral_ack(i2cperipheral_i2c_peripheral_obj_t *self, bool ack); +extern void common_hal_i2cperipheral_i2c_peripheral_close(i2cperipheral_i2c_peripheral_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H diff --git a/shared-bindings/i2cperipheral/__init__ 2.c b/shared-bindings/i2cperipheral/__init__ 2.c new file mode 100644 index 0000000000..e2cb8509d6 --- /dev/null +++ b/shared-bindings/i2cperipheral/__init__ 2.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +//#include "shared-bindings/i2cperipheral/__init__.h" +#include "shared-bindings/i2cperipheral/I2CPeripheral.h" + +#include "py/runtime.h" + +//| """Two wire serial protocol peripheral +//| +//| The `i2cperipheral` module contains classes to support an I2C peripheral. +//| +//| Example emulating a peripheral with 2 addresses (read and write):: +//| +//| import board +//| from i2cperipheral import I2CPeripheral +//| +//| regs = [0] * 16 +//| index = 0 +//| +//| with I2CPeripheral(board.SCL, board.SDA, (0x40, 0x41)) as device: +//| while True: +//| r = device.request() +//| if not r: +//| # Maybe do some housekeeping +//| continue +//| with r: # Closes the transfer if necessary by sending a NACK or feeding dummy bytes +//| if r.address == 0x40: +//| if not r.is_read: # Main write which is Selected read +//| b = r.read(1) +//| if not b or b[0] > 15: +//| break +//| index = b[0] +//| b = r.read(1) +//| if b: +//| regs[index] = b[0] +//| elif r.is_restart: # Combined transfer: This is the Main read message +//| n = r.write(bytes([regs[index]])) +//| #else: +//| # A read transfer is not supported in this example +//| # If the microcontroller tries, it will get 0xff byte(s) by the ctx manager (r.close()) +//| elif r.address == 0x41: +//| if not r.is_read: +//| b = r.read(1) +//| if b and b[0] == 0xde: +//| # do something +//| pass +//| +//| This example sets up an I2C device that can be accessed from Linux like this:: +//| +//| $ i2cget -y 1 0x40 0x01 +//| 0x00 +//| $ i2cset -y 1 0x40 0x01 0xaa +//| $ i2cget -y 1 0x40 0x01 +//| 0xaa +//| +//| .. warning:: +//| I2CPeripheral makes use of clock stretching in order to slow down +//| the host. +//| Make sure the I2C host supports this. +//| +//| Raspberry Pi in particular does not support this with its I2C hw block. +//| This can be worked around by using the ``i2c-gpio`` bit banging driver. +//| Since the RPi firmware uses the hw i2c, it's not possible to emulate a HAT eeprom.""" +//| + +STATIC const mp_rom_map_elem_t i2cperipheral_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cperipheral) }, + { MP_ROM_QSTR(MP_QSTR_I2CPeripheral), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_module_globals, i2cperipheral_module_globals_table); + +const mp_obj_module_t i2cperipheral_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&i2cperipheral_module_globals, +}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.c b/shared-bindings/memorymonitor/AllocationAlarm 2.c new file mode 100644 index 0000000000..7de8c12874 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationAlarm 2.c @@ -0,0 +1,137 @@ +/* + * This file is part of the Micro Python 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 + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| class AllocationAlarm: +//| +//| def __init__(self, *, minimum_block_count: int = 1) -> None: +//| """Throw an exception when an allocation of ``minimum_block_count`` or more blocks +//| occurs while active. +//| +//| Track allocations:: +//| +//| import memorymonitor +//| +//| aa = memorymonitor.AllocationAlarm(minimum_block_count=2) +//| x = 2 +//| # Should not allocate any blocks. +//| with aa: +//| x = 5 +//| +//| # Should throw an exception when allocating storage for the 20 bytes. +//| with aa: +//| x = bytearray(20) +//| +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_minimum_block_count }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_minimum_block_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_int_t minimum_block_count = args[ARG_minimum_block_count].u_int; + if (minimum_block_count < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_minimum_block_count); + } + + memorymonitor_allocationalarm_obj_t *self = m_new_obj(memorymonitor_allocationalarm_obj_t); + self->base.type = &memorymonitor_allocationalarm_type; + + common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count); + + return MP_OBJ_FROM_PTR(self); +} + +//| def ignore(self, count: int) -> AllocationAlarm: +//| """Sets the number of applicable allocations to ignore before raising the exception. +//| Automatically set back to zero at context exit. +//| +//| Use it within a ``with`` block:: +//| +//| # Will not alarm because the bytearray allocation will be ignored. +//| with aa.ignore(2): +//| x = bytearray(20) +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj_ignore(mp_obj_t self_in, mp_obj_t count_obj) { + mp_int_t count = mp_obj_get_int(count_obj); + if (count < 0) { + mp_raise_ValueError_varg(translate("%q must be >= 0"), MP_QSTR_count); + } + common_hal_memorymonitor_allocationalarm_set_ignore(self_in, count); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_2(memorymonitor_allocationalarm_ignore_obj, memorymonitor_allocationalarm_obj_ignore); + +//| def __enter__(self) -> AllocationAlarm: +//| """Enables the alarm.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj___enter__(mp_obj_t self_in) { + common_hal_memorymonitor_allocationalarm_resume(self_in); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationalarm___enter___obj, memorymonitor_allocationalarm_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically disables the allocation alarm when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_memorymonitor_allocationalarm_set_ignore(args[0], 0); + common_hal_memorymonitor_allocationalarm_pause(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationalarm___exit___obj, 4, 4, memorymonitor_allocationalarm_obj___exit__); + +STATIC const mp_rom_map_elem_t memorymonitor_allocationalarm_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_ignore), MP_ROM_PTR(&memorymonitor_allocationalarm_ignore_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationalarm___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationalarm___exit___obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationalarm_locals_dict, memorymonitor_allocationalarm_locals_dict_table); + +const mp_obj_type_t memorymonitor_allocationalarm_type = { + { &mp_type_type }, + .name = MP_QSTR_AllocationAlarm, + .make_new = memorymonitor_allocationalarm_make_new, + .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationalarm_locals_dict, +}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.h b/shared-bindings/memorymonitor/AllocationAlarm 2.h new file mode 100644 index 0000000000..304b9c5a72 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationAlarm 2.h @@ -0,0 +1,39 @@ +/* + * This file is part of the Micro Python 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_MEMORYMONITOR_ALLOCATIONALARM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H + +#include "shared-module/memorymonitor/AllocationAlarm.h" + +extern const mp_obj_type_t memorymonitor_allocationalarm_type; + +void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count); +void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self); +void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self); +void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-bindings/memorymonitor/AllocationSize 2.c b/shared-bindings/memorymonitor/AllocationSize 2.c new file mode 100644 index 0000000000..b35bae3602 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationSize 2.c @@ -0,0 +1,183 @@ +/* + * This file is part of the Micro Python 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 + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/memorymonitor/AllocationSize.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| class AllocationSize: +//| +//| def __init__(self) -> None: +//| """Tracks the number of allocations in power of two buckets. +//| +//| It will have 16 16-bit buckets to track allocation counts. It is total allocations +//| meaning frees are ignored. Reallocated memory is counted twice, at allocation and when +//| reallocated with the larger size. +//| +//| The buckets are measured in terms of blocks which is the finest granularity of the heap. +//| This means bucket 0 will count all allocations less than or equal to the number of bytes +//| per block, typically 16. Bucket 2 will be less than or equal to 4 blocks. See +//| `bytes_per_block` to convert blocks to bytes. +//| +//| Multiple AllocationSizes can be used to track different code boundaries. +//| +//| Track allocations:: +//| +//| import memorymonitor +//| +//| mm = memorymonitor.AllocationSize() +//| with mm: +//| print("hello world" * 3) +//| +//| for bucket, count in enumerate(mm): +//| print("<", 2 ** bucket, count) +//| +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + memorymonitor_allocationsize_obj_t *self = m_new_obj(memorymonitor_allocationsize_obj_t); + self->base.type = &memorymonitor_allocationsize_type; + + common_hal_memorymonitor_allocationsize_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| def __enter__(self) -> AllocationSize: +//| """Clears counts and resumes tracking.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj___enter__(mp_obj_t self_in) { + common_hal_memorymonitor_allocationsize_clear(self_in); + common_hal_memorymonitor_allocationsize_resume(self_in); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize___enter___obj, memorymonitor_allocationsize_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically pauses allocation tracking when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_memorymonitor_allocationsize_pause(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationsize___exit___obj, 4, 4, memorymonitor_allocationsize_obj___exit__); + +//| bytes_per_block: int +//| """Number of bytes per block""" +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj_get_bytes_per_block(mp_obj_t self_in) { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_bytes_per_block(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize_get_bytes_per_block_obj, memorymonitor_allocationsize_obj_get_bytes_per_block); + +const mp_obj_property_t memorymonitor_allocationsize_bytes_per_block_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&memorymonitor_allocationsize_get_bytes_per_block_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| def __len__(self) -> int: +//| """Returns the number of allocation buckets. +//| +//| This allows you to:: +//| +//| mm = memorymonitor.AllocationSize() +//| print(len(mm))""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint16_t len = common_hal_memorymonitor_allocationsize_get_len(self); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); + default: return MP_OBJ_NULL; // op not supported + } +} + +//| def __getitem__(self, index: int) -> Optional[int]: +//| """Returns the allocation count for the given bucket. +//| +//| This allows you to:: +//| +//| mm = memorymonitor.AllocationSize() +//| print(mm[0])""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) { + if (value == mp_const_none) { + // delete item + mp_raise_AttributeError(translate("Cannot delete values")); + } else { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + mp_raise_NotImplementedError(translate("Slices not supported")); + } else { + size_t index = mp_get_index(&memorymonitor_allocationsize_type, common_hal_memorymonitor_allocationsize_get_len(self), index_obj, false); + if (value == MP_OBJ_SENTINEL) { + // load + return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_item(self, index)); + } else { + mp_raise_AttributeError(translate("Read-only")); + } + } + } + return mp_const_none; +} + +STATIC const mp_rom_map_elem_t memorymonitor_allocationsize_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationsize___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationsize___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_bytes_per_block), MP_ROM_PTR(&memorymonitor_allocationsize_bytes_per_block_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationsize_locals_dict, memorymonitor_allocationsize_locals_dict_table); + +const mp_obj_type_t memorymonitor_allocationsize_type = { + { &mp_type_type }, + .name = MP_QSTR_AllocationSize, + .make_new = memorymonitor_allocationsize_make_new, + .subscr = memorymonitor_allocationsize_subscr, + .unary_op = memorymonitor_allocationsize_unary_op, + .getiter = mp_obj_new_generic_iterator, + .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationsize_locals_dict, +}; diff --git a/shared-bindings/memorymonitor/AllocationSize 2.h b/shared-bindings/memorymonitor/AllocationSize 2.h new file mode 100644 index 0000000000..bcd9514bf2 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationSize 2.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Micro Python 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_MEMORYMONITOR_ALLOCATIONSIZE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H + +#include "shared-module/memorymonitor/AllocationSize.h" + +extern const mp_obj_type_t memorymonitor_allocationsize_type; + +extern void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self); +extern size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self); +extern uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self); +extern uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-bindings/memorymonitor/__init__ 2.c b/shared-bindings/memorymonitor/__init__ 2.c new file mode 100644 index 0000000000..c101ba5e0d --- /dev/null +++ b/shared-bindings/memorymonitor/__init__ 2.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/memorymonitor/__init__.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" +#include "shared-bindings/memorymonitor/AllocationSize.h" + +//| """Memory monitoring helpers""" +//| + +//| class AllocationError(Exception): +//| """Catchall exception for allocation related errors.""" +//| ... +MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception) + +NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* fmt, ...) { + va_list argptr; + va_start(argptr,fmt); + mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr); + va_end(argptr); + nlr_raise(exception); +} + +STATIC const mp_rom_map_elem_t memorymonitor_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_memorymonitor) }, + { MP_ROM_QSTR(MP_QSTR_AllocationAlarm), MP_ROM_PTR(&memorymonitor_allocationalarm_type) }, + { MP_ROM_QSTR(MP_QSTR_AllocationSize), MP_ROM_PTR(&memorymonitor_allocationsize_type) }, + + // Errors + { MP_ROM_QSTR(MP_QSTR_AllocationError), MP_ROM_PTR(&mp_type_memorymonitor_AllocationError) }, +}; + +STATIC MP_DEFINE_CONST_DICT(memorymonitor_module_globals, memorymonitor_module_globals_table); + +void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; + bool is_subclass = kind & PRINT_EXC_SUBCLASS; + if (!is_subclass && (k == PRINT_EXC)) { + mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(memorymonitor_module_globals_table[0].value))); + mp_print_str(print, "."); + } + mp_obj_exception_print(print, o_in, kind); +} + +const mp_obj_module_t memorymonitor_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&memorymonitor_module_globals, +}; diff --git a/shared-bindings/memorymonitor/__init__ 2.h b/shared-bindings/memorymonitor/__init__ 2.h new file mode 100644 index 0000000000..60fcdc3f62 --- /dev/null +++ b/shared-bindings/memorymonitor/__init__ 2.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_MEMORYMONITOR___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H + +#include "py/obj.h" + + +void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); + +#define MP_DEFINE_MEMORYMONITOR_EXCEPTION(exc_name, base_name) \ +const mp_obj_type_t mp_type_memorymonitor_ ## exc_name = { \ + { &mp_type_type }, \ + .name = MP_QSTR_ ## exc_name, \ + .print = memorymonitor_exception_print, \ + .make_new = mp_obj_exception_make_new, \ + .attr = mp_obj_exception_attr, \ + .parent = &mp_type_ ## base_name, \ +}; + +extern const mp_obj_type_t mp_type_memorymonitor_AllocationError; + +NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* msg, ...); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H diff --git a/shared-bindings/sdcardio/SDCard 2.c b/shared-bindings/sdcardio/SDCard 2.c new file mode 100644 index 0000000000..975f8b0953 --- /dev/null +++ b/shared-bindings/sdcardio/SDCard 2.c @@ -0,0 +1,183 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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/objproperty.h" +#include "py/runtime.h" +#include "py/objarray.h" + +#include "shared-bindings/sdcardio/SDCard.h" +#include "shared-module/sdcardio/SDCard.h" +#include "common-hal/busio/SPI.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/flash.h" + +//| class SDCard: +//| """SD Card Block Interface +//| +//| Controls an SD card over SPI. This built-in module has higher read +//| performance than the library adafruit_sdcard, but it is only compatible with +//| `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used +//| with ``storage.VfsFat`` to allow file I/O to an SD card.""" +//| +//| def __init__(self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000) -> None: +//| """Construct an SPI SD Card object with the given properties +//| +//| :param busio.SPI spi: The SPI bus +//| :param microcontroller.Pin cs: The chip select connected to the card +//| :param int baudrate: The SPI data rate to use after card setup +//| +//| Note that during detection and configuration, a hard-coded low baudrate is used. +//| Data transfers use the specified baurate (rounded down to one that is supported by +//| the microcontroller) +//| +//| Example usage: +//| +//| .. code-block:: python +//| +//| import os +//| +//| import board +//| import sdcardio +//| import storage +//| +//| sd = sdcardio.SDCard(board.SPI(), board.SD_CS) +//| vfs = storage.VfsFat(sd) +//| storage.mount(vfs, '/sd') +//| os.listdir('/sd')""" + +STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_spi, ARG_cs, ARG_baudrate, ARG_sdio, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_cs, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 8000000} }, + { MP_QSTR_sdio, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_int = 8000000} }, + }; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj); + mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj); + + sdcardio_sdcard_obj_t *self = m_new_obj(sdcardio_sdcard_obj_t); + self->base.type = &sdcardio_SDCard_type; + + common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); + + return self; +} + + +//| def count(self) -> int: +//| """Returns the total number of sectors +//| +//| Due to technical limitations, this is a function and not a property. +//| +//| :return: The number of 512-byte blocks, as a number""" +//| +mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); + +//| def deinit(self) -> None: +//| """Disable permanently. +//| +//| :return: None""" +//| +mp_obj_t sdcardio_sdcard_deinit(mp_obj_t self_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + common_hal_sdcardio_sdcard_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); + + +//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: +//| +//| """Read one or more blocks from the card +//| +//| :param int start_block: The block to start reading from +//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. +//| +//| :return: None""" +//| + +mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks); + +//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: +//| +//| """Write one or more blocks to the card +//| +//| :param int start_block: The block to start writing from +//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. +//| +//| :return: None""" +//| + +mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks); + +STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sdcardio_sdcard_locals_dict, sdcardio_sdcard_locals_dict_table); + +const mp_obj_type_t sdcardio_SDCard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = sdcardio_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&sdcardio_sdcard_locals_dict, +}; diff --git a/shared-bindings/sdcardio/SDCard 2.h b/shared-bindings/sdcardio/SDCard 2.h new file mode 100644 index 0000000000..5986d5b814 --- /dev/null +++ b/shared-bindings/sdcardio/SDCard 2.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2020 Jeff Epler 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 + +extern const mp_obj_type_t sdcardio_SDCard_type; diff --git a/shared-bindings/sdcardio/__init__ 2.c b/shared-bindings/sdcardio/__init__ 2.c new file mode 100644 index 0000000000..746aa5588e --- /dev/null +++ b/shared-bindings/sdcardio/__init__ 2.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sdcardio/SDCard.h" + +//| """Interface to an SD card via the SPI bus""" + +STATIC const mp_rom_map_elem_t sdcardio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcardio) }, + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdcardio_SDCard_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sdcardio_module_globals, sdcardio_module_globals_table); + +const mp_obj_module_t sdcardio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sdcardio_module_globals, +}; diff --git a/shared-bindings/sdcardio/__init__ 2.h b/shared-bindings/sdcardio/__init__ 2.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-bindings/sdioio/SDCard 2.c b/shared-bindings/sdioio/SDCard 2.c new file mode 100644 index 0000000000..aba414cd63 --- /dev/null +++ b/shared-bindings/sdioio/SDCard 2.c @@ -0,0 +1,296 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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 +// sdioio.SDCard class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +//| class SDCard: +//| """SD Card Block Interface with SDIO +//| +//| Controls an SD card over SDIO. SDIO is a parallel protocol designed +//| for SD cards. It uses a clock pin, a command pin, and 1 or 4 +//| data pins. It can be operated at a high frequency such as +//| 25MHz. Usually an SDCard object is used with ``storage.VfsFat`` +//| to allow file I/O to an SD card.""" +//| +//| def __init__(self, clock: microcontroller.Pin, command: microcontroller.Pin, data: Sequence[microcontroller.Pin], frequency: int) -> None: +//| """Construct an SDIO SD Card object with the given properties +//| +//| :param ~microcontroller.Pin clock: the pin to use for the clock. +//| :param ~microcontroller.Pin command: the pin to use for the command. +//| :param data: A sequence of pins to use for data. +//| :param frequency: The frequency of the bus in Hz +//| +//| Example usage: +//| +//| .. code-block:: python +//| +//| import os +//| +//| import board +//| import sdioio +//| import storage +//| +//| sd = sdioio.SDCard( +//| clock=board.SDIO_CLOCK, +//| command=board.SDIO_COMMAND, +//| data=board.SDIO_DATA, +//| frequency=25000000) +//| vfs = storage.VfsFat(sd) +//| storage.mount(vfs, '/sd') +//| os.listdir('/sd')""" +//| ... +//| + +STATIC mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + sdioio_sdcard_obj_t *self = m_new_obj(sdioio_sdcard_obj_t); + self->base.type = &sdioio_SDCard_type; + enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_command, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT }, + }; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t* clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); + const mcu_pin_obj_t* command = validate_obj_is_free_pin(args[ARG_command].u_obj); + mcu_pin_obj_t *data_pins[4]; + uint8_t num_data; + validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); + + common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int); + return MP_OBJ_FROM_PTR(self); +} + +STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + +//| def configure(self, frequency: int = 0, width: int = 0) -> None: +//| """Configures the SDIO bus. +//| +//| :param int frequency: the desired clock rate in Hertz. The actual clock rate may be higher or lower due to the granularity of available clock settings. Check the `frequency` attribute for the actual clock rate. +//| :param int width: the number of data lines to use. Must be 1 or 4 and must also not exceed the number of data lines at construction +//| +//| .. note:: Leaving a value unspecified or 0 means the current setting is kept""" +//| +STATIC mp_obj_t sdioio_sdcard_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_frequency, ARG_width, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t frequency = args[ARG_frequency].u_int; + if (frequency < 0) { + mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_baudrate); + } + + uint8_t width = args[ARG_width].u_int; + if (width != 0 && width != 1 && width != 4) { + mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_width); + } + + if (!common_hal_sdioio_sdcard_configure(self, frequency, width)) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(sdioio_sdcard_configure_obj, 1, sdioio_sdcard_configure); + +//| def count(self) -> int: +//| """Returns the total number of sectors +//| +//| Due to technical limitations, this is a function and not a property. +//| +//| :return: The number of 512-byte blocks, as a number""" +//| +STATIC mp_obj_t sdioio_sdcard_count(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_count(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_count_obj, sdioio_sdcard_count); + +//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: +//| +//| """Read one or more blocks from the card +//| +//| :param int start_block: The block to start reading from +//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. +//| +//| :return: None""" +mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; + int result = common_hal_sdioio_sdcard_readblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks); + +//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: +//| +//| """Write one or more blocks to the card +//| +//| :param int start_block: The block to start writing from +//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. +//| +//| :return: None""" +//| +mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; + int result = common_hal_sdioio_sdcard_writeblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, sdioio_sdcard_writeblocks); + +//| @property +//| def frequency(self) -> int: +//| """The actual SDIO bus frequency. This may not match the frequency +//| requested due to internal limitations.""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj_get_frequency(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_frequency(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_frequency_obj, sdioio_sdcard_obj_get_frequency); + +const mp_obj_property_t sdioio_sdcard_frequency_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&sdioio_sdcard_get_frequency_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| @property +//| def width(self) -> int: +//| """The actual SDIO bus width, in bits""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj_get_width(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_width_obj, sdioio_sdcard_obj_get_width); + +const mp_obj_property_t sdioio_sdcard_width_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&sdioio_sdcard_get_width_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| def deinit(self) -> None: +//| """Disable permanently. +//| +//| :return: None""" +STATIC mp_obj_t sdioio_sdcard_obj_deinit(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_sdioio_sdcard_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_deinit_obj, sdioio_sdcard_obj_deinit); + +//| def __enter__(self) -> SDCard: +//| """No-op used by Context Managers. +//| Provided by context manager helper.""" +//| ... +//| + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_sdioio_sdcard_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sdioio_sdcard_obj___exit___obj, 4, 4, sdioio_sdcard_obj___exit__); + +STATIC const mp_rom_map_elem_t sdioio_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdioio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&sdioio_sdcard_obj___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&sdioio_sdcard_configure_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&sdioio_sdcard_frequency_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sdioio_sdcard_width_obj) }, + + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdioio_sdcard_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdioio_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdioio_sdcard_writeblocks_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sdioio_sdcard_locals_dict, sdioio_sdcard_locals_dict_table); + +const mp_obj_type_t sdioio_SDCard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = sdioio_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&sdioio_sdcard_locals_dict, +}; diff --git a/shared-bindings/sdioio/SDCard 2.h b/shared-bindings/sdioio/SDCard 2.h new file mode 100644 index 0000000000..7f62ee7a65 --- /dev/null +++ b/shared-bindings/sdioio/SDCard 2.h @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_BUSIO_SDIO_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/sdioio/SDCard.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t sdioio_SDCard_type; + +// Construct an underlying SDIO object. +extern void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, + const mcu_pin_obj_t * clock, const mcu_pin_obj_t * command, + uint8_t num_data, mcu_pin_obj_t ** data, uint32_t frequency); + +extern void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self); +extern bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self); + +extern bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t baudrate, uint8_t width); + +extern void common_hal_sdioio_sdcard_unlock(sdioio_sdcard_obj_t *self); + +// Return actual SDIO bus frequency. +uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t* self); + +// Return SDIO bus width. +uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t* self); + +// Return number of device blocks +uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t* self); + +// Read or write blocks +int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); +int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); + +// This is used by the supervisor to claim SDIO devices indefinitely. +extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H diff --git a/shared-bindings/sdioio/__init__ 2.c b/shared-bindings/sdioio/__init__ 2.c new file mode 100644 index 0000000000..b88e5c3a96 --- /dev/null +++ b/shared-bindings/sdioio/__init__ 2.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sdioio/SDCard.h" + +//| """Interface to an SD card via the SDIO bus""" + +STATIC const mp_rom_map_elem_t sdioio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) }, + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sdioio_module_globals, sdioio_module_globals_table); + +const mp_obj_module_t sdioio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sdioio_module_globals, +}; diff --git a/shared-bindings/sdioio/__init__ 2.h b/shared-bindings/sdioio/__init__ 2.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/memorymonitor/AllocationAlarm 2.c b/shared-module/memorymonitor/AllocationAlarm 2.c new file mode 100644 index 0000000000..35f4e4c636 --- /dev/null +++ b/shared-module/memorymonitor/AllocationAlarm 2.c @@ -0,0 +1,94 @@ +/* + * This file is part of the Micro Python 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 "shared-bindings/memorymonitor/__init__.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" + +#include "py/gc.h" +#include "py/mpstate.h" +#include "py/runtime.h" + +void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count) { + self->minimum_block_count = minimum_block_count; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count) { + self->count = count; +} + +void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self) { + // Check to make sure we aren't already paused. We can be if we're exiting from an exception we + // caused. + if (self->previous == NULL) { + return; + } + *self->previous = self->next; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self) { + if (self->previous != NULL) { + mp_raise_RuntimeError(translate("Already running")); + } + self->next = MP_STATE_VM(active_allocationalarms); + self->previous = (memorymonitor_allocationalarm_obj_t**) &MP_STATE_VM(active_allocationalarms); + if (self->next != NULL) { + self->next->previous = &self->next; + } + MP_STATE_VM(active_allocationalarms) = self; +} + +void memorymonitor_allocationalarms_allocation(size_t block_count) { + memorymonitor_allocationalarm_obj_t* alarm = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationalarms)); + size_t alert_count = 0; + while (alarm != NULL) { + // Hold onto next in case we remove the alarm from the list. + memorymonitor_allocationalarm_obj_t* next = alarm->next; + if (block_count >= alarm->minimum_block_count) { + if (alarm->count > 0) { + alarm->count--; + } else { + // Uncomment the breakpoint below if you want to use a C debugger to figure out the C + // call stack for an allocation. + // asm("bkpt"); + // Pause now because we may alert when throwing the exception too. + common_hal_memorymonitor_allocationalarm_pause(alarm); + alert_count++; + } + } + alarm = next; + } + if (alert_count > 0) { + mp_raise_memorymonitor_AllocationError(translate("Attempt to allocate %d blocks"), block_count); + } +} + +void memorymonitor_allocationalarms_reset(void) { + MP_STATE_VM(active_allocationalarms) = NULL; +} diff --git a/shared-module/memorymonitor/AllocationAlarm 2.h b/shared-module/memorymonitor/AllocationAlarm 2.h new file mode 100644 index 0000000000..172c24f6c8 --- /dev/null +++ b/shared-module/memorymonitor/AllocationAlarm 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python 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_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H +#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H + +#include +#include + +#include "py/obj.h" + +typedef struct _memorymonitor_allocationalarm_obj_t memorymonitor_allocationalarm_obj_t; + +#define ALLOCATION_SIZE_BUCKETS 16 + +typedef struct _memorymonitor_allocationalarm_obj_t { + mp_obj_base_t base; + size_t minimum_block_count; + mp_int_t count; + // Store the location that points to us so we can remove ourselves. + memorymonitor_allocationalarm_obj_t** previous; + memorymonitor_allocationalarm_obj_t* next; +} memorymonitor_allocationalarm_obj_t; + +void memorymonitor_allocationalarms_allocation(size_t block_count); +void memorymonitor_allocationalarms_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-module/memorymonitor/AllocationSize 2.c b/shared-module/memorymonitor/AllocationSize 2.c new file mode 100644 index 0000000000..c28e65592c --- /dev/null +++ b/shared-module/memorymonitor/AllocationSize 2.c @@ -0,0 +1,91 @@ +/* + * This file is part of the Micro Python 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 "shared-bindings/memorymonitor/AllocationSize.h" + +#include "py/gc.h" +#include "py/mpstate.h" +#include "py/runtime.h" + +void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self) { + common_hal_memorymonitor_allocationsize_clear(self); + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self) { + *self->previous = self->next; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self) { + if (self->previous != NULL) { + mp_raise_RuntimeError(translate("Already running")); + } + self->next = MP_STATE_VM(active_allocationsizes); + self->previous = (memorymonitor_allocationsize_obj_t**) &MP_STATE_VM(active_allocationsizes); + if (self->next != NULL) { + self->next->previous = &self->next; + } + MP_STATE_VM(active_allocationsizes) = self; +} + +void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self) { + for (size_t i = 0; i < ALLOCATION_SIZE_BUCKETS; i++) { + self->buckets[i] = 0; + } +} + +uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self) { + return ALLOCATION_SIZE_BUCKETS; +} + +size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self) { + return BYTES_PER_BLOCK; +} + +uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index) { + return self->buckets[index]; +} + +void memorymonitor_allocationsizes_track_allocation(size_t block_count) { + memorymonitor_allocationsize_obj_t* as = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationsizes)); + size_t power_of_two = 0; + block_count >>= 1; + while (block_count != 0) { + power_of_two++; + block_count >>= 1; + } + while (as != NULL) { + as->buckets[power_of_two]++; + as = as->next; + } +} + +void memorymonitor_allocationsizes_reset(void) { + MP_STATE_VM(active_allocationsizes) = NULL; +} diff --git a/shared-module/memorymonitor/AllocationSize 2.h b/shared-module/memorymonitor/AllocationSize 2.h new file mode 100644 index 0000000000..3baab2213e --- /dev/null +++ b/shared-module/memorymonitor/AllocationSize 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python 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_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H +#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H + +#include +#include + +#include "py/obj.h" + +typedef struct _memorymonitor_allocationsize_obj_t memorymonitor_allocationsize_obj_t; + +#define ALLOCATION_SIZE_BUCKETS 16 + +typedef struct _memorymonitor_allocationsize_obj_t { + mp_obj_base_t base; + uint16_t buckets[ALLOCATION_SIZE_BUCKETS]; + // Store the location that points to us so we can remove ourselves. + memorymonitor_allocationsize_obj_t** previous; + memorymonitor_allocationsize_obj_t* next; + bool paused; +} memorymonitor_allocationsize_obj_t; + +void memorymonitor_allocationsizes_track_allocation(size_t block_count); +void memorymonitor_allocationsizes_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-module/memorymonitor/__init__ 2.c b/shared-module/memorymonitor/__init__ 2.c new file mode 100644 index 0000000000..6cb424153d --- /dev/null +++ b/shared-module/memorymonitor/__init__ 2.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft + * + * 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-module/memorymonitor/__init__.h" +#include "shared-module/memorymonitor/AllocationAlarm.h" +#include "shared-module/memorymonitor/AllocationSize.h" + +void memorymonitor_track_allocation(size_t block_count) { + memorymonitor_allocationalarms_allocation(block_count); + memorymonitor_allocationsizes_track_allocation(block_count); +} + +void memorymonitor_reset(void) { + memorymonitor_allocationalarms_reset(); + memorymonitor_allocationsizes_reset(); +} diff --git a/shared-module/memorymonitor/__init__ 2.h b/shared-module/memorymonitor/__init__ 2.h new file mode 100644 index 0000000000..f47f6434bf --- /dev/null +++ b/shared-module/memorymonitor/__init__ 2.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft 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_MEMORYMONITOR___INIT___H +#define MICROPY_INCLUDED_MEMORYMONITOR___INIT___H + +#include + +void memorymonitor_track_allocation(size_t block_count); +void memorymonitor_reset(void); + +#endif // MICROPY_INCLUDED_MEMORYMONITOR___INIT___H diff --git a/shared-module/sdcardio/SDCard 2.c b/shared-module/sdcardio/SDCard 2.c new file mode 100644 index 0000000000..9e861279d3 --- /dev/null +++ b/shared-module/sdcardio/SDCard 2.c @@ -0,0 +1,466 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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. + */ + +// This implementation largely follows the structure of adafruit_sdcard.py + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/sdcardio/SDCard.h" + +#include "py/mperrno.h" + +#if 0 +#define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print, ## __VA_ARGS__)) +#else +#define DEBUG_PRINT(...) ((void)0) +#endif + +#define CMD_TIMEOUT (200) + +#define R1_IDLE_STATE (1<<0) +#define R1_ILLEGAL_COMMAND (1<<2) + +#define TOKEN_CMD25 (0xFC) +#define TOKEN_STOP_TRAN (0xFD) +#define TOKEN_DATA (0xFE) + +STATIC bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { + if (!common_hal_busio_spi_try_lock(self->bus)) { + return false; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); + common_hal_digitalio_digitalinout_set_value(&self->cs, false); + return true; +} + +STATIC void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { + if (!lock_and_configure_bus(self)) { + mp_raise_OSError(EAGAIN); + } +} + +STATIC void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { + uint8_t buf[] = {0xff}; + common_hal_digitalio_digitalinout_set_value(&self->cs, true); + for (int i=0; ibus, buf, 1); + } +} + +STATIC void extraclock_and_unlock_bus(sdcardio_sdcard_obj_t *self) { + clock_card(self, 1); + common_hal_busio_spi_unlock(self->bus); +} + +static uint8_t CRC7(const uint8_t* data, uint8_t n) { + uint8_t crc = 0; + for (uint8_t i = 0; i < n; i++) { + uint8_t d = data[i]; + for (uint8_t j = 0; j < 8; j++) { + crc <<= 1; + if ((d & 0x80) ^ (crc & 0x80)) { + crc ^= 0x09; + } + d <<= 1; + } + } + return (crc << 1) | 1; +} + +#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms +STATIC void wait_for_ready(sdcardio_sdcard_obj_t *self) { + uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS; + while (common_hal_time_monotonic_ns() < deadline) { + uint8_t b; + common_hal_busio_spi_read(self->bus, &b, 1, 0xff); + if (b == 0xff) { + break; + } + } +} + +// In Python API, defaults are response=None, data_block=True, wait=True +STATIC int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) { + DEBUG_PRINT("cmd % 3d [%02x] arg=% 11d [%08x] len=%d%s%s\n", cmd, cmd, arg, arg, response_len, data_block ? " data" : "", wait ? " wait" : ""); + uint8_t cmdbuf[6]; + cmdbuf[0] = cmd | 0x40; + cmdbuf[1] = (arg >> 24) & 0xff; + cmdbuf[2] = (arg >> 16) & 0xff; + cmdbuf[3] = (arg >> 8) & 0xff; + cmdbuf[4] = arg & 0xff; + cmdbuf[5] = CRC7(cmdbuf, 5); + + if (wait) { + wait_for_ready(self); + } + + common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); + + // Wait for the response (response[7] == 0) + bool response_received = false; + for (int i=0; ibus, cmdbuf, 1, 0xff); + if ((cmdbuf[0] & 0x80) == 0) { + response_received = true; + break; + } + } + + if (!response_received) { + return -EIO; + } + + if (response_buf) { + + if (data_block) { + cmdbuf[1] = 0xff; + do { + // Wait for the start block byte + common_hal_busio_spi_read(self->bus, cmdbuf+1, 1, 0xff); + } while (cmdbuf[1] != 0xfe); + } + + common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff); + + if (data_block) { + // Read and discard the CRC-CCITT checksum + common_hal_busio_spi_read(self->bus, cmdbuf+1, 2, 0xff); + } + + } + + return cmdbuf[0]; +} + +STATIC int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) { + return cmd(self, cmd_, block * self->cdv, response_buf, response_len, true, true); +} + +STATIC bool cmd_nodata(sdcardio_sdcard_obj_t* self, int cmd, int response) { + uint8_t cmdbuf[2] = {cmd, 0xff}; + + common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); + + // Wait for the response (response[7] == response) + for (int i=0; ibus, cmdbuf, 1, 0xff); + if (cmdbuf[0] == response) { + return 0; + } + } + return -EIO; +} + +STATIC const compressed_string_t *init_card_v1(sdcardio_sdcard_obj_t *self) { + for (int i=0; icdv = 1; + } + return NULL; + } + } + return translate("timeout waiting for v2 card"); +} + +STATIC const compressed_string_t *init_card(sdcardio_sdcard_obj_t *self) { + clock_card(self, 10); + + common_hal_digitalio_digitalinout_set_value(&self->cs, false); + + // CMD0: init card: should return _R1_IDLE_STATE (allow 5 attempts) + { + bool reached_idle_state = false; + for (int i=0; i<5; i++) { + if (cmd(self, 0, 0, NULL, 0, true, true) == R1_IDLE_STATE) { + reached_idle_state = true; + break; + } + } + if (!reached_idle_state) { + return translate("no SD card"); + } + } + + // CMD8: determine card version + { + uint8_t rb7[4]; + int response = cmd(self, 8, 0x1AA, rb7, sizeof(rb7), false, true); + if (response == R1_IDLE_STATE) { + const compressed_string_t *result =init_card_v2(self); + if (result != NULL) { + return result; + } + } else if (response == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) { + const compressed_string_t *result =init_card_v1(self); + if (result != NULL) { + return result; + } + } else { + return translate("couldn't determine SD card version"); + } + } + + // CMD9: get number of sectors + { + uint8_t csd[16]; + int response = cmd(self, 9, 0, csd, sizeof(csd), true, true); + if (response != 0) { + return translate("no response from SD card"); + } + int csd_version = (csd[0] & 0xC0) >> 6; + if (csd_version >= 2) { + return translate("SD card CSD format not supported"); + } + + if (csd_version == 1) { + self->sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024; + } else { + uint32_t block_length = 1 << (csd[5] & 0xF); + uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); + uint32_t mult = 1 << (((csd[9] & 0x3) << 1 | (csd[10] & 0x80) >> 7) + 2); + self->sectors = block_length / 512 * mult * (c_size + 1); + } + } + + // CMD16: set block length to 512 bytes + { + int response = cmd(self, 16, 512, NULL, 0, true, true); + if (response != 0) { + return translate("can't set 512 block size"); + } + } + + return NULL; +} + +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mcu_pin_obj_t *cs, int baudrate) { + self->bus = bus; + common_hal_digitalio_digitalinout_construct(&self->cs, cs); + common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); + + self->cdv = 512; + self->sectors = 0; + self->baudrate = 250000; + + lock_bus_or_throw(self); + const compressed_string_t *result = init_card(self); + extraclock_and_unlock_bus(self); + + if (result != NULL) { + common_hal_digitalio_digitalinout_deinit(&self->cs); + mp_raise_OSError_msg(result); + } + + self->baudrate = baudrate; +} + +void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { + if (!self->bus) { + return; + } + self->bus = 0; + common_hal_digitalio_digitalinout_deinit(&self->cs); +} + +void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { + if (!self->bus) { + raise_deinited_error(); + } +} + +int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { + common_hal_sdcardio_check_for_deinit(self); + return self->sectors; +} + +int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) { + uint8_t aux[2] = {0, 0}; + while (aux[0] != 0xfe) { + common_hal_busio_spi_read(self->bus, aux, 1, 0xff); + } + + common_hal_busio_spi_read(self->bus, buf, size, 0xff); + + // Read checksum and throw it away + common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff); + return 0; +} + +int readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + uint32_t nblocks = buf->len / 512; + if (nblocks == 1) { + // Use CMD17 to read a single block + return block_cmd(self, 17, start_block, buf->buf, buf->len, true, true); + } else { + // Use CMD18 to read multiple blocks + int r = block_cmd(self, 18, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + + uint8_t *ptr = buf->buf; + while (nblocks--) { + r = readinto(self, ptr, 512); + if (r < 0) { + return r; + } + ptr += 512; + } + + // End the multi-block read + r = cmd(self, 12, 0, NULL, 0, true, false); + + // Return first status 0 or last before card ready (0xff) + while (r != 0) { + uint8_t single_byte; + common_hal_busio_spi_read(self->bus, &single_byte, 1, 0xff); + if (single_byte & 0x80) { + return r; + } + r = single_byte; + } + } + return 0; +} + +int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + if (buf->len % 512 != 0) { + mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); + } + + lock_and_configure_bus(self); + int r = readblocks(self, start_block, buf); + extraclock_and_unlock_bus(self); + return r; +} + +int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { + wait_for_ready(self); + + uint8_t cmd[2]; + cmd[0] = token; + + common_hal_busio_spi_write(self->bus, cmd, 1); + common_hal_busio_spi_write(self->bus, buf, size); + + cmd[0] = cmd[1] = 0xff; + common_hal_busio_spi_write(self->bus, cmd, 2); + + // Check the response + // This differs from the traditional adafruit_sdcard handling, + // but adafruit_sdcard also ignored the return value of SDCard._write(!) + // so nobody noticed + // + // + // Response is as follows: + // x x x 0 STAT 1 + // 7 6 5 4 3..1 0 + // with STATUS 010 indicating "data accepted", and other status bit + // combinations indicating failure. + // In practice, I was seeing cmd[0] as 0xe5, indicating success + for (int i=0; ibus, cmd, 1, 0xff); + DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); + if ((cmd[0] & 0b00010001) == 0b00000001) { + if ((cmd[0] & 0x1f) != 0x5) { + return -EIO; + } else { + break; + } + } + } + + // Wait for the write to finish + do { + common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); + } while (cmd[0] == 0); + + // Success + return 0; +} + +int writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + uint32_t nblocks = buf->len / 512; + if (nblocks == 1) { + // Use CMD24 to write a single block + int r = block_cmd(self, 24, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + r = _write(self, TOKEN_DATA, buf->buf, buf->len); + if (r < 0) { + return r; + } + } else { + // Use CMD25 to write multiple block + int r = block_cmd(self, 25, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + + uint8_t *ptr = buf->buf; + while (nblocks--) { + r = _write(self, TOKEN_CMD25, ptr, 512); + if (r < 0) { + return r; + } + ptr += 512; + } + + cmd_nodata(self, TOKEN_STOP_TRAN, 0); + } + return 0; +} + +int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + if (buf->len % 512 != 0) { + mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); + } + lock_and_configure_bus(self); + int r = writeblocks(self, start_block, buf); + extraclock_and_unlock_bus(self); + return r; +} diff --git a/shared-module/sdcardio/SDCard 2.h b/shared-module/sdcardio/SDCard 2.h new file mode 100644 index 0000000000..76c906029f --- /dev/null +++ b/shared-module/sdcardio/SDCard 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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 + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objarray.h" + +#include "common-hal/busio/SPI.h" +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + busio_spi_obj_t *bus; + digitalio_digitalinout_obj_t cs; + int cdv; + int baudrate; + uint32_t sectors; +} sdcardio_sdcard_obj_t; + +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *cs, int baudrate); +void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); +void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); +int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); +int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); diff --git a/shared-module/sdcardio/__init__ 2.c b/shared-module/sdcardio/__init__ 2.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-module/sdcardio/__init__ 2.h b/shared-module/sdcardio/__init__ 2.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/supervisor/background_callback 2.h b/supervisor/background_callback 2.h new file mode 100644 index 0000000000..535dd656be --- /dev/null +++ b/supervisor/background_callback 2.h @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler 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 CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H +#define CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H + +/** Background callbacks are a linked list of tasks to call in the background. + * + * Include a member of type `background_callback_t` inside an object + * which needs to queue up background work, and zero-initialize it. + * + * To schedule the work, use background_callback_add, with fun as the + * function to call and data pointing to the object itself. + * + * Next time run_background_tasks_if_tick is called, the callback will + * be run and removed from the linked list. + * + * Queueing a task that is already queued does nothing. Unconditionally + * re-queueing it from its own background task will cause it to run during the + * very next background-tasks invocation, leading to a CircuitPython freeze, so + * don't do that. + * + * background_callback_add can be called from interrupt context. + */ +typedef void (*background_callback_fun)(void *data); +typedef struct background_callback { + background_callback_fun fun; + void *data; + struct background_callback *next; + struct background_callback *prev; +} background_callback_t; + +/* Add a background callback for which 'fun' and 'data' were previously set */ +void background_callback_add_core(background_callback_t *cb); + +/* Add a background callback to the given function with the given data. When + * the callback involves an object on the GC heap, the 'data' must be a pointer + * to that object itself, not an internal pointer. Otherwise, it can be the + * case that no other references to the object itself survive, and the object + * becomes garbage collected while an outstanding background callback still + * exists. + */ +void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data); + +/* Run all background callbacks. Normally, this is done by the supervisor + * whenever the list is non-empty */ +void background_callback_run_all(void); + +/* During soft reset, remove all pending callbacks and clear the critical section flag */ +void background_callback_reset(void); + +/* Sometimes background callbacks must be blocked. Use these functions to + * bracket the section of code where this is the case. These calls nest, and + * begins must be balanced with ends. + */ +void background_callback_begin_critical_section(void); +void background_callback_end_critical_section(void); + +/* + * Background callbacks may stop objects from being collected + */ +void background_callback_gc_collect(void); + +#endif diff --git a/supervisor/shared/background_callback 2.c b/supervisor/shared/background_callback 2.c new file mode 100644 index 0000000000..8e12dd3625 --- /dev/null +++ b/supervisor/shared/background_callback 2.c @@ -0,0 +1,138 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/gc.h" +#include "py/mpconfig.h" +#include "supervisor/background_callback.h" +#include "supervisor/shared/tick.h" +#include "shared-bindings/microcontroller/__init__.h" + +STATIC volatile background_callback_t *callback_head, *callback_tail; + +#define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts()) +#define CALLBACK_CRITICAL_END (common_hal_mcu_enable_interrupts()) + +void background_callback_add_core(background_callback_t *cb) { + CALLBACK_CRITICAL_BEGIN; + if (cb->prev || callback_head == cb) { + CALLBACK_CRITICAL_END; + return; + } + cb->next = 0; + cb->prev = (background_callback_t*)callback_tail; + if (callback_tail) { + callback_tail->next = cb; + cb->prev = (background_callback_t*)callback_tail; + } + if (!callback_head) { + callback_head = cb; + } + callback_tail = cb; + CALLBACK_CRITICAL_END; +} + +void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) { + cb->fun = fun; + cb->data = data; + background_callback_add_core(cb); +} + +static bool in_background_callback; +void background_callback_run_all() { + if (!callback_head) { + return; + } + CALLBACK_CRITICAL_BEGIN; + if (in_background_callback) { + CALLBACK_CRITICAL_END; + return; + } + in_background_callback = true; + background_callback_t *cb = (background_callback_t*)callback_head; + callback_head = NULL; + callback_tail = NULL; + while (cb) { + background_callback_t *next = cb->next; + cb->next = cb->prev = NULL; + background_callback_fun fun = cb->fun; + void *data = cb->data; + CALLBACK_CRITICAL_END; + // Leave the critical section in order to run the callback function + if (fun) { + fun(data); + } + CALLBACK_CRITICAL_BEGIN; + cb = next; + } + in_background_callback = false; + CALLBACK_CRITICAL_END; +} + +void background_callback_begin_critical_section() { + CALLBACK_CRITICAL_BEGIN; +} + +void background_callback_end_critical_section() { + CALLBACK_CRITICAL_END; +} + +void background_callback_reset() { + CALLBACK_CRITICAL_BEGIN; + background_callback_t *cb = (background_callback_t*)callback_head; + while(cb) { + background_callback_t *next = cb->next; + memset(cb, 0, sizeof(*cb)); + cb = next; + } + callback_head = NULL; + callback_tail = NULL; + in_background_callback = false; + CALLBACK_CRITICAL_END; +} + +void background_callback_gc_collect(void) { + // We don't enter the callback critical section here. We rely on + // gc_collect_ptr _NOT_ entering background callbacks, so it is not + // possible for the list to be cleared. + // + // However, it is possible for the list to be extended. We make the + // minor assumption that no newly added callback is for a + // collectable object. That is, we only plug the hole where an + // object becomes collectable AFTER it is added but before the + // callback is run, not the hole where an object was ALREADY + // collectable but adds a background task for itself. + // + // It's necessary to traverse the whole list here, as the callbacks + // themselves can be in non-gc memory, and some of the cb->data + // objects themselves might be in non-gc memory. + background_callback_t *cb = (background_callback_t*)callback_head; + while(cb) { + gc_collect_ptr(cb->data); + cb = cb->next; + } +}