diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index ccdf973e9f..9318bd466b 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -133,6 +133,9 @@ endif ifeq ($(CIRCUITPY_BOARD),1) SRC_PATTERNS += board/% endif +ifeq ($(CIRCUITPY_BUSDEVICE),1) +SRC_PATTERNS += busdevice/% +endif ifeq ($(CIRCUITPY_BUSIO),1) SRC_PATTERNS += busio/% bitbangio/OneWire.% endif @@ -432,6 +435,8 @@ SRC_SHARED_MODULE_ALL = \ bitbangio/SPI.c \ bitbangio/__init__.c \ board/__init__.c \ + busdevice/__init__.c \ + busdevice/I2CDevice.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 1e01bd9c5e..240fac189b 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -324,6 +324,13 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_UART_ROOT_POINTER #endif +#if CIRCUITPY_BUSDEVICE +extern const struct _mp_obj_module_t busdevice_module; +#define BUSDEVICE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busdevice), (mp_obj_t)&busdevice_module }, +#else +#define BUSDEVICE_MODULE +#endif + #if CIRCUITPY_BUSIO extern const struct _mp_obj_module_t busio_module; #define BUSIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module }, @@ -773,6 +780,7 @@ extern const struct _mp_obj_module_t wifi_module; BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ + BUSDEVICE_MODULE \ BUSIO_MODULE \ CAMERA_MODULE \ CANIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a6aabec33d..1f96a8f2dd 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -90,6 +90,9 @@ CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO) CIRCUITPY_BOARD ?= 1 CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) +CIRCUITPY_BUSDEVICE ?= 1 +CFLAGS += -DCIRCUITPY_BUSDEVICE=$(CIRCUITPY_BUSDEVICE) + CIRCUITPY_BUSIO ?= 1 CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c new file mode 100644 index 0000000000..02dac6a95b --- /dev/null +++ b/shared-bindings/busdevice/I2CDevice.c @@ -0,0 +1,246 @@ +/* + * 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 +// busio.I2C class. + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busdevice/I2CDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/busdevice/I2CDevice.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +//| class I2CDevice: +//| """Two wire serial protocol""" +//| +//| def __init__(self, i2c, device_address, probe=True) -> None: +//| +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + busdevice_i2cdevice_obj_t *self = m_new_obj(busdevice_i2cdevice_obj_t); + self->base.type = &busdevice_i2cdevice_type; + enum { ARG_i2c, ARG_device_address, ARG_probe }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_probe, MP_ARG_BOOL, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + busio_i2c_obj_t* i2c = args[ARG_i2c].u_obj; + + common_hal_busdevice_i2cdevice_construct(self, i2c, args[ARG_device_address].u_int, args[ARG_probe].u_bool); + return (mp_obj_t)self; +} + +//| def __enter__(self) -> None: +//| """Automatically initializes the hardware on context exit. See FIX +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_obj___enter__(mp_obj_t self_in) { + common_hal_busdevice_i2cdevice_lock(self_in); + return self_in; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___enter___obj, busdevice_i2cdevice_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware on context exit. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_busdevice_i2cdevice_unlock(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, 4, busdevice_i2cdevice_obj___exit__); + +STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_readinto(self, ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + readinto(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_readinto_obj, 2, busdevice_i2cdevice_readinto); + + +STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_write(self, ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice_write); + + +/*STATIC void write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, + int32_t out_start, mp_int_t out_end, int32_t in_start, mp_int_t in_end) { + mp_buffer_info_t out_bufinfo; + mp_get_buffer_raise(out_buffer, &out_bufinfo, MP_BUFFER_READ); + + size_t out_length = out_bufinfo.len; + normalize_buffer_bounds(&out_start, out_end, &out_length); + if (out_length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + mp_buffer_info_t in_bufinfo; + mp_get_buffer_raise(in_buffer, &in_bufinfo, MP_BUFFER_WRITE); + + size_t in_length = in_bufinfo.len; + normalize_buffer_bounds(&in_start, in_end, &in_length); + if (in_length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_write_then_readinto(self, out_buffer, in_buffer, out_length, in_length); + if (status != 0) { + mp_raise_OSError(status); + } +}*/ + +STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); + + readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busdevice_i2cdevice_write_then_readinto); + + +STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { + //busdevice_i2cdevice_obj_t *self = self_in; + + //common_hal_busdevice_i2cdevice_lock(self_in); + +/* + uint8_t buffer; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(&buffer, &bufinfo, MP_BUFFER_WRITE); + + uint8_t status = common_hal_busdevice_i2cdevice_readinto(self_in, (uint8_t*)bufinfo.buf, 1); + if (status != 0) { + common_hal_busdevice_i2cdevice_unlock(self_in); + mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); + } +*/ + //common_hal_busdevice_i2cdevice_unlock(self_in); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___probe_for_device_obj, busdevice_i2cdevice___probe_for_device); + + +STATIC const mp_rom_map_elem_t busdevice_i2cdevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_i2cdevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_i2cdevice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busdevice_i2cdevice_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busdevice_i2cdevice_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&busdevice_i2cdevice_write_then_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR___probe_for_device), MP_ROM_PTR(&busdevice_i2cdevice___probe_for_device_obj) }, +}; + + +STATIC MP_DEFINE_CONST_DICT(busdevice_i2cdevice_locals_dict, busdevice_i2cdevice_locals_dict_table); + +const mp_obj_type_t busdevice_i2cdevice_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDevice, + .make_new = busdevice_i2cdevice_make_new, + .locals_dict = (mp_obj_dict_t*)&busdevice_i2cdevice_locals_dict, +}; \ No newline at end of file diff --git a/shared-bindings/busdevice/I2CDevice.h b/shared-bindings/busdevice/I2CDevice.h new file mode 100644 index 0000000000..bc85023d79 --- /dev/null +++ b/shared-bindings/busdevice/I2CDevice.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/busdevice/I2CDevice.h" +#include "shared-bindings/busio/I2C.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busdevice_i2cdevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe); +extern void common_hal_busdevice_i2cdevice___enter__(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice___exit__(busdevice_i2cdevice_obj_t *self); +extern uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, + mp_obj_t in_buffer, size_t out_length, size_t in_length); +extern uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-bindings/busdevice/__init__.c b/shared-bindings/busdevice/__init__.c new file mode 100644 index 0000000000..6b24160a02 --- /dev/null +++ b/shared-bindings/busdevice/__init__.c @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "py/objproperty.h" + +#include "shared-bindings/busdevice/__init__.h" +#include "shared-bindings/busdevice/I2CDevice.h" + + +//| """Hardware accelerated external bus access +//| +//| The `busio` module contains classes to support a variety of serial +//| protocols. +//| +//| When the microcontroller does not support the behavior in a hardware +//| accelerated fashion it may internally use a bitbang routine. However, if +//| hardware support is available on a subset of pins but not those provided, +//| then a RuntimeError will be raised. Use the `bitbangio` module to explicitly +//| bitbang a serial protocol on any general purpose pins. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| For example:: +//| +//| import busio +//| from board import * +//| +//| i2c = busio.I2C(SCL, SDA) +//| print(i2c.scan()) +//| i2c.deinit() +//| +//| This example will initialize the the device, run +//| :py:meth:`~busio.I2C.scan` and then :py:meth:`~busio.I2C.deinit` the +//| hardware. The last step is optional because CircuitPython automatically +//| resets hardware after a program finishes.""" +//| + +STATIC const mp_rom_map_elem_t busdevice_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busdevice) }, + { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&busdevice_i2cdevice_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(busdevice_module_globals, busdevice_module_globals_table); + +const mp_obj_module_t busdevice_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&busdevice_module_globals, +}; diff --git a/shared-bindings/busdevice/__init__.h b/shared-bindings/busdevice/__init__.h new file mode 100644 index 0000000000..4a669807be --- /dev/null +++ b/shared-bindings/busdevice/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c new file mode 100644 index 0000000000..30f4aad339 --- /dev/null +++ b/shared-module/busdevice/I2CDevice.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/busdevice/I2CDevice.h" +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/nlr.h" + +void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe) { + self->i2c = i2c; + self->device_address = device_address; + self->probe = probe; + + if (self->probe == true) { + common_hal_busdevice_i2cdevice___probe_for_device(self); + } +} + +void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { + bool success = false; + while (!success) { + success = common_hal_busio_i2c_try_lock(self->i2c); + } +} + +void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self) { + common_hal_busio_i2c_unlock(self->i2c); +} + +uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + uint8_t status = common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + uint8_t status = common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, + size_t out_length, size_t in_length) { + uint8_t status = 0; + + status = common_hal_busio_i2c_write(self->i2c, self->device_address, out_buffer, out_length, true); + + status = common_hal_busio_i2c_read(self->i2c, self->device_address, in_buffer, in_length); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self) { + + + + + // write "" + + +/* + while not self.i2c.try_lock(): + pass + try: + self.i2c.writeto(self.device_address, b"") + except OSError: + # some OS's dont like writing an empty bytesting... + # Retry by reading a byte + try: + result = bytearray(1) + self.i2c.readfrom_into(self.device_address, result) + except OSError: + raise ValueError("No I2C device at address: %x" % self.device_address) + finally: + self.i2c.unlock() +*/ + return 0; +} diff --git a/shared-module/busdevice/I2CDevice.h b/shared-module/busdevice/I2CDevice.h new file mode 100644 index 0000000000..c872704db6 --- /dev/null +++ b/shared-module/busdevice/I2CDevice.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" +#include "common-hal/busio/I2C.h" + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t *i2c; + uint8_t device_address; + bool probe; +} busdevice_i2cdevice_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/busdevice/__init__.c b/shared-module/busdevice/__init__.c new file mode 100644 index 0000000000..e69de29bb2