bringing up to date
This commit is contained in:
parent
a28d0f6c80
commit
14f5d03b6d
|
@ -1 +1 @@
|
|||
Subproject commit 11a7ecff6d76a02644ff23a734b792afaa615e44
|
||||
Subproject commit cf61d728e70b9ec57e5711b40540793a89296f5d
|
|
@ -1 +1 @@
|
|||
Subproject commit 41f7a3530d4cacdbf668399d3a015ea29c7e169b
|
||||
Subproject commit 5d584576ef79ca36506e6c7470e7ac5204cf0a8d
|
|
@ -1 +1 @@
|
|||
Subproject commit 6a034887e370caa61fee5f51db8dd393d3e72542
|
||||
Subproject commit 3ffb3f02d2046910e09d1f5a74721bd1a4cdf8cf
|
|
@ -1 +1 @@
|
|||
Subproject commit eb4b21e216efd8ec0c4862a938e81b56be961724
|
||||
Subproject commit e9411c4244984b69ec6928370ede40cec014c10b
|
|
@ -1 +1 @@
|
|||
Subproject commit 3c540329b63163e45f108df4bfebc387d5352c4f
|
||||
Subproject commit e9f15d61502f34173912ba271aaaf9446dae8da1
|
|
@ -1 +1 @@
|
|||
Subproject commit 809646ba11366b5aedbc8a90be1da1829304bf62
|
||||
Subproject commit 0e1230676a54da17a309d1dfffdd7fa90240191c
|
|
@ -1 +1 @@
|
|||
Subproject commit 209edd164eb640a8ced561a54505792fc99a67b9
|
||||
Subproject commit 7914a6390318687bb8e2e9c4119aa932fea01531
|
|
@ -1 +1 @@
|
|||
Subproject commit 5d81a9ea822a85e46be4a512ac44abf21e77d816
|
||||
Subproject commit 0d49a1fcd96c13a94e8bdf26f92abe79b8517906
|
|
@ -1 +1 @@
|
|||
Subproject commit 01f3f6674b4493ba29b857e0f43deb69975736ec
|
||||
Subproject commit 94b03517c1f4ff68cc2bb09b0963f7e7e3ce3d04
|
|
@ -1 +1 @@
|
|||
Subproject commit 1e3312ab1cba0b1d3bb1f559c52acfdc1a6d57b8
|
||||
Subproject commit 72968d3546f9d6c5af138d4c179343007cb9662c
|
|
@ -1 +1 @@
|
|||
Subproject commit 829ba0f0a2d8a63f7d0215c6c9fc821e14e52a93
|
||||
Subproject commit 65fb213b8c554181d54b77f75335e16e2f4c0987
|
|
@ -1 +1 @@
|
|||
Subproject commit fc3a7b479874a1ea315ddb3bf6c5e281e16ef097
|
||||
Subproject commit d435fc9a9d90cb063608ae037bf5284b33bc5e84
|
|
@ -1 +1 @@
|
|||
Subproject commit 9fe8f314c032cee89b9ad7697d61e9cba76431ff
|
||||
Subproject commit 457aba6dd59ad00502b80c9031655d3d26ecc82b
|
|
@ -1 +1 @@
|
|||
Subproject commit f1cc47f024b27e670b9bf2a51c89e32f93c1b957
|
||||
Subproject commit ee8f2187d4795b08ae4aa60558f564d26c997be9
|
|
@ -1 +1 @@
|
|||
Subproject commit 434e5b5346cb0a1a9eb15989b00278be87cb2ff1
|
||||
Subproject commit 5fd72fb963c4a0318d29282ca2cc988f19787fda
|
|
@ -1 +1 @@
|
|||
Subproject commit 6143ec2a96a6d218041e9cab5968de26702d7bbf
|
||||
Subproject commit 56358b4494da825cd99a56a854119f926abca670
|
|
@ -1 +1 @@
|
|||
Subproject commit 43017e30a1e772b67ac68293a944e863c031e389
|
||||
Subproject commit 41de8b3c05dd78d7be8893a0f6cb47a7e9b421a2
|
|
@ -1 +1 @@
|
|||
Subproject commit fb773e0ed1891cda2ace6271fafc5312e167d275
|
||||
Subproject commit b5bbdbd56ca205c581ba2c84d927ef99befce88e
|
|
@ -1 +1 @@
|
|||
Subproject commit 88738da275a83acabb14b7140d1c79b33cdc7b02
|
||||
Subproject commit 76c0dd13294ce8ae0518cb9882dcad5d3668977e
|
|
@ -1 +1 @@
|
|||
Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223
|
||||
Subproject commit 0d2c083a2fb57a1562d4806775f45273abbfbfae
|
2
lib/mp3
2
lib/mp3
|
@ -1 +1 @@
|
|||
Subproject commit bc58a654964c799e972719a63ff12694998f3549
|
||||
Subproject commit c3c664bf4db6a36d11808dfcbb5dbf7cff1715b8
|
|
@ -1 +1 @@
|
|||
Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164
|
||||
Subproject commit 9f71088d2c32206c6f0495704ae0c040426d5764
|
|
@ -1 +1 @@
|
|||
Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9
|
||||
Subproject commit dc5445e2f45cb348a44fe24fc1be4bc8b5ba5bab
|
|
@ -1 +1 @@
|
|||
Subproject commit 35a1525796c7ef8a3893d90befdad2f267fca20e
|
||||
Subproject commit 039b5f3bbc3f4ba4421e581db290560d59fef625
|
|
@ -1 +1 @@
|
|||
Subproject commit 0f5f1522d09c8fa7d858edec484a994c21c59668
|
||||
Subproject commit 6b531fc923d9f02b14bd731a5f584ddf716e8773
|
|
@ -1 +1 @@
|
|||
Subproject commit c991d439fac9c23cfcac0da16fe8055f818d40a4
|
||||
Subproject commit 7f6568c7f4898cdb24a2f06040784a836050686e
|
|
@ -1 +1 @@
|
|||
Subproject commit 160ba4924d8b588e718f76e3a0d0e92c11052fa3
|
||||
Subproject commit 0daf6e0e41f95d22d193d08941a00df9525bc405
|
|
@ -1 +1 @@
|
|||
Subproject commit 1900834751fd6754457874b8c971690bab33e0a7
|
||||
Subproject commit 3fc2e0f3db155b33177bb0705e0dd65cadb58412
|
|
@ -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`
|
||||
"""
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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
|
|
@ -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,
|
||||
};
|
|
@ -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;
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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 <string.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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,
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
|
@ -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;
|
||||
}
|
|
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
|
@ -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();
|
||||
}
|
|
@ -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 <stddef.h>
|
||||
|
||||
void memorymonitor_track_allocation(size_t block_count);
|
||||
void memorymonitor_reset(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_MEMORYMONITOR___INIT___H
|
|
@ -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; i<bytes; i++) {
|
||||
common_hal_busio_spi_write(self->bus, 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; i<CMD_TIMEOUT; i++) {
|
||||
common_hal_busio_spi_read(self->bus, 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; i<CMD_TIMEOUT; i++) {
|
||||
common_hal_busio_spi_read(self->bus, 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; i<CMD_TIMEOUT; i++) {
|
||||
if (cmd(self, 41, 0, NULL, 0, true, true) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return translate("timeout waiting for v1 card");
|
||||
}
|
||||
|
||||
STATIC const compressed_string_t *init_card_v2(sdcardio_sdcard_obj_t *self) {
|
||||
for (int i=0; i<CMD_TIMEOUT; i++) {
|
||||
uint8_t ocr[4];
|
||||
common_hal_time_delay_ms(50);
|
||||
cmd(self, 58, 0, ocr, sizeof(ocr), false, true);
|
||||
cmd(self, 55, 0, NULL, 0, true, true);
|
||||
if (cmd(self, 41, 0x40000000, NULL, 0, true, true) == 0) {
|
||||
cmd(self, 58, 0, ocr, sizeof(ocr), false, true);
|
||||
if ((ocr[0] & 0x40) != 0) {
|
||||
self->cdv = 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; i<CMD_TIMEOUT; i++) {
|
||||
common_hal_busio_spi_read(self->bus, 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;
|
||||
}
|
|
@ -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);
|
|
@ -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
|
|
@ -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 <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue