|
| 1 | +// This file is part of the CircuitPython project: https://circuitpython.org |
| 2 | +// |
| 3 | +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft |
| 4 | +// |
| 5 | +// SPDX-License-Identifier: MIT |
| 6 | + |
| 7 | +// TODO: wiznet.PIO_SPI class. |
| 8 | +// This file contains all of the Python API definitions for the |
| 9 | +// wiznet.PIO_SPI class. |
| 10 | + |
| 11 | +#include <string.h> |
| 12 | + |
| 13 | +#include "shared-bindings/microcontroller/Pin.h" |
| 14 | +#include "bindings/wiznet/PIO_SPI.h" |
| 15 | +#include "shared-bindings/util.h" |
| 16 | + |
| 17 | +#include "shared/runtime/buffer_helper.h" |
| 18 | +#include "shared/runtime/context_manager_helpers.h" |
| 19 | +#include "py/binary.h" |
| 20 | +#include "py/mperrno.h" |
| 21 | +#include "py/objproperty.h" |
| 22 | +#include "py/runtime.h" |
| 23 | + |
| 24 | + |
| 25 | +// TODO: class WIZNET_PIO_SPI |
| 26 | + |
| 27 | + |
| 28 | +static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { |
| 29 | + #if CIRCUITPY_WIZNET |
| 30 | + wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &wiznet_pio_spi_type); |
| 31 | + #if CIRCUITPY_WIZNET_W6300 |
| 32 | + enum { ARG_clock, ARG_quad_io0, ARG_quad_io1, ARG_quad_io2, ARG_quad_io3, ARG_half_duplex, ARG_quad_spi }; |
| 33 | + static const mp_arg_t allowed_args[] = { |
| 34 | + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 35 | + { MP_QSTR_quad_io0, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 36 | + { MP_QSTR_quad_io1, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 37 | + { MP_QSTR_quad_io2, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 38 | + { MP_QSTR_quad_io3, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 39 | + { MP_QSTR_half_duplex, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, |
| 40 | + }; |
| 41 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 42 | + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 43 | + |
| 44 | + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); |
| 45 | + const mcu_pin_obj_t *quad_io0 = validate_obj_is_free_pin_or_none(args[ARG_quad_io0].u_obj, MP_QSTR_quad_io0); |
| 46 | + const mcu_pin_obj_t *quad_io1 = validate_obj_is_free_pin_or_none(args[ARG_quad_io1].u_obj, MP_QSTR_quad_io1); |
| 47 | + const mcu_pin_obj_t *quad_io2 = validate_obj_is_free_pin_or_none(args[ARG_quad_io2].u_obj, MP_QSTR_quad_io2); |
| 48 | + const mcu_pin_obj_t *quad_io3 = validate_obj_is_free_pin_or_none(args[ARG_quad_io3].u_obj, MP_QSTR_quad_io3); |
| 49 | + |
| 50 | + if (!quad_io0 || !quad_io1 || !quad_io2 || !quad_io3) { |
| 51 | + mp_raise_ValueError(MP_ERROR_TEXT("Must provide all quad_io pins for QSPI")); |
| 52 | + } |
| 53 | + |
| 54 | + common_hal_wiznet_pio_qspi_construct(self, clock, quad_io0, quad_io1, quad_io2, quad_io3, args[ARG_half_duplex].u_bool); |
| 55 | + |
| 56 | + #else // W55RP20 |
| 57 | + enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; |
| 58 | + static const mp_arg_t allowed_args[] = { |
| 59 | + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, |
| 60 | + { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 61 | + { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
| 62 | + { MP_QSTR_half_duplex, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, |
| 63 | + }; |
| 64 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 65 | + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 66 | + |
| 67 | + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); |
| 68 | + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi); |
| 69 | + const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso); |
| 70 | + |
| 71 | + if (!miso && !mosi) { |
| 72 | + mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin")); |
| 73 | + } |
| 74 | + |
| 75 | + common_hal_wiznet_pio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool); |
| 76 | + #endif |
| 77 | + return MP_OBJ_FROM_PTR(self); |
| 78 | + #else |
| 79 | + mp_raise_NotImplementedError(NULL); |
| 80 | + #endif // CIRCUITPY_WIZNET |
| 81 | +} |
| 82 | + |
| 83 | +#if CIRCUITPY_WIZNET |
| 84 | + |
| 85 | +// TODO: def deinit |
| 86 | + |
| 87 | +static mp_obj_t wiznet_pio_spi_obj_deinit(mp_obj_t self_in) { |
| 88 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 89 | + common_hal_wiznet_pio_spi_deinit(self); |
| 90 | + return mp_const_none; |
| 91 | +} |
| 92 | +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_deinit_obj, wiznet_pio_spi_obj_deinit); |
| 93 | + |
| 94 | +// TODO: def __enter__ |
| 95 | + |
| 96 | +// TODO: def __exit__ |
| 97 | + |
| 98 | +static void check_lock(wiznet_pio_spi_obj_t *self) { |
| 99 | + asm (""); |
| 100 | + if (!common_hal_wiznet_pio_spi_has_lock(self)) { |
| 101 | + mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +static void check_for_deinit(wiznet_pio_spi_obj_t *self) { |
| 106 | + if (common_hal_wiznet_pio_spi_deinited(self)) { |
| 107 | + raise_deinited_error(); |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +// TODO: def configure |
| 112 | + |
| 113 | +static mp_obj_t wiznet_pio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
| 114 | + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits }; |
| 115 | + static const mp_arg_t allowed_args[] = { |
| 116 | + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, |
| 117 | + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
| 118 | + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
| 119 | + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, |
| 120 | + }; |
| 121 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); |
| 122 | + check_for_deinit(self); |
| 123 | + check_lock(self); |
| 124 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 125 | + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 126 | + |
| 127 | + uint8_t polarity = (uint8_t)mp_arg_validate_int_range(args[ARG_polarity].u_int, 0, 1, MP_QSTR_polarity); |
| 128 | + uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); |
| 129 | + uint8_t bits = (uint8_t)mp_arg_validate_int_range(args[ARG_bits].u_int, 8, 9, MP_QSTR_bits); |
| 130 | + |
| 131 | + if (!common_hal_wiznet_pio_spi_configure(self, args[ARG_baudrate].u_int, |
| 132 | + polarity, phase, bits)) { |
| 133 | + mp_raise_OSError(MP_EIO); |
| 134 | + } |
| 135 | + return mp_const_none; |
| 136 | +} |
| 137 | +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_configure_obj, 1, wiznet_pio_spi_configure); |
| 138 | + |
| 139 | +// TODO: def try_lock |
| 140 | + |
| 141 | +static mp_obj_t wiznet_pio_spi_obj_try_lock(mp_obj_t self_in) { |
| 142 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 143 | + return mp_obj_new_bool(common_hal_wiznet_pio_spi_try_lock(self)); |
| 144 | +} |
| 145 | +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_try_lock_obj, wiznet_pio_spi_obj_try_lock); |
| 146 | + |
| 147 | +// TODO: def unlock |
| 148 | + |
| 149 | +static mp_obj_t wiznet_pio_spi_obj_unlock(mp_obj_t self_in) { |
| 150 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 151 | + check_for_deinit(self); |
| 152 | + common_hal_wiznet_pio_spi_unlock(self); |
| 153 | + return mp_const_none; |
| 154 | +} |
| 155 | +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_unlock_obj, wiznet_pio_spi_obj_unlock); |
| 156 | + |
| 157 | +// TODO: def write |
| 158 | + |
| 159 | +static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
| 160 | + enum { ARG_buffer, ARG_start, ARG_end }; |
| 161 | + static const mp_arg_t allowed_args[] = { |
| 162 | + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 163 | + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
| 164 | + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, |
| 165 | + }; |
| 166 | + |
| 167 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); |
| 168 | + check_for_deinit(self); |
| 169 | + check_lock(self); |
| 170 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 171 | + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 172 | + |
| 173 | + mp_buffer_info_t bufinfo; |
| 174 | + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); |
| 175 | + // Compute bounds in terms of elements, not bytes. |
| 176 | + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); |
| 177 | + int32_t start = args[ARG_start].u_int; |
| 178 | + size_t length = bufinfo.len / stride_in_bytes; |
| 179 | + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); |
| 180 | + |
| 181 | + // Treat start and length in terms of bytes from now on. |
| 182 | + start *= stride_in_bytes; |
| 183 | + length *= stride_in_bytes; |
| 184 | + |
| 185 | + if (length == 0) { |
| 186 | + return mp_const_none; |
| 187 | + } |
| 188 | + |
| 189 | + bool ok = common_hal_wiznet_pio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length); |
| 190 | + |
| 191 | + if (!ok) { |
| 192 | + mp_raise_OSError(MP_EIO); |
| 193 | + } |
| 194 | + return mp_const_none; |
| 195 | +} |
| 196 | +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_obj, 1, wiznet_pio_spi_write); |
| 197 | + |
| 198 | +// TODO: def readinto |
| 199 | + |
| 200 | +static mp_obj_t wiznet_pio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
| 201 | + enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; |
| 202 | + static const mp_arg_t allowed_args[] = { |
| 203 | + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, |
| 204 | + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
| 205 | + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, |
| 206 | + { MP_QSTR_write_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, |
| 207 | + }; |
| 208 | + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); |
| 209 | + check_for_deinit(self); |
| 210 | + check_lock(self); |
| 211 | + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; |
| 212 | + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); |
| 213 | + |
| 214 | + mp_buffer_info_t bufinfo; |
| 215 | + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); |
| 216 | + // Compute bounds in terms of elements, not bytes. |
| 217 | + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); |
| 218 | + int32_t start = args[ARG_start].u_int; |
| 219 | + size_t length = bufinfo.len / stride_in_bytes; |
| 220 | + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); |
| 221 | + |
| 222 | + // Treat start and length in terms of bytes from now on. |
| 223 | + start *= stride_in_bytes; |
| 224 | + length *= stride_in_bytes; |
| 225 | + |
| 226 | + if (length == 0) { |
| 227 | + return mp_const_none; |
| 228 | + } |
| 229 | + |
| 230 | + bool ok = common_hal_wiznet_pio_spi_read(self, ((uint8_t *)bufinfo.buf) + start, length, args[ARG_write_value].u_int); |
| 231 | + if (!ok) { |
| 232 | + mp_raise_OSError(MP_EIO); |
| 233 | + } |
| 234 | + return mp_const_none; |
| 235 | +} |
| 236 | +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_readinto_obj, 1, wiznet_pio_spi_readinto); |
| 237 | + |
| 238 | +#endif // CIRCUITPY_WIZNET |
| 239 | + |
| 240 | +static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { |
| 241 | + #if CIRCUITPY_WIZNET |
| 242 | + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wiznet_pio_spi_deinit_obj) }, |
| 243 | + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, |
| 244 | + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, |
| 245 | + |
| 246 | + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&wiznet_pio_spi_configure_obj) }, |
| 247 | + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&wiznet_pio_spi_try_lock_obj) }, |
| 248 | + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&wiznet_pio_spi_unlock_obj) }, |
| 249 | + |
| 250 | + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&wiznet_pio_spi_readinto_obj) }, |
| 251 | + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&wiznet_pio_spi_write_obj) }, |
| 252 | + |
| 253 | + #endif // CIRCUITPY_WIZNET |
| 254 | +}; |
| 255 | +static MP_DEFINE_CONST_DICT(wiznet_pio_spi_locals_dict, wiznet_pio_spi_locals_dict_table); |
| 256 | + |
| 257 | +MP_DEFINE_CONST_OBJ_TYPE( |
| 258 | + wiznet_pio_spi_type, |
| 259 | + MP_QSTR_PIO_SPI, |
| 260 | + MP_TYPE_FLAG_NONE, |
| 261 | + make_new, wiznet_pio_spi_make_new, |
| 262 | + locals_dict, &wiznet_pio_spi_locals_dict |
| 263 | + ); |
| 264 | + |
| 265 | +wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj, qstr arg_name) { |
| 266 | + return mp_arg_validate_type(obj, &wiznet_pio_spi_type, arg_name); |
| 267 | +} |
0 commit comments