diff options
Diffstat (limited to 'shared-bindings/busio')
| -rw-r--r-- | shared-bindings/busio/I2C.c | 286 | ||||
| -rw-r--r-- | shared-bindings/busio/I2C.h | 70 | ||||
| -rw-r--r-- | shared-bindings/busio/OneWire.c | 169 | ||||
| -rw-r--r-- | shared-bindings/busio/OneWire.h | 42 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.c | 304 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.h | 57 | ||||
| -rw-r--r-- | shared-bindings/busio/UART.c | 290 | ||||
| -rw-r--r-- | shared-bindings/busio/UART.h | 60 | ||||
| -rw-r--r-- | shared-bindings/busio/__init__.c | 98 | ||||
| -rw-r--r-- | shared-bindings/busio/__init__.h | 34 |
10 files changed, 1410 insertions, 0 deletions
diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c new file mode 100644 index 000000000..7383cb104 --- /dev/null +++ b/shared-bindings/busio/I2C.c @@ -0,0 +1,286 @@ +/* + * 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/busio/I2C.h" + +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +//| .. currentmodule:: busio +//| +//| :class:`I2C` --- Two wire serial protocol +//| ------------------------------------------ +//| +//| .. class:: I2C(scl, sda, \*, frequency=400000) +//| +//| I2C is a two-wire protocol for communicating between devices. At the +//| physical level it consists of 2 wires: SCL and SDA, the clock and data +//| lines respectively. +//| +//| .. seealso:: Using this class directly requires careful lock management. +//| Instead, use :class:`~adafruit_bus_device.i2c_device.I2CDevice` to +//| manage locks. +//| +//| .. seealso:: Using this class to directly read registers requires manual +//| bit unpacking. Instead, use an existing driver or make one with +//| :ref:`Register <register-module-reference>` data descriptors. +//| +//| :param ~microcontroller.Pin scl: The clock pin +//| :param ~microcontroller.Pin sda: The data pin +//| :param int frequency: The clock frequency in Hertz +//| +STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + busio_i2c_obj_t *self = m_new_obj(busio_i2c_obj_t); + self->base.type = &busio_i2c_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_scl, ARG_sda, ARG_frequency }; + 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_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + }; + 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); + assert_pin(args[ARG_scl].u_obj, false); + assert_pin(args[ARG_sda].u_obj, false); + const mcu_pin_obj_t* scl = MP_OBJ_TO_PTR(args[ARG_scl].u_obj); + assert_pin_free(scl); + const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj); + assert_pin_free(sda); + common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int); + return (mp_obj_t)self; +} + +//| .. method:: I2C.deinit() +//| +//| Releases control of the underlying hardware so other classes can use it. +//| +STATIC mp_obj_t busio_i2c_obj_deinit(mp_obj_t self_in) { + busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busio_i2c_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_deinit_obj, busio_i2c_obj_deinit); + +//| .. method:: I2C.__enter__() +//| +//| No-op used in Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: I2C.__exit__() +//| +//| Automatically deinitializes the hardware on context exit. +//| +STATIC mp_obj_t busio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_busio_i2c_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_i2c___exit___obj, 4, 4, busio_i2c_obj___exit__); + +static void check_lock(busio_i2c_obj_t *self) { + if (!common_hal_busio_i2c_has_lock(self)) { + mp_raise_RuntimeError("Function requires lock."); + } +} + +//| .. method:: I2C.scan() +//| +//| Scan all I2C addresses between 0x08 and 0x77 inclusive and return a +//| list of those that respond. +//| +//| :return: List of device ids on the I2C bus +//| :rtype: list +//| +STATIC mp_obj_t busio_i2c_scan(mp_obj_t self_in) { + busio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_lock(self); + mp_obj_t list = mp_obj_new_list(0, NULL); + // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved + for (int addr = 0x08; addr < 0x78; ++addr) { + bool success = common_hal_busio_i2c_probe(self, addr); + if (success) { + mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); + } + } + return list; +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_scan_obj, busio_i2c_scan); + +//| .. method:: I2C.try_lock() +//| +//| Attempts to grab the I2C lock. Returns True on success. +//| +//| :return: True when lock has been grabbed +//| :rtype: bool +//| +STATIC mp_obj_t busio_i2c_obj_try_lock(mp_obj_t self_in) { + return mp_obj_new_bool(common_hal_busio_i2c_try_lock(MP_OBJ_TO_PTR(self_in))); +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_try_lock_obj, busio_i2c_obj_try_lock); + +//| .. method:: I2C.unlock() +//| +//| Releases the I2C lock. +//| +STATIC mp_obj_t busio_i2c_obj_unlock(mp_obj_t self_in) { + common_hal_busio_i2c_unlock(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_i2c_unlock_obj, busio_i2c_obj_unlock); + +//| .. method:: I2C.readfrom_into(address, buffer, \*, start=0, end=len(buffer)) +//| +//| Read into ``buffer`` from the slave specified by ``address``. +//| The number of bytes read will be the length of ``buffer``. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]``. This will not cause an allocation like +//| ``buf[start:end]`` will so it saves memory. +//| +//| :param int address: 7-bit device address +//| :param bytearray buffer: buffer to write into +//| :param int start: Index to start writing at +//| :param int end: Index to write up to but not include +//| +STATIC mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { 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} }, + }; + busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + int32_t end = args[ARG_end].u_int; + if (end < 0) { + end += bufinfo.len; + } + uint32_t start = args[ARG_start].u_int; + uint32_t len = end - start; + if ((uint32_t) end < start) { + len = 0; + } else if (len > bufinfo.len) { + len = bufinfo.len; + } + uint8_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, len); + if (status != 0) { + mp_raise_OSError(status); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_readfrom_into_obj, 3, busio_i2c_readfrom_into); + +//| .. method:: I2C.writeto(address, buffer, \*, start=0, end=len(buffer), stop=True) +//| +//| Write the bytes from ``buffer`` to the slave specified by ``address``. +//| Transmits a stop bit if ``stop`` is set. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]``. This will not cause an allocation like +//| ``buffer[start:end]`` will so it saves memory. +//| +//| :param int address: 7-bit device address +//| :param bytearray buffer: buffer containing the bytes to write +//| :param int start: Index to start writing from +//| :param int end: Index to read up to but not include +//| :param bool stop: If true, output an I2C stop condition after the +//| buffer is written +//| +STATIC mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_buffer, ARG_start, ARG_end, ARG_stop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { 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} }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + busio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to write the data from + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + + int32_t end = args[ARG_end].u_int; + if (end < 0) { + end += bufinfo.len; + } + uint32_t start = args[ARG_start].u_int; + uint32_t len = end - start; + if ((uint32_t) end < start) { + len = 0; + } else if (len > bufinfo.len) { + len = bufinfo.len; + } + + // do the transfer + uint8_t status = common_hal_busio_i2c_write(self, args[ARG_address].u_int, + ((uint8_t*) bufinfo.buf) + start, len, args[ARG_stop].u_bool); + if (status != 0) { + mp_raise_OSError(status); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busio_i2c_writeto_obj, 1, busio_i2c_writeto); + +STATIC const mp_rom_map_elem_t busio_i2c_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_i2c___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&busio_i2c_scan_obj) }, + + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&busio_i2c_try_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&busio_i2c_unlock_obj) }, + + { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&busio_i2c_readfrom_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&busio_i2c_writeto_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(busio_i2c_locals_dict, busio_i2c_locals_dict_table); + +const mp_obj_type_t busio_i2c_type = { + { &mp_type_type }, + .name = MP_QSTR_I2C, + .make_new = busio_i2c_make_new, + .locals_dict = (mp_obj_dict_t*)&busio_i2c_locals_dict, +}; diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h new file mode 100644 index 000000000..0d260a309 --- /dev/null +++ b/shared-bindings/busio/I2C.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +// 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_BUSIO_I2C_H__ +#define __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H__ + +#include "py/obj.h" + +#include "common-hal/microcontroller/types.h" +#include "common-hal/busio/I2C.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busio_i2c_type; + +// Initializes the hardware peripheral. +extern void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t * scl, + const mcu_pin_obj_t * sda, + uint32_t frequency); + +extern void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self); + +extern bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self); +extern bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self); +extern void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self); + +// Probe the bus to see if a device acknowledges the given address. +extern bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr); + +// Write to the device and return 0 on success or an appropriate error code from mperrno.h +extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, + const uint8_t * data, size_t len, + bool stop); + +// Reads memory of the i2c device picking up where it left off and return 0 on +// success or an appropriate error code from mperrno.h +extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, + uint8_t * data, size_t len); + +#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_H__ diff --git a/shared-bindings/busio/OneWire.c b/shared-bindings/busio/OneWire.c new file mode 100644 index 000000000..52aed2135 --- /dev/null +++ b/shared-bindings/busio/OneWire.c @@ -0,0 +1,169 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/OneWire.h" + +//| .. currentmodule:: busio +//| +//| :class:`OneWire` -- Lowest-level of the Maxim OneWire protocol +//| ================================================================= +//| +//| :class:`~busio.OneWire` implements the timing-sensitive foundation of the Maxim +//| (formerly Dallas Semi) OneWire protocol. +//| +//| Protocol definition is here: https://www.maximintegrated.com/en/app-notes/index.mvp/id/126 +//| +//| .. class:: OneWire(pin) +//| +//| Create a OneWire object associated with the given pin. The object +//| implements the lowest level timing-sensitive bits of the protocol. +//| +//| :param ~microcontroller.Pin pin: Pin connected to the OneWire bus +//| +//| Read a short series of pulses:: +//| +//| import busio +//| import board +//| +//| with busio.OneWire(board.D7) as onewire: +//| onewire.reset() +//| onewire.write_bit(True) +//| onewire.write_bit(False) +//| print(onewire.read_bit()) +//| +STATIC mp_obj_t busio_onewire_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_pin }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + assert_pin(args[ARG_pin].u_obj, false); + const mcu_pin_obj_t* pin = MP_OBJ_TO_PTR(args[ARG_pin].u_obj); + assert_pin_free(pin); + + busio_onewire_obj_t *self = m_new_obj(busio_onewire_obj_t); + self->base.type = &busio_onewire_type; + + common_hal_busio_onewire_construct(self, pin); + return MP_OBJ_FROM_PTR(self); +} + +//| .. method:: deinit() +//| +//| Deinitialize the OneWire bus and release any hardware resources for reuse. +//| +STATIC mp_obj_t busio_onewire_deinit(mp_obj_t self_in) { + busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busio_onewire_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_deinit_obj, busio_onewire_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. +//| +STATIC mp_obj_t busio_onewire_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_busio_onewire_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_onewire___exit___obj, 4, 4, busio_onewire_obj___exit__); + +//| .. method:: reset() +//| +//| Reset the OneWire bus and read presence +//| +//| :returns: False when at least one device is present +//| :rtype: bool +//| +STATIC mp_obj_t busio_onewire_obj_reset(mp_obj_t self_in) { + busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_busio_onewire_reset(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_reset_obj, busio_onewire_obj_reset); + +//| .. method:: read_bit() +//| +//| Read in a bit +//| +//| :returns: bit state read +//| :rtype: bool +//| +STATIC mp_obj_t busio_onewire_obj_read_bit(mp_obj_t self_in) { + busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return mp_obj_new_bool(common_hal_busio_onewire_read_bit(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_onewire_read_bit_obj, busio_onewire_obj_read_bit); + +//| .. method:: write_bit(value) +//| +//| Write out a bit based on value. +//| +STATIC mp_obj_t busio_onewire_obj_write_bit(mp_obj_t self_in, mp_obj_t bool_obj) { + busio_onewire_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_busio_onewire_write_bit(self, mp_obj_is_true(bool_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(busio_onewire_write_bit_obj, busio_onewire_obj_write_bit); + +STATIC const mp_rom_map_elem_t busio_onewire_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_onewire_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_onewire___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&busio_onewire_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_bit), MP_ROM_PTR(&busio_onewire_read_bit_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_bit), MP_ROM_PTR(&busio_onewire_write_bit_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(busio_onewire_locals_dict, busio_onewire_locals_dict_table); + +const mp_obj_type_t busio_onewire_type = { + { &mp_type_type }, + .name = MP_QSTR_OneWire, + .make_new = busio_onewire_make_new, + .locals_dict = (mp_obj_dict_t*)&busio_onewire_locals_dict, +}; diff --git a/shared-bindings/busio/OneWire.h b/shared-bindings/busio/OneWire.h new file mode 100644 index 000000000..df5cecb7c --- /dev/null +++ b/shared-bindings/busio/OneWire.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_ONEWIRE_H__ +#define __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_ONEWIRE_H__ + +#include "common-hal/microcontroller/types.h" +#include "common-hal/busio/OneWire.h" + +extern const mp_obj_type_t busio_onewire_type; + +extern void common_hal_busio_onewire_construct(busio_onewire_obj_t* self, + const mcu_pin_obj_t* pin); +extern void common_hal_busio_onewire_deinit(busio_onewire_obj_t* self); +extern bool common_hal_busio_onewire_reset(busio_onewire_obj_t* self); +extern bool common_hal_busio_onewire_read_bit(busio_onewire_obj_t* self); +extern void common_hal_busio_onewire_write_bit(busio_onewire_obj_t* self, bool bit); + +#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_ONEWIRE_H__ diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c new file mode 100644 index 000000000..d4d9ec345 --- /dev/null +++ b/shared-bindings/busio/SPI.c @@ -0,0 +1,304 @@ +/* + * 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.SPI class. + +#include <string.h> + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/SPI.h" + +#include "lib/utils/context_manager_helpers.h" +#include "py/mperrno.h" +#include "py/nlr.h" +#include "py/runtime.h" + +//| .. currentmodule:: busio +//| +//| :class:`SPI` -- a 3-4 wire serial protocol +//| ----------------------------------------------- +//| +//| SPI is a serial protocol that has exclusive pins for data in and out of the +//| master. It is typically faster than :py:class:`~busio.I2C` because a +//| separate pin is used to control the active slave rather than a transitted +//| address. This class only manages three of the four SPI lines: `!clock`, +//| `!MOSI`, `!MISO`. Its up to the client to manage the appropriate slave +//| select line. (This is common because multiple slaves can share the `!clock`, +//| `!MOSI` and `!MISO` lines and therefore the hardware.) +//| +//| .. class:: SPI(clock, MOSI=None, MISO=None) +//| +//| Construct an SPI object on the given pins. +//| +//| .. seealso:: Using this class directly requires careful lock management. +//| Instead, use :class:`~adafruit_bus_device.spi_device.SPIDevice` to +//| manage locks. +//| +//| .. seealso:: Using this class to directly read registers requires manual +//| bit unpacking. Instead, use an existing driver or make one with +//| :ref:`Register <register-module-reference>` data descriptors. +//| +//| :param ~microcontroller.Pin clock: the pin to use for the clock. +//| :param ~microcontroller.Pin MOSI: the Master Out Slave In pin. +//| :param ~microcontroller.Pin MISO: the Master In Slave Out pin. +//| + +// TODO(tannewt): Support LSB SPI. +STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + busio_spi_obj_t *self = m_new_obj(busio_spi_obj_t); + self->base.type = &busio_spi_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_clock, ARG_MOSI, ARG_MISO }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + assert_pin(args[ARG_clock].u_obj, false); + assert_pin(args[ARG_MOSI].u_obj, true); + assert_pin(args[ARG_MISO].u_obj, true); + const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(args[ARG_clock].u_obj); + assert_pin_free(clock); + const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(args[ARG_MOSI].u_obj); + assert_pin_free(mosi); + const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(args[ARG_MISO].u_obj); + assert_pin_free(miso); + common_hal_busio_spi_construct(self, clock, mosi, miso); + return (mp_obj_t)self; +} + +//| .. method:: SPI.deinit() +//| +//| Turn off the SPI bus. +//| +STATIC mp_obj_t busio_spi_obj_deinit(mp_obj_t self_in) { + busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busio_spi_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit); + +//| .. method:: SPI.__enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: SPI.__exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. +//| +STATIC mp_obj_t busio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_busio_spi_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_spi_obj___exit___obj, 4, 4, busio_spi_obj___exit__); + +static void check_lock(busio_spi_obj_t *self) { + if (!common_hal_busio_spi_has_lock(self)) { + mp_raise_RuntimeError("Function requires lock"); + } +} + +//| .. method:: SPI.configure(\*, baudrate=100000, polarity=0, phase=0, bits=8) +//| +//| Configures the SPI bus. Only valid when locked. +//| +//| :param int baudrate: the clock rate in Hertz +//| :param int polarity: the base state of the clock line (0 or 1) +//| :param int phase: the edge of the clock that data is captured. First (0) +//| or second (1). Rising or falling depends on clock polarity. +//| :param int bits: the number of bits per word +//| +STATIC mp_obj_t busio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + }; + busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t polarity = args[ARG_polarity].u_int; + if (polarity != 0 && polarity != 1) { + mp_raise_ValueError("Invalid polarity"); + } + uint8_t phase = args[ARG_phase].u_int; + if (phase != 0 && phase != 1) { + mp_raise_ValueError("Invalid phase"); + } + uint8_t bits = args[ARG_bits].u_int; + if (bits != 8 && bits != 9) { + mp_raise_ValueError("Invalid number of bits"); + } + + if (!common_hal_busio_spi_configure(self, args[ARG_baudrate].u_int, + polarity, phase, bits)) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_configure_obj, 1, busio_spi_configure); + +//| .. method:: SPI.try_lock() +//| +//| Attempts to grab the SPI lock. Returns True on success. +//| +//| :return: True when lock has been grabbed +//| :rtype: bool +//| +STATIC mp_obj_t busio_spi_obj_try_lock(mp_obj_t self_in) { + return mp_obj_new_bool(common_hal_busio_spi_try_lock(MP_OBJ_TO_PTR(self_in))); +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_try_lock_obj, busio_spi_obj_try_lock); + +//| .. method:: SPI.unlock() +//| +//| Releases the SPI lock. +//| +STATIC mp_obj_t busio_spi_obj_unlock(mp_obj_t self_in) { + common_hal_busio_spi_unlock(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock); + +//| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer)) +//| +//| Write the data contained in ``buf``. Requires the SPI being locked. +//| +//| :param bytearray buffer: buffer containing the bytes to write +//| :param int start: Index to start writing from +//| :param int end: Index to read up to but not include +//| +STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + 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} }, + }; + busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + int32_t end = args[ARG_end].u_int; + if (end < 0) { + end += bufinfo.len; + } + uint32_t start = args[ARG_start].u_int; + uint32_t len = end - start; + if ((uint32_t) end < start) { + len = 0; + } else if (len > bufinfo.len) { + len = bufinfo.len; + } + + bool ok = common_hal_busio_spi_write(self, ((uint8_t*)bufinfo.buf) + start, len); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write); + + +//| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0) +//| +//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked. +//| +//| :param bytearray buffer: buffer to write into +//| :param int start: Index to start writing at +//| :param int end: Index to write up to but not include +//| :param int write_value: Value to write reading. (Usually ignored.) +//| +STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; + 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} }, + { MP_QSTR_write_value,MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + int32_t end = args[ARG_end].u_int; + if (end < 0) { + end += bufinfo.len; + } + uint32_t start = args[ARG_start].u_int; + uint32_t len = end - start; + if ((uint32_t) end < start) { + len = 0; + } else if (len > bufinfo.len) { + len = bufinfo.len; + } + + bool ok = common_hal_busio_spi_read(self, ((uint8_t*)bufinfo.buf) + start, len, args[ARG_write_value].u_int); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto); + +STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_spi_obj___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&busio_spi_configure_obj) }, + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&busio_spi_try_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&busio_spi_unlock_obj) }, + + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table); + +const mp_obj_type_t busio_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .make_new = busio_spi_make_new, + .locals_dict = (mp_obj_dict_t*)&busio_spi_locals_dict, +}; diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h new file mode 100644 index 000000000..e3deb0e72 --- /dev/null +++ b/shared-bindings/busio/SPI.h @@ -0,0 +1,57 @@ +/* + * 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_SPI_H__ +#define __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H__ + +#include "py/obj.h" + +#include "common-hal/microcontroller/types.h" +#include "common-hal/busio/SPI.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busio_spi_type; + +// Construct an underlying SPI object. +extern void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, + const mcu_pin_obj_t * miso); + +extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self); + +extern bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); + +extern bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self); +extern bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self); +extern void common_hal_busio_spi_unlock(busio_spi_obj_t *self); + +// Writes out the given data. +extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len); + +// Reads in len bytes while outputting zeroes. +extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); + +#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H__ diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c new file mode 100644 index 000000000..11ee91355 --- /dev/null +++ b/shared-bindings/busio/UART.c @@ -0,0 +1,290 @@ +/* + * This file is part of the Micro Python 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 <stdint.h> + +#include "shared-bindings/busio/UART.h" + +#include "lib/utils/context_manager_helpers.h" + +#include "py/ioctl.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "shared-bindings/microcontroller/Pin.h" + +//| .. currentmodule:: busio +//| +//| :class:`UART` -- a bidirectional serial protocol +//| ================================================= +//| +//| +//| .. class:: UART(tx, rx, \*, baudrate=9600, bits=8, parity=None, stop=1, timeout=1000, receiver_buffer_size=64) +//| +//| A common bidirectional serial protocol that uses an an agreed upon speed +//| rather than a shared clock line. +//| +//| :param ~microcontroller.Pin tx: the pin to transmit with +//| :param ~microcontroller.Pin rx: the pin to receive on +//| :param int baudrate: the transmit and receive speed +/// :param int bits: the number of bits per byte, 7, 8 or 9. +/// :param Parity parity: the parity used for error checking +/// :param int stop: the number of stop bits, 1 or 2. +/// :param int timeout: the timeout in milliseconds to wait for the first character and between subsequent characters. +/// :param int receiver_buffer_size: the character length of the read buffer (0 to disable). (When a character is 9 bits the buffer will be 2 * receiver_buffer_size bytes.) +//| +typedef struct { + mp_obj_base_t base; +} busio_uart_parity_obj_t; +extern const busio_uart_parity_obj_t busio_uart_parity_even_obj; +extern const busio_uart_parity_obj_t busio_uart_parity_odd_obj; + +STATIC mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + busio_uart_obj_t *self = m_new_obj(busio_uart_obj_t); + self->base.type = &busio_uart_type; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args); + enum { ARG_tx, ARG_rx, ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_receiver_buffer_size}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tx, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rx, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + { MP_QSTR_parity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} }, + { MP_QSTR_receiver_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} }, + }; + 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); + + assert_pin(args[ARG_rx].u_obj, true); + const mcu_pin_obj_t* rx = MP_OBJ_TO_PTR(args[ARG_rx].u_obj); + assert_pin_free(rx); + + assert_pin(args[ARG_tx].u_obj, true); + const mcu_pin_obj_t* tx = MP_OBJ_TO_PTR(args[ARG_tx].u_obj); + assert_pin_free(tx); + + uint8_t bits = args[ARG_bits].u_int; + if (bits < 7 || bits > 9) { + mp_raise_ValueError("bits must be 7, 8 or 9"); + } + + uart_parity_t parity = PARITY_NONE; + if (args[ARG_parity].u_obj == &busio_uart_parity_even_obj) { + parity = PARITY_EVEN; + } else if (args[ARG_parity].u_obj == &busio_uart_parity_odd_obj) { + parity = PARITY_ODD; + } + + uint8_t stop = args[ARG_stop].u_int; + if (stop != 1 && stop != 2) { + mp_raise_ValueError("stop must be 1 or 2"); + } + + common_hal_busio_uart_construct(self, tx, rx, + args[ARG_baudrate].u_int, bits, parity, stop, args[ARG_timeout].u_int, + args[ARG_receiver_buffer_size].u_int); + return (mp_obj_t)self; +} + +//| .. method:: deinit() +//| +//| Deinitialises the UART and releases any hardware resources for reuse. +//| +STATIC mp_obj_t busio_uart_obj_deinit(mp_obj_t self_in) { + busio_uart_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busio_uart_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(busio_uart_deinit_obj, busio_uart_obj_deinit); + +//| .. method:: __enter__() +//| +//| No-op used by Context Managers. +//| +// Provided by context manager helper. + +//| .. method:: __exit__() +//| +//| Automatically deinitializes the hardware when exiting a context. +//| +STATIC mp_obj_t busio_uart_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_busio_uart_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busio_uart___exit___obj, 4, 4, busio_uart_obj___exit__); + +// These are standard stream methods. Code is in py/stream.c. +// +//| .. method:: read(nbytes=None) +//| +//| Read characters. If ``nbytes`` is specified then read at most that many +//| bytes. Otherwise, read everything that has been buffered. +//| +//| :return: Data read +//| :rtype: bytes or None +//| +//| .. method:: readinto(buf, nbytes=None) +//| +//| Read bytes into the ``buf``. If ``nbytes`` is specified then read at most +//| that many bytes. Otherwise, read at most ``len(buf)`` bytes. +//| +//| :return: number of bytes read and stored into ``buf`` +//| :rtype: bytes or None +//| +//| .. method:: readline() +//| +//| Read a line, ending in a newline character. +//| +//| :return: the line read +//| :rtype: int or None +//| +//| .. method:: write(buf) +//| +//| Write the buffer of bytes to the bus. +//| +//| :return: the number of bytes written +//| :rtype: int or None +//| + +// These three methods are used by the shared stream methods. +STATIC mp_uint_t busio_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + busio_uart_obj_t *self = self_in; + byte *buf = buf_in; + + // make sure we want at least 1 char + if (size == 0) { + return 0; + } + + return common_hal_busio_uart_read(self, buf, size, errcode); +} + +STATIC mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + busio_uart_obj_t *self = self_in; + const byte *buf = buf_in; + + return common_hal_busio_uart_write(self, buf, size, errcode); +} + +STATIC mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + busio_uart_obj_t *self = self_in; + mp_uint_t ret; + if (request == MP_IOCTL_POLL) { + mp_uint_t flags = arg; + ret = 0; + if ((flags & MP_IOCTL_POLL_RD) && common_hal_busio_uart_rx_characters_available(self) > 0) { + ret |= MP_IOCTL_POLL_RD; + } + if ((flags & MP_IOCTL_POLL_WR) && common_hal_busio_uart_ready_to_tx(self)) { + ret |= MP_IOCTL_POLL_WR; + } + } else { + *errcode = MP_EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + +//| .. class:: busio.UART.Parity +//| +//| Enum-like class to define the parity used to verify correct data transfer. +//| +//| .. data:: ODD +//| +//| Total number of ones should be odd. +//| +//| .. data:: EVEN +//| +//| Total number of ones should be even. +//| +const mp_obj_type_t busio_uart_parity_type; + +const busio_uart_parity_obj_t busio_uart_parity_odd_obj = { + { &busio_uart_parity_type }, +}; + +const busio_uart_parity_obj_t busio_uart_parity_even_obj = { + { &busio_uart_parity_type }, +}; + +STATIC const mp_rom_map_elem_t busio_uart_parity_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_ODD), MP_ROM_PTR(&busio_uart_parity_odd_obj) }, + { MP_ROM_QSTR(MP_QSTR_EVEN), MP_ROM_PTR(&busio_uart_parity_even_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(busio_uart_parity_locals_dict, busio_uart_parity_locals_dict_table); + +STATIC void busio_uart_parity_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr parity = MP_QSTR_ODD; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&busio_uart_parity_even_obj)) { + parity = MP_QSTR_EVEN; + } + mp_printf(print, "%q.%q.%q.%q", MP_QSTR_busio, MP_QSTR_UART, MP_QSTR_Parity, parity); +} + +const mp_obj_type_t busio_uart_parity_type = { + { &mp_type_type }, + .name = MP_QSTR_Parity, + .print = busio_uart_parity_print, + .locals_dict = (mp_obj_t)&busio_uart_parity_locals_dict, +}; + +STATIC const mp_rom_map_elem_t busio_uart_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_uart_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busio_uart___exit___obj) }, + + // Standard stream methods. + { MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + + // Nested Enum-like Classes. + { MP_ROM_QSTR(MP_QSTR_Parity), MP_ROM_PTR(&busio_uart_parity_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(busio_uart_locals_dict, busio_uart_locals_dict_table); + +STATIC const mp_stream_p_t uart_stream_p = { + .read = busio_uart_read, + .write = busio_uart_write, + .ioctl = busio_uart_ioctl, + .is_text = false, +}; + +const mp_obj_type_t busio_uart_type = { + { &mp_type_type }, + .name = MP_QSTR_UART, + .make_new = busio_uart_make_new, + .getiter = mp_identity, + .iternext = mp_stream_unbuffered_iter, + .protocol = &uart_stream_p, + .locals_dict = (mp_obj_dict_t*)&busio_uart_locals_dict, +}; diff --git a/shared-bindings/busio/UART.h b/shared-bindings/busio/UART.h new file mode 100644 index 000000000..e0a8a0b09 --- /dev/null +++ b/shared-bindings/busio/UART.h @@ -0,0 +1,60 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H__ +#define __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H__ + +#include "common-hal/microcontroller/types.h" +#include "common-hal/busio/UART.h" + +extern const mp_obj_type_t busio_uart_type; + +typedef enum { + PARITY_NONE, + PARITY_EVEN, + PARITY_ODD +} uart_parity_t; + +// Construct an underlying UART object. +extern void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t * tx, const mcu_pin_obj_t * rx, uint32_t baudrate, + uint8_t bits, uart_parity_t parity, uint8_t stop, uint32_t timeout, + uint8_t receiver_buffer_size); + +extern void common_hal_busio_uart_deinit(busio_uart_obj_t *self); + +// Read characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_read(busio_uart_obj_t *self, + uint8_t *data, size_t len, int *errcode); + +// Write characters. len is in characters NOT bytes! +extern size_t common_hal_busio_uart_write(busio_uart_obj_t *self, + const uint8_t *data, size_t len, int *errcode); + +extern uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self); +extern bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self); + +#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_UART_H__ diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c new file mode 100644 index 000000000..9e075752d --- /dev/null +++ b/shared-bindings/busio/__init__.c @@ -0,0 +1,98 @@ +/* + * 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 <stdint.h> + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/OneWire.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/busio/UART.h" +#include "shared-bindings/busio/__init__.h" + +#include "py/runtime.h" + +//| :mod:`busio` --- Hardware accelerated behavior +//| ================================================= +//| +//| .. module:: busio +//| :synopsis: Hardware accelerated behavior +//| :platform: SAMD21 +//| +//| 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. +//| +//| Libraries +//| +//| .. toctree:: +//| :maxdepth: 3 +//| +//| I2C +//| OneWire +//| SPI +//| UART +//| +//| All libraries change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager. +//| +//| For example:: +//| +//| import busio +//| from board import * +//| +//| with busio.I2C(SCL, SDA) as i2c: +//| i2c.scan() +//| +//| This example will initialize the the device, run +//| :py:meth:`~busio.I2C.scan` and then :py:meth:`~busio.I2C.deinit` the +//| hardware. +//| + +STATIC const mp_rom_map_elem_t busio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busio) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) }, + { MP_ROM_QSTR(MP_QSTR_OneWire), MP_ROM_PTR(&busio_onewire_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table); + +const mp_obj_module_t busio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&busio_module_globals, +}; diff --git a/shared-bindings/busio/__init__.h b/shared-bindings/busio/__init__.h new file mode 100644 index 000000000..214c2b144 --- /dev/null +++ b/shared-bindings/busio/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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___INIT___H__ +#define __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO___INIT___H__ + +#include "py/obj.h" + +// Nothing now. + +#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO___INIT___H__ |
