summaryrefslogtreecommitdiffstatshomepage
path: root/extmod
diff options
context:
space:
mode:
Diffstat (limited to 'extmod')
-rw-r--r--extmod/machine_i2c.c440
-rw-r--r--extmod/machine_i2c.h23
-rw-r--r--extmod/machine_mem.c2
-rw-r--r--extmod/machine_spi.c204
-rw-r--r--extmod/machine_spi.h7
-rw-r--r--extmod/modbtree.c7
-rw-r--r--extmod/modframebuf.c453
-rw-r--r--extmod/modlwip.c34
-rw-r--r--extmod/modurandom.c2
-rw-r--r--extmod/moduselect.c312
-rw-r--r--extmod/modussl_axtls.c1
-rw-r--r--extmod/modussl_mbedtls.c1
-rw-r--r--extmod/modutimeq.c212
-rw-r--r--extmod/moduzlib.c1
-rw-r--r--extmod/vfs_fat.c6
-rw-r--r--extmod/vfs_fat_file.c20
-rw-r--r--extmod/vfs_fat_lexer.c83
-rw-r--r--extmod/vfs_fat_reader.c88
18 files changed, 1579 insertions, 317 deletions
diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c
index e201b23990..c0a51a6e7f 100644
--- a/extmod/machine_i2c.c
+++ b/extmod/machine_i2c.c
@@ -28,21 +28,14 @@
#include <stdint.h>
#include <string.h>
+#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/runtime.h"
#include "extmod/machine_i2c.h"
#if MICROPY_PY_MACHINE_I2C
-// Clock stretching limit, so that we don't get stuck.
-#define I2C_STRETCH_LIMIT 255
-
-typedef struct _machine_i2c_obj_t {
- mp_obj_base_t base;
- uint32_t us_delay;
- mp_hal_pin_obj_t scl;
- mp_hal_pin_obj_t sda;
-} machine_i2c_obj_t;
+typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t;
STATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) {
// We need to use an accurate delay to get acceptable I2C
@@ -54,13 +47,19 @@ STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) {
mp_hal_pin_od_low(self->scl);
}
-STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
+STATIC int mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
+ uint32_t count = self->us_timeout;
+
mp_hal_pin_od_high(self->scl);
mp_hal_i2c_delay(self);
// For clock stretching, wait for the SCL pin to be released, with timeout.
- for (int count = I2C_STRETCH_LIMIT; mp_hal_pin_read(self->scl) == 0 && count; --count) {
+ for (; mp_hal_pin_read(self->scl) == 0 && count; --count) {
mp_hal_delay_us_fast(1);
}
+ if (count == 0) {
+ return -MP_ETIMEDOUT;
+ }
+ return 0; // success
}
STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {
@@ -75,21 +74,26 @@ STATIC int mp_hal_i2c_sda_read(machine_i2c_obj_t *self) {
return mp_hal_pin_read(self->sda);
}
-STATIC void mp_hal_i2c_start(machine_i2c_obj_t *self) {
+STATIC int mp_hal_i2c_start(machine_i2c_obj_t *self) {
mp_hal_i2c_sda_release(self);
mp_hal_i2c_delay(self);
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
+ if (ret != 0) {
+ return ret;
+ }
mp_hal_i2c_sda_low(self);
mp_hal_i2c_delay(self);
+ return 0; // success
}
-STATIC void mp_hal_i2c_stop(machine_i2c_obj_t *self) {
+STATIC int mp_hal_i2c_stop(machine_i2c_obj_t *self) {
mp_hal_i2c_delay(self);
mp_hal_i2c_sda_low(self);
mp_hal_i2c_delay(self);
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
mp_hal_i2c_sda_release(self);
mp_hal_i2c_delay(self);
+ return ret;
}
STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) {
@@ -99,9 +103,13 @@ STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) {
}
mp_hal_pin_open_drain(self->scl);
mp_hal_pin_open_drain(self->sda);
- mp_hal_i2c_stop(self);
+ mp_hal_i2c_stop(self); // ignore error
}
+// return value:
+// 0 - byte written and ack received
+// 1 - byte written and nack received
+// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self);
@@ -113,21 +121,31 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
mp_hal_i2c_sda_low(self);
}
mp_hal_i2c_delay(self);
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
+ if (ret != 0) {
+ mp_hal_i2c_sda_release(self);
+ return ret;
+ }
mp_hal_i2c_scl_low(self);
}
mp_hal_i2c_sda_release(self);
mp_hal_i2c_delay(self);
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
+ if (ret != 0) {
+ return ret;
+ }
- int ret = mp_hal_i2c_sda_read(self);
+ int ack = mp_hal_i2c_sda_read(self);
mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self);
- return !ret;
+ return ack;
}
+// return value:
+// 0 - success
+// <0 - error, with errno being the negative of the return value
STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack) {
mp_hal_i2c_delay(self);
mp_hal_i2c_scl_low(self);
@@ -135,7 +153,10 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
uint8_t data = 0;
for (int i = 7; i >= 0; i--) {
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
+ if (ret != 0) {
+ return ret;
+ }
data = (data << 1) | mp_hal_i2c_sda_read(self);
mp_hal_i2c_scl_low(self);
mp_hal_i2c_delay(self);
@@ -147,111 +168,140 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
mp_hal_i2c_sda_low(self);
}
mp_hal_i2c_delay(self);
- mp_hal_i2c_scl_release(self);
+ int ret = mp_hal_i2c_scl_release(self);
+ if (ret != 0) {
+ mp_hal_i2c_sda_release(self);
+ return ret;
+ }
mp_hal_i2c_scl_low(self);
mp_hal_i2c_sda_release(self);
- return 1; // success
+ return 0; // success
}
-// addr is the device address, memaddr is a memory address sent big-endian
-STATIC int mp_hal_i2c_write_addresses(machine_i2c_obj_t *self, uint8_t addr,
- uint32_t memaddr, uint8_t addrsize) {
- if (!mp_hal_i2c_write_byte(self, addr << 1)) {
- return 0; // error
- }
- for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
- if (!mp_hal_i2c_write_byte(self, memaddr >> i)) {
- return 0; // error
- }
- }
- return 1; // success
-}
+// return value:
+// >=0 - number of acks received
+// <0 - error, with errno being the negative of the return value
+int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
-STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr,
- uint32_t memaddr, uint8_t addrsize, const uint8_t *src, size_t len) {
// start the I2C transaction
- mp_hal_i2c_start(self);
+ int ret = mp_hal_i2c_start(self);
+ if (ret != 0) {
+ return ret;
+ }
- // write the slave address and the memory address within the slave
- if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
- goto er;
+ // write the slave address
+ ret = mp_hal_i2c_write_byte(self, addr << 1);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != 0) {
+ // nack received, release the bus cleanly
+ mp_hal_i2c_stop(self);
+ return -MP_ENODEV;
}
// write the buffer to the I2C memory
+ int num_acks = 0;
while (len--) {
- if (!mp_hal_i2c_write_byte(self, *src++)) {
- goto er;
+ ret = mp_hal_i2c_write_byte(self, *src++);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != 0) {
+ // nack received, stop sending
+ break;
}
+ ++num_acks;
}
// finish the I2C transaction
- mp_hal_i2c_stop(self);
- return;
+ if (stop) {
+ ret = mp_hal_i2c_stop(self);
+ if (ret != 0) {
+ return ret;
+ }
+ }
-er:
- mp_hal_i2c_stop(self);
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
+ return num_acks;
}
-STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr,
- uint32_t memaddr, uint8_t addrsize, uint8_t *dest, size_t len) {
- // start the I2C transaction
- mp_hal_i2c_start(self);
-
- if (addrsize) {
- // write the slave address and the memory address within the slave
- if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) {
- goto er;
- }
+// return value:
+// 0 - success
+// <0 - error, with errno being the negative of the return value
+int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
- // i2c_read will do a repeated start, and then read the I2C memory
- mp_hal_i2c_start(self);
+ // start the I2C transaction
+ int ret = mp_hal_i2c_start(self);
+ if (ret != 0) {
+ return ret;
}
- if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) {
- goto er;
+ // write the slave address
+ ret = mp_hal_i2c_write_byte(self, (addr << 1) | 1);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != 0) {
+ // nack received, release the bus cleanly
+ mp_hal_i2c_stop(self);
+ return -MP_ENODEV;
}
+
+ // read the bytes from the slave
while (len--) {
- if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) {
- goto er;
+ ret = mp_hal_i2c_read_byte(self, dest++, len == 0);
+ if (ret != 0) {
+ return ret;
}
}
- mp_hal_i2c_stop(self);
- return;
-
-er:
- mp_hal_i2c_stop(self);
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
-}
-STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, const uint8_t *src, size_t len) {
- mp_hal_i2c_write_mem(self, addr, 0, 0, src, len);
-}
+ // finish the I2C transaction
+ if (stop) {
+ ret = mp_hal_i2c_stop(self);
+ if (ret != 0) {
+ return ret;
+ }
+ }
-STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *dest, size_t len) {
- mp_hal_i2c_read_mem(self, addr, 0, 0, dest, len);
+ return 0; // success
}
/******************************************************************************/
// MicroPython bindings for I2C
STATIC void machine_i2c_obj_init_helper(machine_i2c_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_scl, ARG_sda, ARG_freq };
+ enum { ARG_scl, ARG_sda, ARG_freq, ARG_timeout };
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_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} },
};
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);
self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj);
self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj);
+ self->us_timeout = args[ARG_timeout].u_int;
mp_hal_i2c_init(self, args[ARG_freq].u_int);
}
STATIC mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
+ // check the id argument, if given
+ if (n_args > 0) {
+ if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) {
+ #if defined(MICROPY_PY_MACHINE_I2C_MAKE_NEW)
+ // dispatch to port-specific constructor
+ extern mp_obj_t MICROPY_PY_MACHINE_I2C_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
+ return MICROPY_PY_MACHINE_I2C_MAKE_NEW(type, n_args, n_kw, args);
+ #else
+ mp_raise_ValueError("invalid I2C peripheral");
+ #endif
+ }
+ --n_args;
+ ++args;
+ }
+
+ // create new soft I2C object
machine_i2c_obj_t *self = m_new_obj(machine_i2c_obj_t);
self->base.type = &machine_i2c_type;
mp_map_t kw_args;
@@ -267,99 +317,188 @@ STATIC mp_obj_t machine_i2c_obj_init(size_t n_args, const mp_obj_t *args, mp_map
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_init_obj, 1, machine_i2c_obj_init);
STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_base_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
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) {
- mp_hal_i2c_start(self);
- int ack = mp_hal_i2c_write_byte(self, (addr << 1));
- if (ack) {
+ int ret = i2c_p->writeto(self, addr, NULL, 0, true);
+ if (ret == 0) {
mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
}
- mp_hal_i2c_stop(self);
}
return list;
}
MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_scan_obj, machine_i2c_scan);
STATIC mp_obj_t machine_i2c_start(mp_obj_t self_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_hal_i2c_start(self);
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ if (i2c_p->start == NULL) {
+ mp_raise_msg(&mp_type_OSError, "I2C operation not supported");
+ }
+ int ret = i2c_p->start(self);
+ if (ret != 0) {
+ mp_raise_OSError(-ret);
+ }
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_start_obj, machine_i2c_start);
STATIC mp_obj_t machine_i2c_stop(mp_obj_t self_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_hal_i2c_stop(self);
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ if (i2c_p->stop == NULL) {
+ mp_raise_msg(&mp_type_OSError, "I2C operation not supported");
+ }
+ int ret = i2c_p->stop(self);
+ if (ret != 0) {
+ mp_raise_OSError(-ret);
+ }
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_stop_obj, machine_i2c_stop);
-STATIC mp_obj_t machine_i2c_readinto(mp_obj_t self_in, mp_obj_t buf_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC mp_obj_t machine_i2c_readinto(size_t n_args, const mp_obj_t *args) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ if (i2c_p->read == NULL) {
+ mp_raise_msg(&mp_type_OSError, "I2C operation not supported");
+ }
// get the buffer to read into
mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
+ mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
+
+ // work out if we want to send a nack at the end
+ bool nack = (n_args == 2) ? true : mp_obj_is_true(args[2]);
// do the read
- uint8_t *dest = bufinfo.buf;
- while (bufinfo.len--) {
- if (!mp_hal_i2c_read_byte(self, dest++, bufinfo.len == 0)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
- }
+ int ret = i2c_p->read(self, bufinfo.buf, bufinfo.len, nack);
+ if (ret != 0) {
+ mp_raise_OSError(-ret);
}
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_readinto_obj, machine_i2c_readinto);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readinto_obj, 2, 3, machine_i2c_readinto);
STATIC mp_obj_t machine_i2c_write(mp_obj_t self_in, mp_obj_t buf_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ if (i2c_p->write == NULL) {
+ mp_raise_msg(&mp_type_OSError, "I2C operation not supported");
+ }
// get the buffer to write from
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
// do the write
- uint8_t *src = bufinfo.buf;
- while (bufinfo.len--) {
- if (!mp_hal_i2c_write_byte(self, *src++)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
- }
+ int ret = i2c_p->write(self, bufinfo.buf, bufinfo.len);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
}
- return mp_const_none;
+ // return number of acks received
+ return MP_OBJ_NEW_SMALL_INT(ret);
}
MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write);
-STATIC mp_obj_t machine_i2c_readfrom(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t nbytes_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ mp_int_t addr = mp_obj_get_int(args[1]);
vstr_t vstr;
- vstr_init_len(&vstr, mp_obj_get_int(nbytes_in));
- mp_hal_i2c_read(self, mp_obj_get_int(addr_in), (uint8_t*)vstr.buf, vstr.len);
+ vstr_init_len(&vstr, mp_obj_get_int(args[2]));
+ bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
+ int ret = i2c_p->readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
-MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_obj, machine_i2c_readfrom);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_readfrom);
-STATIC mp_obj_t machine_i2c_readfrom_into(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t buf_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ mp_int_t addr = mp_obj_get_int(args[1]);
mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
- mp_hal_i2c_read(self, mp_obj_get_int(addr_in), (uint8_t*)bufinfo.buf, bufinfo.len);
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
+ bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
+ int ret = i2c_p->readfrom(self, addr, bufinfo.buf, bufinfo.len, stop);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_readfrom_into_obj, machine_i2c_readfrom_into);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine_i2c_readfrom_into);
-STATIC mp_obj_t machine_i2c_writeto(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t buf_in) {
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ mp_int_t addr = mp_obj_get_int(args[1]);
mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
- mp_hal_i2c_write(self, mp_obj_get_int(addr_in), bufinfo.buf, bufinfo.len);
- return mp_const_none;
+ mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
+ bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
+ int ret = i2c_p->writeto(self, addr, bufinfo.buf, bufinfo.len, stop);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
+ // return number of acks received
+ return MP_OBJ_NEW_SMALL_INT(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto);
+
+STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+ uint8_t memaddr_buf[4];
+ size_t memaddr_len = 0;
+ for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
+ memaddr_buf[memaddr_len++] = memaddr >> i;
+ }
+ int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false);
+ if (ret != memaddr_len) {
+ // must generate STOP
+ i2c_p->writeto(self, addr, NULL, 0, true);
+ return ret;
+ }
+ return i2c_p->readfrom(self, addr, buf, len, true);
+}
+
+#define MAX_MEMADDR_SIZE (4)
+#define BUF_STACK_SIZE (12)
+
+STATIC int write_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, const uint8_t *buf, size_t len) {
+ mp_obj_base_t *self = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in);
+ mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+
+ // need some memory to create the buffer to send; try to use stack if possible
+ uint8_t buf2_stack[MAX_MEMADDR_SIZE + BUF_STACK_SIZE];
+ uint8_t *buf2;
+ size_t buf2_alloc = 0;
+ if (len <= BUF_STACK_SIZE) {
+ buf2 = buf2_stack;
+ } else {
+ buf2_alloc = MAX_MEMADDR_SIZE + len;
+ buf2 = m_new(uint8_t, buf2_alloc);
+ }
+
+ // create the buffer to send
+ size_t memaddr_len = 0;
+ for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
+ buf2[memaddr_len++] = memaddr >> i;
+ }
+ memcpy(buf2 + memaddr_len, buf, len);
+
+ int ret = i2c_p->writeto(self, addr, buf2, memaddr_len + len, true);
+ if (buf2_alloc != 0) {
+ m_del(uint8_t, buf2, buf2_alloc);
+ }
+ return ret;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_i2c_writeto_obj, machine_i2c_writeto);
STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
@@ -370,7 +509,6 @@ STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_n, ARG_addrsize };
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
@@ -380,8 +518,12 @@ STATIC mp_obj_t machine_i2c_readfrom_mem(size_t n_args, const mp_obj_t *pos_args
vstr_init_len(&vstr, mp_obj_get_int(args[ARG_n].u_obj));
// do the transfer
- mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
+ int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
+
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom_mem);
@@ -389,7 +531,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_obj, 1, machine_i2c_readfrom
STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
@@ -399,15 +540,17 @@ STATIC mp_obj_t machine_i2c_readfrom_mem_into(size_t n_args, const mp_obj_t *pos
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_WRITE);
// do the transfer
- mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
+ int ret = read_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_readfrom_mem_into_obj, 1, machine_i2c_readfrom_mem_into);
STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_addr, ARG_memaddr, ARG_buf, ARG_addrsize };
- machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(machine_i2c_mem_allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
MP_ARRAY_SIZE(machine_i2c_mem_allowed_args), machine_i2c_mem_allowed_args, args);
@@ -417,8 +560,12 @@ STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args,
mp_get_buffer_raise(args[ARG_buf].u_obj, &bufinfo, MP_BUFFER_READ);
// do the transfer
- mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int,
+ int ret = write_mem(pos_args[0], args[ARG_addr].u_int, args[ARG_memaddr].u_int,
args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len);
+ if (ret < 0) {
+ mp_raise_OSError(-ret);
+ }
+
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem);
@@ -444,13 +591,50 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_writeto_mem), MP_ROM_PTR(&machine_i2c_writeto_mem_obj) },
};
-STATIC MP_DEFINE_CONST_DICT(machine_i2c_locals_dict, machine_i2c_locals_dict_table);
+MP_DEFINE_CONST_DICT(mp_machine_soft_i2c_locals_dict, machine_i2c_locals_dict_table);
+
+int mp_machine_soft_i2c_read(mp_obj_base_t *self_in, uint8_t *dest, size_t len, bool nack) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
+ while (len--) {
+ int ret = mp_hal_i2c_read_byte(self, dest++, nack && (len == 0));
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ return 0; // success
+}
+
+int mp_machine_soft_i2c_write(mp_obj_base_t *self_in, const uint8_t *src, size_t len) {
+ machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
+ int num_acks = 0;
+ while (len--) {
+ int ret = mp_hal_i2c_write_byte(self, *src++);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != 0) {
+ // nack received, stop sending
+ break;
+ }
+ ++num_acks;
+ }
+ return num_acks;
+}
+
+STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {
+ .start = (int(*)(mp_obj_base_t*))mp_hal_i2c_start,
+ .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop,
+ .read = mp_machine_soft_i2c_read,
+ .write = mp_machine_soft_i2c_write,
+ .readfrom = mp_machine_soft_i2c_readfrom,
+ .writeto = mp_machine_soft_i2c_writeto,
+};
const mp_obj_type_t machine_i2c_type = {
{ &mp_type_type },
.name = MP_QSTR_I2C,
.make_new = machine_i2c_make_new,
- .locals_dict = (mp_obj_dict_t*)&machine_i2c_locals_dict,
+ .protocol = &mp_machine_soft_i2c_p,
+ .locals_dict = (mp_obj_dict_t*)&mp_machine_soft_i2c_locals_dict,
};
#endif // MICROPY_PY_MACHINE_I2C
diff --git a/extmod/machine_i2c.h b/extmod/machine_i2c.h
index 03fa6422ad..d49ff01e46 100644
--- a/extmod/machine_i2c.h
+++ b/extmod/machine_i2c.h
@@ -29,6 +29,29 @@
#include "py/obj.h"
+// I2C protocol
+// the first 4 methods can be NULL, meaning operation is not supported
+typedef struct _mp_machine_i2c_p_t {
+ int (*start)(mp_obj_base_t *obj);
+ int (*stop)(mp_obj_base_t *obj);
+ int (*read)(mp_obj_base_t *obj, uint8_t *dest, size_t len, bool nack);
+ int (*write)(mp_obj_base_t *obj, const uint8_t *src, size_t len);
+ int (*readfrom)(mp_obj_base_t *obj, uint16_t addr, uint8_t *dest, size_t len, bool stop);
+ int (*writeto)(mp_obj_base_t *obj, uint16_t addr, const uint8_t *src, size_t len, bool stop);
+} mp_machine_i2c_p_t;
+
+typedef struct _mp_machine_soft_i2c_obj_t {
+ mp_obj_base_t base;
+ uint32_t us_delay;
+ uint32_t us_timeout;
+ mp_hal_pin_obj_t scl;
+ mp_hal_pin_obj_t sda;
+} mp_machine_soft_i2c_obj_t;
+
extern const mp_obj_type_t machine_i2c_type;
+extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict;
+
+int mp_machine_soft_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop);
+int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop);
#endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H__
diff --git a/extmod/machine_mem.c b/extmod/machine_mem.c
index 8151bab47f..88c176803f 100644
--- a/extmod/machine_mem.c
+++ b/extmod/machine_mem.c
@@ -31,7 +31,7 @@
// If you wish to override the functions for mapping the machine_mem read/write
// address, then add a #define for MICROPY_MACHINE_MEM_GET_READ_ADDR and/or
-// MICROPY_MACHINE_MEM_GET_WRITE_ADDR in yopur mpconfigport.h. Since the
+// MICROPY_MACHINE_MEM_GET_WRITE_ADDR in your mpconfigport.h. Since the
// prototypes are identical, it is allowable for both of the macros to evaluate
// the to same function.
//
diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c
index e3d72ab588..6e76784988 100644
--- a/extmod/machine_spi.c
+++ b/extmod/machine_spi.c
@@ -32,6 +32,12 @@
#if MICROPY_PY_MACHINE_SPI
+// if a port didn't define MSB/LSB constants then provide them
+#ifndef MICROPY_PY_MACHINE_SPI_MSB
+#define MICROPY_PY_MACHINE_SPI_MSB (0)
+#define MICROPY_PY_MACHINE_SPI_LSB (1)
+#endif
+
void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
uint32_t delay_half = self->delay_half;
@@ -93,6 +99,49 @@ void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint
}
}
+/******************************************************************************/
+// MicroPython bindings for generic machine.SPI
+
+STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
+
+mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // check the id argument, if given
+ if (n_args > 0) {
+ if (args[0] != MP_OBJ_NEW_SMALL_INT(-1)) {
+ #if defined(MICROPY_PY_MACHINE_SPI_MAKE_NEW)
+ // dispatch to port-specific constructor
+ extern mp_obj_t MICROPY_PY_MACHINE_SPI_MAKE_NEW(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args);
+ return MICROPY_PY_MACHINE_SPI_MAKE_NEW(type, n_args, n_kw, args);
+ #else
+ mp_raise_ValueError("invalid SPI peripheral");
+ #endif
+ }
+ --n_args;
+ ++args;
+ }
+
+ // software SPI
+ return mp_machine_soft_spi_make_new(type, n_args, n_kw, args);
+}
+
+STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
+ mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;
+ spi_p->init(s, n_args - 1, args + 1, kw_args);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_spi_init_obj, 1, machine_spi_init);
+
+STATIC mp_obj_t machine_spi_deinit(mp_obj_t self) {
+ mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self);
+ mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;
+ if (spi_p->deinit != NULL) {
+ spi_p->deinit(s);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_deinit);
+
STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t len, const void *src, void *dest) {
mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self);
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol;
@@ -138,4 +187,159 @@ STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp
}
MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto);
+STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) },
+ { MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) },
+};
+
+MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
+
+/******************************************************************************/
+// Implementation of soft SPI
+
+STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
+ #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
+ if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
+ return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE;
+ } else
+ #endif
+ {
+ return 500000 / delay_half;
+ }
+}
+
+STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
+ #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
+ if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) {
+ return MICROPY_PY_MACHINE_SPI_MIN_DELAY;
+ } else
+ #endif
+ {
+ uint32_t delay_half = 500000 / baudrate;
+ // round delay_half up so that: actual_baudrate <= requested_baudrate
+ if (500000 % baudrate != 0) {
+ delay_half += 1;
+ }
+ return delay_half;
+ }
+}
+
+STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u,"
+ " sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
+ baudrate_from_delay_half(self->delay_half), self->polarity, self->phase,
+ mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso));
+}
+
+STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_sck, ARG_mosi, ARG_miso };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 500000} },
+ { 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} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_PY_MACHINE_SPI_MSB} },
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // create new object
+ mp_machine_soft_spi_obj_t *self = m_new_obj(mp_machine_soft_spi_obj_t);
+ self->base.type = &mp_machine_soft_spi_type;
+
+ // set parameters
+ self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
+ self->polarity = args[ARG_polarity].u_int;
+ self->phase = args[ARG_phase].u_int;
+ if (args[ARG_bits].u_int != 8) {
+ mp_raise_ValueError("bits must be 8");
+ }
+ if (args[ARG_firstbit].u_int != MICROPY_PY_MACHINE_SPI_MSB) {
+ mp_raise_ValueError("firstbit must be MSB");
+ }
+ if (args[ARG_sck].u_obj == MP_OBJ_NULL
+ || args[ARG_mosi].u_obj == MP_OBJ_NULL
+ || args[ARG_miso].u_obj == MP_OBJ_NULL) {
+ mp_raise_ValueError("must specify all of sck/mosi/miso");
+ }
+ self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+ self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
+ self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
+
+ // configure pins
+ mp_hal_pin_write(self->sck, self->polarity);
+ mp_hal_pin_output(self->sck);
+ mp_hal_pin_output(self->mosi);
+ mp_hal_pin_input(self->miso);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
+
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ };
+ 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);
+
+ if (args[ARG_baudrate].u_int != -1) {
+ self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
+ }
+ if (args[ARG_polarity].u_int != -1) {
+ self->polarity = args[ARG_polarity].u_int;
+ }
+ if (args[ARG_phase].u_int != -1) {
+ self->phase = args[ARG_phase].u_int;
+ }
+ if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
+ self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+ }
+ if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
+ self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
+ }
+ if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
+ self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
+ }
+
+ // configure pins
+ mp_hal_pin_write(self->sck, self->polarity);
+ mp_hal_pin_output(self->sck);
+ mp_hal_pin_output(self->mosi);
+ mp_hal_pin_input(self->miso);
+}
+
+STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = {
+ .init = mp_machine_soft_spi_init,
+ .deinit = NULL,
+ .transfer = mp_machine_soft_spi_transfer,
+};
+
+const mp_obj_type_t mp_machine_soft_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SoftSPI,
+ .print = mp_machine_soft_spi_print,
+ .make_new = mp_machine_spi_make_new, // delegate to master constructor
+ .protocol = &mp_machine_soft_spi_p,
+ .locals_dict = (mp_obj_dict_t*)&mp_machine_spi_locals_dict,
+};
+
#endif // MICROPY_PY_MACHINE_SPI
diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h
index 62f42a8851..88a3e19f41 100644
--- a/extmod/machine_spi.h
+++ b/extmod/machine_spi.h
@@ -32,6 +32,8 @@
// SPI protocol
typedef struct _mp_machine_spi_p_t {
+ void (*init)(mp_obj_base_t *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
+ void (*deinit)(mp_obj_base_t *obj); // can be NULL
void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest);
} mp_machine_spi_p_t;
@@ -45,8 +47,13 @@ typedef struct _mp_machine_soft_spi_obj_t {
mp_hal_pin_obj_t miso;
} mp_machine_soft_spi_obj_t;
+extern const mp_obj_type_t mp_machine_soft_spi_type;
+extern const mp_obj_dict_t mp_machine_spi_locals_dict;
+
void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest);
+mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
+
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj);
MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj);
diff --git a/extmod/modbtree.c b/extmod/modbtree.c
index f5ec5bfca1..bb75845b1b 100644
--- a/extmod/modbtree.c
+++ b/extmod/modbtree.c
@@ -81,6 +81,12 @@ STATIC void btree_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind
mp_printf(print, "<btree %p>", self->db);
}
+STATIC mp_obj_t btree_flush(mp_obj_t self_in) {
+ mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(__bt_sync(self->db, 0));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(btree_flush_obj, btree_flush);
+
STATIC mp_obj_t btree_close(mp_obj_t self_in) {
mp_obj_btree_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(__bt_close(self->db));
@@ -314,6 +320,7 @@ STATIC mp_obj_t btree_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in)
STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&btree_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&btree_get_obj) },
{ MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&btree_put_obj) },
{ MP_ROM_QSTR(MP_QSTR_seq), MP_ROM_PTR(&btree_seq_obj) },
diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c
index cd7f1c5e4b..d6e686e076 100644
--- a/extmod/modframebuf.c
+++ b/extmod/modframebuf.c
@@ -35,18 +35,106 @@
#include "stmhal/font_petme128_8x8.h"
-// 1-bit frame buffer, each byte is a column of 8 pixels
-typedef struct _mp_obj_framebuf1_t {
+typedef struct _mp_obj_framebuf_t {
mp_obj_base_t base;
- uint8_t *buf;
+ mp_obj_t buf_obj; // need to store this to prevent GC from reclaiming buf
+ void *buf;
uint16_t width, height, stride;
-} mp_obj_framebuf1_t;
+ uint8_t format;
+} mp_obj_framebuf_t;
-STATIC mp_obj_t framebuf1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 3, 4, false);
+typedef void (*setpixel_t)(const mp_obj_framebuf_t*, int, int, uint32_t);
+typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t*, int, int);
+typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
- mp_obj_framebuf1_t *o = m_new_obj(mp_obj_framebuf1_t);
+typedef struct _mp_framebuf_p_t {
+ setpixel_t setpixel;
+ getpixel_t getpixel;
+ fill_rect_t fill_rect;
+} mp_framebuf_p_t;
+
+// Functions for MVLSB format
+
+STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
+ size_t index = (y >> 3) * fb->stride + x;
+ uint8_t offset = y & 0x07;
+ ((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((color != 0) << offset);
+}
+
+STATIC uint32_t mvlsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
+ return (((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x] >> (y & 0x07)) & 0x01;
+}
+
+STATIC void mvlsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
+ while (h--) {
+ uint8_t *b = &((uint8_t*)fb->buf)[(y >> 3) * fb->stride + x];
+ uint8_t offset = y & 0x07;
+ for (int ww = w; ww; --ww) {
+ *b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
+ ++b;
+ }
+ ++y;
+ }
+}
+
+// Functions for RGB565 format
+
+STATIC void rgb565_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
+ ((uint16_t*)fb->buf)[x + y * fb->stride] = color;
+}
+
+STATIC uint32_t rgb565_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
+ return ((uint16_t*)fb->buf)[x + y * fb->stride];
+}
+
+STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t colour) {
+ uint16_t *b = &((uint16_t*)fb->buf)[x + y * fb->stride];
+ while (h--) {
+ for (int ww = w; ww; --ww) {
+ *b++ = colour;
+ }
+ b += fb->stride - w;
+ }
+}
+
+// constants for formats
+#define FRAMEBUF_MVLSB (0)
+#define FRAMEBUF_RGB565 (1)
+
+STATIC mp_framebuf_p_t formats[] = {
+ [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
+ [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
+};
+
+static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
+ formats[fb->format].setpixel(fb, x, y, color);
+}
+
+static inline uint32_t getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
+ return formats[fb->format].getpixel(fb, x, y);
+}
+
+STATIC void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
+ if (x + w <= 0 || y + h <= 0 || y >= fb->height || x >= fb->width) {
+ // No operation needed.
+ return;
+ }
+
+ // clip to the framebuffer
+ int xend = MIN(fb->width, x + w);
+ int yend = MIN(fb->height, y + h);
+ x = MAX(x, 0);
+ y = MAX(y, 0);
+
+ formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col);
+}
+
+STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 4, 5, false);
+
+ mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);
o->base.type = type;
+ o->buf_obj = args[0];
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
@@ -54,98 +142,263 @@ STATIC mp_obj_t framebuf1_make_new(const mp_obj_type_t *type, size_t n_args, siz
o->width = mp_obj_get_int(args[1]);
o->height = mp_obj_get_int(args[2]);
- o->stride = o->width;
- if (n_args >= 4) {
- o->stride = mp_obj_get_int(args[3]);
+ o->format = mp_obj_get_int(args[3]);
+ if (n_args >= 5) {
+ o->stride = mp_obj_get_int(args[4]);
+ } else {
+ o->stride = o->width;
+ }
+
+ switch (o->format) {
+ case FRAMEBUF_MVLSB:
+ case FRAMEBUF_RGB565:
+ break;
+ default:
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
+ "invalid format"));
}
return MP_OBJ_FROM_PTR(o);
}
-STATIC mp_obj_t framebuf1_fill(mp_obj_t self_in, mp_obj_t col_in) {
- mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in);
+STATIC mp_int_t framebuf_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
+ (void)flags;
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
+ bufinfo->buf = self->buf;
+ bufinfo->len = self->stride * self->height * (self->format == FRAMEBUF_RGB565 ? 2 : 1);
+ bufinfo->typecode = 'B'; // view framebuf as bytes
+ return 0;
+}
+
+STATIC mp_obj_t framebuf_fill(mp_obj_t self_in, mp_obj_t col_in) {
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
mp_int_t col = mp_obj_get_int(col_in);
- if (col) {
- col = 0xff;
- }
- int end = (self->height + 7) >> 3;
- for (int y = 0; y < end; ++y) {
- memset(self->buf + y * self->stride, col, self->width);
- }
+ formats[self->format].fill_rect(self, 0, 0, self->width, self->height, col);
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf1_fill_obj, framebuf1_fill);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf_fill_obj, framebuf_fill);
+
+STATIC mp_obj_t framebuf_fill_rect(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
-STATIC mp_obj_t framebuf1_pixel(size_t n_args, const mp_obj_t *args) {
- mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t x = mp_obj_get_int(args[1]);
+ mp_int_t y = mp_obj_get_int(args[2]);
+ mp_int_t width = mp_obj_get_int(args[3]);
+ mp_int_t height = mp_obj_get_int(args[4]);
+ mp_int_t color = mp_obj_get_int(args[5]);
+
+ fill_rect(self, x, y, width, height, color);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_fill_rect_obj, 6, 6, framebuf_fill_rect);
+
+STATIC mp_obj_t framebuf_pixel(size_t n_args, const mp_obj_t *args) {
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
if (0 <= x && x < self->width && 0 <= y && y < self->height) {
- int index = (y / 8) * self->stride + x;
if (n_args == 3) {
// get
- return MP_OBJ_NEW_SMALL_INT((self->buf[index] >> (y & 7)) & 1);
+ return MP_OBJ_NEW_SMALL_INT(getpixel(self, x, y));
} else {
// set
- if (mp_obj_get_int(args[3])) {
- self->buf[index] |= (1 << (y & 7));
- } else {
- self->buf[index] &= ~(1 << (y & 7));
- }
+ setpixel(self, x, y, mp_obj_get_int(args[3]));
}
}
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf1_pixel_obj, 3, 4, framebuf1_pixel);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_pixel_obj, 3, 4, framebuf_pixel);
-STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
- mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in);
- mp_int_t xstep = mp_obj_get_int(xstep_in);
- mp_int_t ystep = mp_obj_get_int(ystep_in);
- int end = (self->height + 7) >> 3;
- if (ystep > 0) {
- for (int y = end; y > 0;) {
- --y;
- for (int x = 0; x < self->width; ++x) {
- int prev = 0;
- if (y > 0) {
- prev = (self->buf[(y - 1) * self->stride + x] >> (8 - ystep)) & ((1 << ystep) - 1);
- }
- self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] << ystep) | prev;
- }
+STATIC mp_obj_t framebuf_hline(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t x = mp_obj_get_int(args[1]);
+ mp_int_t y = mp_obj_get_int(args[2]);
+ mp_int_t w = mp_obj_get_int(args[3]);
+ mp_int_t col = mp_obj_get_int(args[4]);
+
+ fill_rect(self, x, y, w, 1, col);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_hline_obj, 5, 5, framebuf_hline);
+
+STATIC mp_obj_t framebuf_vline(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t x = mp_obj_get_int(args[1]);
+ mp_int_t y = mp_obj_get_int(args[2]);
+ mp_int_t h = mp_obj_get_int(args[3]);
+ mp_int_t col = mp_obj_get_int(args[4]);
+
+ fill_rect(self, x, y, 1, h, col);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_vline_obj, 5, 5, framebuf_vline);
+
+STATIC mp_obj_t framebuf_rect(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t x = mp_obj_get_int(args[1]);
+ mp_int_t y = mp_obj_get_int(args[2]);
+ mp_int_t w = mp_obj_get_int(args[3]);
+ mp_int_t h = mp_obj_get_int(args[4]);
+ mp_int_t col = mp_obj_get_int(args[5]);
+
+ fill_rect(self, x, y, w, 1, col);
+ fill_rect(self, x, y + h- 1, w, 1, col);
+ fill_rect(self, x, y, 1, h, col);
+ fill_rect(self, x + w- 1, y, 1, h, col);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_rect_obj, 6, 6, framebuf_rect);
+
+STATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_int_t x1 = mp_obj_get_int(args[1]);
+ mp_int_t y1 = mp_obj_get_int(args[2]);
+ mp_int_t x2 = mp_obj_get_int(args[3]);
+ mp_int_t y2 = mp_obj_get_int(args[4]);
+ mp_int_t col = mp_obj_get_int(args[5]);
+
+ mp_int_t dx = x2 - x1;
+ mp_int_t sx;
+ if (dx > 0) {
+ sx = 1;
+ } else {
+ dx = -dx;
+ sx = -1;
+ }
+
+ mp_int_t dy = y2 - y1;
+ mp_int_t sy;
+ if (dy > 0) {
+ sy = 1;
+ } else {
+ dy = -dy;
+ sy = -1;
+ }
+
+ bool steep;
+ if (dy > dx) {
+ mp_int_t temp;
+ temp = x1; x1 = y1; y1 = temp;
+ temp = dx; dx = dy; dy = temp;
+ temp = sx; sx = sy; sy = temp;
+ steep = true;
+ } else {
+ steep = false;
+ }
+
+ mp_int_t e = 2 * dy - dx;
+ for (mp_int_t i = 0; i < dx; ++i) {
+ if (steep) {
+ setpixel(self, y1, x1, col);
+ } else {
+ setpixel(self, x1, y1, col);
}
- } else if (ystep < 0) {
- for (int y = 0; y < end; ++y) {
- for (int x = 0; x < self->width; ++x) {
- int prev = 0;
- if (y + 1 < end) {
- prev = self->buf[(y + 1) * self->stride + x] << (8 + ystep);
- }
- self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] >> -ystep) | prev;
- }
+ while (e >= 0) {
+ y1 += sy;
+ e -= 2 * dx;
}
+ x1 += sx;
+ e += 2 * dy;
}
- if (xstep < 0) {
- for (int y = 0; y < end; ++y) {
- for (int x = 0; x < self->width + xstep; ++x) {
- self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep];
+
+ setpixel(self, x2, y2, col);
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_line_obj, 6, 6, framebuf_line);
+
+STATIC mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args) {
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(args[1]);
+ mp_int_t x = mp_obj_get_int(args[2]);
+ mp_int_t y = mp_obj_get_int(args[3]);
+ mp_int_t key = -1;
+ if (n_args > 4) {
+ key = mp_obj_get_int(args[4]);
+ }
+
+ if (
+ (x >= self->width) ||
+ (y >= self->height) ||
+ (-x >= source->width) ||
+ (-y >= source->height)
+ ) {
+ // Out of bounds, no-op.
+ return mp_const_none;
+ }
+
+ // Clip.
+ int x0 = MAX(0, x);
+ int y0 = MAX(0, y);
+ int x1 = MAX(0, -x);
+ int y1 = MAX(0, -y);
+ int x0end = MIN(self->width, x + source->width);
+ int y0end = MIN(self->height, y + source->height);
+ uint32_t color;
+
+ for (; y0 < y0end; ++y0) {
+ int cx1 = x1;
+ for (int cx0 = x0; cx0 < x0end; ++cx0) {
+ color = getpixel(source, cx1, y1);
+ if (color != key) {
+ setpixel(self, cx0, y0, color);
}
+ ++cx1;
}
- } else if (xstep > 0) {
- for (int y = 0; y < end; ++y) {
- for (int x = self->width - 1; x >= xstep; --x) {
- self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep];
- }
+ ++y1;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_blit_obj, 4, 5, framebuf_blit);
+
+STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t xstep = mp_obj_get_int(xstep_in);
+ mp_int_t ystep = mp_obj_get_int(ystep_in);
+ int sx, y, xend, yend, dx, dy;
+ if (xstep < 0) {
+ sx = 0;
+ xend = self->width + xstep;
+ dx = 1;
+ } else {
+ sx = self->width - 1;
+ xend = xstep - 1;
+ dx = -1;
+ }
+ if (ystep < 0) {
+ y = 0;
+ yend = self->height + ystep;
+ dy = 1;
+ } else {
+ y = self->height - 1;
+ yend = ystep - 1;
+ dy = -1;
+ }
+ for (; y != yend; y += dy) {
+ for (int x = sx; x != xend; x += dx) {
+ setpixel(self, x, y, getpixel(self, x - xstep, y - ystep));
}
}
- // TODO: Should we clear the margin created by scrolling?
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf1_scroll_obj, framebuf1_scroll);
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf_scroll_obj, framebuf_scroll);
-STATIC mp_obj_t framebuf1_text(size_t n_args, const mp_obj_t *args) {
+STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) {
// extract arguments
- mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args[0]);
const char *str = mp_obj_str_get_str(args[1]);
mp_int_t x0 = mp_obj_get_int(args[2]);
mp_int_t y0 = mp_obj_get_int(args[3]);
@@ -170,43 +423,67 @@ STATIC mp_obj_t framebuf1_text(size_t n_args, const mp_obj_t *args) {
for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column
if (vline_data & 1) { // only draw if pixel set
if (0 <= y && y < self->height) { // clip y
- uint byte_pos = x0 + self->stride * ((uint)y >> 3);
- if (col == 0) {
- // clear pixel
- self->buf[byte_pos] &= ~(1 << (y & 7));
- } else {
- // set pixel
- self->buf[byte_pos] |= 1 << (y & 7);
- }
+ setpixel(self, x0, y, col);
}
}
}
}
}
}
-
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf1_text_obj, 4, 5, framebuf1_text);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text);
-STATIC const mp_rom_map_elem_t framebuf1_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf1_fill_obj) },
- { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf1_pixel_obj) },
- { MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf1_scroll_obj) },
- { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf1_text_obj) },
+STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf_fill_obj) },
+ { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf_pixel_obj) },
+ { MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&framebuf_hline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&framebuf_vline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&framebuf_rect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&framebuf_line_obj) },
+ { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&framebuf_blit_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf_scroll_obj) },
+ { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf_text_obj) },
};
-STATIC MP_DEFINE_CONST_DICT(framebuf1_locals_dict, framebuf1_locals_dict_table);
+STATIC MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table);
-STATIC const mp_obj_type_t mp_type_framebuf1 = {
+STATIC const mp_obj_type_t mp_type_framebuf = {
{ &mp_type_type },
- .name = MP_QSTR_FrameBuffer1,
- .make_new = framebuf1_make_new,
- .locals_dict = (mp_obj_t)&framebuf1_locals_dict,
+ .name = MP_QSTR_FrameBuffer,
+ .make_new = framebuf_make_new,
+ .buffer_p = { .get_buffer = framebuf_get_buffer },
+ .locals_dict = (mp_obj_t)&framebuf_locals_dict,
};
+// this factory function is provided for backwards compatibility with old FrameBuffer1 class
+STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) {
+ mp_obj_framebuf_t *o = m_new_obj(mp_obj_framebuf_t);
+ o->base.type = &mp_type_framebuf;
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
+ o->buf = bufinfo.buf;
+
+ o->width = mp_obj_get_int(args[1]);
+ o->height = mp_obj_get_int(args[2]);
+ o->format = FRAMEBUF_MVLSB;
+ if (n_args >= 4) {
+ o->stride = mp_obj_get_int(args[3]);
+ } else {
+ o->stride = o->width;
+ }
+
+ return MP_OBJ_FROM_PTR(o);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1);
+
STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) },
- { MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&mp_type_framebuf1) },
+ { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) },
+ { MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) },
+ { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB) },
+ { MP_ROM_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565) },
};
STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table);
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 11ba6e4231..62699bd417 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -114,7 +114,7 @@ u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len) {
}
// constructor lwip.slip(device=integer, iplocal=string, ipremote=string)
-STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 3, 3, false);
lwip_slip_obj.base.type = &lwip_slip_type;
@@ -578,8 +578,7 @@ STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
}
// FIXME: Only supports two arguments at present
-STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args,
- mp_uint_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 4, false);
lwip_socket_obj_t *socket = m_new_obj_with_finaliser(lwip_socket_obj_t);
@@ -1127,6 +1126,34 @@ STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t
return MP_STREAM_ERROR;
}
+STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ lwip_socket_obj_t *socket = self_in;
+ mp_uint_t ret;
+
+ if (request == MP_STREAM_POLL) {
+ uintptr_t flags = arg;
+ ret = 0;
+
+ if (flags & MP_STREAM_POLL_RD && socket->incoming.pbuf != NULL) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+
+ if (flags & MP_STREAM_POLL_WR && tcp_sndbuf(socket->pcb.tcp) > 0) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+
+ if (flags & MP_STREAM_POLL_HUP && socket->state == STATE_PEER_CLOSED) {
+ ret |= MP_STREAM_POLL_HUP;
+ }
+
+ } else {
+ *errcode = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+
+ return ret;
+}
+
STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&lwip_socket_close_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&lwip_socket_close_obj },
@@ -1153,6 +1180,7 @@ STATIC MP_DEFINE_CONST_DICT(lwip_socket_locals_dict, lwip_socket_locals_dict_tab
STATIC const mp_stream_p_t lwip_socket_stream_p = {
.read = lwip_socket_read,
.write = lwip_socket_write,
+ .ioctl = lwip_socket_ioctl,
};
STATIC const mp_obj_type_t lwip_socket_type = {
diff --git a/extmod/modurandom.c b/extmod/modurandom.c
index 995b0a2665..12e56741e3 100644
--- a/extmod/modurandom.c
+++ b/extmod/modurandom.c
@@ -206,9 +206,11 @@ STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_urandom_randrange_obj) },
{ MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_urandom_randint_obj) },
{ MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_urandom_choice_obj) },
+ #if MICROPY_PY_BUILTINS_FLOAT
{ MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_urandom_random_obj) },
{ MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_urandom_uniform_obj) },
#endif
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals_table);
diff --git a/extmod/moduselect.c b/extmod/moduselect.c
new file mode 100644
index 0000000000..5b00f6badd
--- /dev/null
+++ b/extmod/moduselect.c
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpconfig.h"
+#if MICROPY_PY_USELECT
+
+#include <stdio.h>
+
+#include "py/runtime.h"
+#include "py/obj.h"
+#include "py/objlist.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+
+// Flags for poll()
+#define FLAG_ONESHOT (1)
+
+/// \module select - Provides select function to wait for events on a stream
+///
+/// This module provides the select function.
+
+typedef struct _poll_obj_t {
+ mp_obj_t obj;
+ mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, mp_uint_t arg, int *errcode);
+ mp_uint_t flags;
+ mp_uint_t flags_ret;
+} poll_obj_t;
+
+STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {
+ for (mp_uint_t i = 0; i < obj_len; i++) {
+ mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ if (elem->value == NULL) {
+ // object not found; get its ioctl and add it to the poll list
+ const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
+ poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
+ poll_obj->obj = obj[i];
+ poll_obj->ioctl = stream_p->ioctl;
+ poll_obj->flags = flags;
+ poll_obj->flags_ret = 0;
+ elem->value = poll_obj;
+ } else {
+ // object exists; update its flags
+ if (or_flags) {
+ ((poll_obj_t*)elem->value)->flags |= flags;
+ } else {
+ ((poll_obj_t*)elem->value)->flags = flags;
+ }
+ }
+ }
+}
+
+// poll each object in the map
+STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, mp_uint_t *rwx_num) {
+ mp_uint_t n_ready = 0;
+ for (mp_uint_t i = 0; i < poll_map->alloc; ++i) {
+ if (!MP_MAP_SLOT_IS_FILLED(poll_map, i)) {
+ continue;
+ }
+
+ poll_obj_t *poll_obj = (poll_obj_t*)poll_map->table[i].value;
+ int errcode;
+ mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode);
+ poll_obj->flags_ret = ret;
+
+ if (ret == -1) {
+ // error doing ioctl
+ mp_raise_OSError(errcode);
+ }
+
+ if (ret != 0) {
+ // object is ready
+ n_ready += 1;
+ if (rwx_num != NULL) {
+ if (ret & MP_STREAM_POLL_RD) {
+ rwx_num[0] += 1;
+ }
+ if (ret & MP_STREAM_POLL_WR) {
+ rwx_num[1] += 1;
+ }
+ if ((ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
+ rwx_num[2] += 1;
+ }
+ }
+ }
+ }
+ return n_ready;
+}
+
+/// \function select(rlist, wlist, xlist[, timeout])
+STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) {
+ // get array data from tuple/list arguments
+ mp_uint_t rwx_len[3];
+ mp_obj_t *r_array, *w_array, *x_array;
+ mp_obj_get_array(args[0], &rwx_len[0], &r_array);
+ mp_obj_get_array(args[1], &rwx_len[1], &w_array);
+ mp_obj_get_array(args[2], &rwx_len[2], &x_array);
+
+ // get timeout
+ mp_uint_t timeout = -1;
+ if (n_args == 4) {
+ if (args[3] != mp_const_none) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ float timeout_f = mp_obj_get_float(args[3]);
+ if (timeout_f >= 0) {
+ timeout = (mp_uint_t)(timeout_f * 1000);
+ }
+ #else
+ timeout = mp_obj_get_int(args[3]) * 1000;
+ #endif
+ }
+ }
+
+ // merge separate lists and get the ioctl function for each object
+ mp_map_t poll_map;
+ mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]);
+ poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);
+ poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);
+ poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);
+
+ mp_uint_t start_tick = mp_hal_ticks_ms();
+ rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
+ for (;;) {
+ // poll the objects
+ mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len);
+
+ if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
+ // one or more objects are ready, or we had a timeout
+ mp_obj_t list_array[3];
+ list_array[0] = mp_obj_new_list(rwx_len[0], NULL);
+ list_array[1] = mp_obj_new_list(rwx_len[1], NULL);
+ list_array[2] = mp_obj_new_list(rwx_len[2], NULL);
+ rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
+ for (mp_uint_t i = 0; i < poll_map.alloc; ++i) {
+ if (!MP_MAP_SLOT_IS_FILLED(&poll_map, i)) {
+ continue;
+ }
+ poll_obj_t *poll_obj = (poll_obj_t*)poll_map.table[i].value;
+ if (poll_obj->flags_ret & MP_STREAM_POLL_RD) {
+ ((mp_obj_list_t*)list_array[0])->items[rwx_len[0]++] = poll_obj->obj;
+ }
+ if (poll_obj->flags_ret & MP_STREAM_POLL_WR) {
+ ((mp_obj_list_t*)list_array[1])->items[rwx_len[1]++] = poll_obj->obj;
+ }
+ if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
+ ((mp_obj_list_t*)list_array[2])->items[rwx_len[2]++] = poll_obj->obj;
+ }
+ }
+ mp_map_deinit(&poll_map);
+ return mp_obj_new_tuple(3, list_array);
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
+
+/// \class Poll - poll class
+
+typedef struct _mp_obj_poll_t {
+ mp_obj_base_t base;
+ mp_map_t poll_map;
+} mp_obj_poll_t;
+
+/// \method register(obj[, eventmask])
+STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = args[0];
+ mp_uint_t flags;
+ if (n_args == 3) {
+ flags = mp_obj_get_int(args[2]);
+ } else {
+ flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;
+ }
+ poll_map_add(&self->poll_map, &args[1], 1, flags, false);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
+
+/// \method unregister(obj)
+STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
+ mp_obj_poll_t *self = self_in;
+ mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
+ // TODO raise KeyError if obj didn't exist in map
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
+
+/// \method modify(obj, eventmask)
+STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
+ mp_obj_poll_t *self = self_in;
+ mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
+ if (elem == NULL) {
+ mp_raise_OSError(MP_ENOENT);
+ }
+ ((poll_obj_t*)elem->value)->flags = mp_obj_get_int(eventmask_in);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
+
+/// \method poll([timeout])
+/// Timeout is in milliseconds.
+STATIC mp_obj_t poll_poll(uint n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = args[0];
+
+ // work out timeout (its given already in ms)
+ mp_uint_t timeout = -1;
+ int flags = 0;
+ if (n_args >= 2) {
+ if (args[1] != mp_const_none) {
+ mp_int_t timeout_i = mp_obj_get_int(args[1]);
+ if (timeout_i >= 0) {
+ timeout = timeout_i;
+ }
+ }
+ if (n_args >= 3) {
+ flags = mp_obj_get_int(args[2]);
+ }
+ }
+
+ mp_uint_t start_tick = mp_hal_ticks_ms();
+ for (;;) {
+ // poll the objects
+ mp_uint_t n_ready = poll_map_poll(&self->poll_map, NULL);
+
+ if (n_ready > 0 || (timeout != -1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
+ // one or more objects are ready, or we had a timeout
+ mp_obj_list_t *ret_list = mp_obj_new_list(n_ready, NULL);
+ n_ready = 0;
+ for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) {
+ if (!MP_MAP_SLOT_IS_FILLED(&self->poll_map, i)) {
+ continue;
+ }
+ poll_obj_t *poll_obj = (poll_obj_t*)self->poll_map.table[i].value;
+ if (poll_obj->flags_ret != 0) {
+ mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)};
+ ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);
+ if (flags & FLAG_ONESHOT) {
+ // Don't poll next time, until new event flags will be set explicitly
+ poll_obj->flags = 0;
+ }
+ }
+ }
+ return ret_list;
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);
+
+STATIC const mp_map_elem_t poll_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR_register), (mp_obj_t)&poll_register_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_unregister), (mp_obj_t)&poll_unregister_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_modify), (mp_obj_t)&poll_modify_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_poll), (mp_obj_t)&poll_poll_obj },
+};
+STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
+
+STATIC const mp_obj_type_t mp_type_poll = {
+ { &mp_type_type },
+ .name = MP_QSTR_poll,
+ .locals_dict = (mp_obj_t)&poll_locals_dict,
+};
+
+/// \function poll()
+STATIC mp_obj_t select_poll(void) {
+ mp_obj_poll_t *poll = m_new_obj(mp_obj_poll_t);
+ poll->base.type = &mp_type_poll;
+ mp_map_init(&poll->poll_map, 0);
+ return poll;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll);
+
+STATIC const mp_map_elem_t mp_module_select_globals_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uselect) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_select_select_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_poll), (mp_obj_t)&mp_select_poll_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_POLLIN), MP_OBJ_NEW_SMALL_INT(MP_STREAM_POLL_RD) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_POLLOUT), MP_OBJ_NEW_SMALL_INT(MP_STREAM_POLL_WR) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_POLLERR), MP_OBJ_NEW_SMALL_INT(MP_STREAM_POLL_ERR) },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_POLLHUP), MP_OBJ_NEW_SMALL_INT(MP_STREAM_POLL_HUP) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table);
+
+const mp_obj_module_t mp_module_uselect = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_select_globals,
+};
+
+#endif // MICROPY_PY_USELECT
diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c
index 5bc69fe261..4169158216 100644
--- a/extmod/modussl_axtls.c
+++ b/extmod/modussl_axtls.c
@@ -142,7 +142,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c
index 5a7a745d82..a7b8a14405 100644
--- a/extmod/modussl_mbedtls.c
+++ b/extmod/modussl_mbedtls.c
@@ -242,7 +242,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c
new file mode 100644
index 0000000000..f73b39103d
--- /dev/null
+++ b/extmod/modutimeq.c
@@ -0,0 +1,212 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "py/nlr.h"
+#include "py/objlist.h"
+#include "py/runtime0.h"
+#include "py/runtime.h"
+#include "py/smallint.h"
+
+#if MICROPY_PY_UTIMEQ
+
+#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD
+
+#define DEBUG 0
+
+// the algorithm here is modelled on CPython's heapq.py
+
+struct qentry {
+ mp_uint_t time;
+ mp_obj_t callback;
+ mp_obj_t args;
+};
+
+typedef struct _mp_obj_utimeq_t {
+ mp_obj_base_t base;
+ mp_uint_t alloc;
+ mp_uint_t len;
+ struct qentry items[];
+} mp_obj_utimeq_t;
+
+
+STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) {
+ return MP_OBJ_TO_PTR(heap_in);
+}
+
+STATIC bool time_less_than(struct qentry *item, struct qentry *parent) {
+ mp_uint_t item_tm = item->time;
+ mp_uint_t parent_tm = parent->time;
+ mp_uint_t res = parent_tm - item_tm;
+ if ((mp_int_t)res < 0) {
+ res += MODULO;
+ }
+ return res && res < (MODULO / 2);
+}
+
+STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+ mp_uint_t alloc = mp_obj_get_int(args[0]);
+ mp_obj_utimeq_t *o = m_new_obj_var(mp_obj_utimeq_t, struct qentry, alloc);
+ o->base.type = type;
+ memset(o->items, 0, sizeof(*o->items) * alloc);
+ o->alloc = alloc;
+ o->len = 0;
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
+ struct qentry item = heap->items[pos];
+ while (pos > start_pos) {
+ mp_uint_t parent_pos = (pos - 1) >> 1;
+ struct qentry *parent = &heap->items[parent_pos];
+ bool lessthan = time_less_than(&item, parent);
+ if (lessthan) {
+ heap->items[pos] = *parent;
+ pos = parent_pos;
+ } else {
+ break;
+ }
+ }
+ heap->items[pos] = item;
+}
+
+STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
+ mp_uint_t start_pos = pos;
+ mp_uint_t end_pos = heap->len;
+ struct qentry item = heap->items[pos];
+ for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
+ // choose right child if it's <= left child
+ if (child_pos + 1 < end_pos) {
+ bool lessthan = time_less_than(&heap->items[child_pos], &heap->items[child_pos + 1]);
+ if (!lessthan) {
+ child_pos += 1;
+ }
+ }
+ // bubble up the smaller child
+ heap->items[pos] = heap->items[child_pos];
+ pos = child_pos;
+ }
+ heap->items[pos] = item;
+ heap_siftdown(heap, start_pos, pos);
+}
+
+STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ mp_obj_t heap_in = args[0];
+ mp_obj_utimeq_t *heap = get_heap(heap_in);
+ if (heap->len == heap->alloc) {
+ mp_raise_msg(&mp_type_IndexError, "queue overflow");
+ }
+ mp_uint_t l = heap->len;
+ heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);
+ heap->items[l].callback = args[2];
+ heap->items[l].args = args[3];
+ heap_siftdown(heap, 0, heap->len);
+ heap->len++;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush);
+
+STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
+ mp_obj_utimeq_t *heap = get_heap(heap_in);
+ if (heap->len == 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
+ }
+ mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
+ if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 3) {
+ mp_raise_TypeError("");
+ }
+
+ struct qentry *item = &heap->items[0];
+ ret->items[0] = MP_OBJ_NEW_SMALL_INT(item->time);
+ ret->items[1] = item->callback;
+ ret->items[2] = item->args;
+ heap->len -= 1;
+ heap->items[0] = heap->items[heap->len];
+ heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer
+ heap->items[heap->len].args = MP_OBJ_NULL;
+ if (heap->len) {
+ heap_siftup(heap, 0);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
+
+#if DEBUG
+STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
+ mp_obj_utimeq_t *heap = get_heap(heap_in);
+ for (int i = 0; i < heap->len; i++) {
+ printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time,
+ MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args));
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_dump_obj, mod_utimeq_dump);
+#endif
+
+STATIC mp_obj_t utimeq_unary_op(mp_uint_t op, mp_obj_t self_in) {
+ mp_obj_utimeq_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->len != 0);
+ case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->len);
+ default: return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&mod_utimeq_heappush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&mod_utimeq_heappop_obj) },
+ #if DEBUG
+ { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_utimeq_dump_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(utimeq_locals_dict, utimeq_locals_dict_table);
+
+STATIC const mp_obj_type_t utimeq_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_utimeq,
+ .make_new = utimeq_make_new,
+ .unary_op = utimeq_unary_op,
+ .locals_dict = (void*)&utimeq_locals_dict,
+};
+
+STATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utimeq) },
+ { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&utimeq_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_utimeq_globals, mp_module_utimeq_globals_table);
+
+const mp_obj_module_t mp_module_utimeq = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_utimeq_globals,
+};
+
+#endif //MICROPY_PY_UTIMEQ
diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c
index c5d4c48120..a91405a93a 100644
--- a/extmod/moduzlib.c
+++ b/extmod/moduzlib.c
@@ -124,7 +124,6 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er
STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
};
diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c
index 6e827fc664..bd88bcf1b1 100644
--- a/extmod/vfs_fat.c
+++ b/extmod/vfs_fat.c
@@ -121,6 +121,12 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_
const char *old_path = mp_obj_str_get_str(path_in);
const char *new_path = mp_obj_str_get_str(path_out);
FRESULT res = f_rename(old_path, new_path);
+ if (res == FR_EXIST) {
+ // if new_path exists then try removing it (but only if it's a file)
+ fat_vfs_remove_internal(path_out, 0); // 0 == file attribute
+ // try to rename again
+ res = f_rename(old_path, new_path);
+ }
if (res == FR_OK) {
return mp_const_none;
} else {
diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c
index 76ac23685a..77848b5a53 100644
--- a/extmod/vfs_fat_file.c
+++ b/extmod/vfs_fat_file.c
@@ -108,15 +108,6 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz
return sz_out;
}
-STATIC mp_obj_t file_obj_flush(mp_obj_t self_in) {
- pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
- FRESULT res = f_sync(&self->fp);
- if (res != FR_OK) {
- mp_raise_OSError(fresult_to_errno_table[res]);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_flush_obj, file_obj_flush);
STATIC mp_obj_t file_obj_close(mp_obj_t self_in) {
pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -164,6 +155,14 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
s->offset = f_tell(&self->fp);
return 0;
+ } else if (request == MP_STREAM_FLUSH) {
+ FRESULT res = f_sync(&self->fp);
+ if (res != FR_OK) {
+ *errcode = fresult_to_errno_table[res];
+ return MP_STREAM_ERROR;
+ }
+ return 0;
+
} else {
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
@@ -239,12 +238,11 @@ STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size
STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&file_obj_flush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
diff --git a/extmod/vfs_fat_lexer.c b/extmod/vfs_fat_lexer.c
deleted file mode 100644
index 91acdb830d..0000000000
--- a/extmod/vfs_fat_lexer.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file is part of the Micro Python project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-// *_ADHOC part is for cc3200 port which doesn't use general uPy
-// infrastructure and instead duplicates code. TODO: Resolve.
-#if MICROPY_VFS_FAT || MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC
-
-#include "py/lexer.h"
-#include "lib/fatfs/ff.h"
-
-typedef struct _mp_lexer_file_buf_t {
- FIL fp;
- byte buf[20];
- uint16_t len;
- uint16_t pos;
-} mp_lexer_file_buf_t;
-
-STATIC mp_uint_t file_buf_next_byte(mp_lexer_file_buf_t *fb) {
- if (fb->pos >= fb->len) {
- if (fb->len < sizeof(fb->buf)) {
- return MP_LEXER_EOF;
- } else {
- UINT n;
- f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
- if (n == 0) {
- return MP_LEXER_EOF;
- }
- fb->len = n;
- fb->pos = 0;
- }
- }
- return fb->buf[fb->pos++];
-}
-
-STATIC void file_buf_close(mp_lexer_file_buf_t *fb) {
- f_close(&fb->fp);
- m_del_obj(mp_lexer_file_buf_t, fb);
-}
-
-mp_lexer_t *fat_vfs_lexer_new_from_file(const char *filename);
-
-mp_lexer_t *fat_vfs_lexer_new_from_file(const char *filename) {
- mp_lexer_file_buf_t *fb = m_new_obj_maybe(mp_lexer_file_buf_t);
- if (fb == NULL) {
- return NULL;
- }
- FRESULT res = f_open(&fb->fp, filename, FA_READ);
- if (res != FR_OK) {
- m_del_obj(mp_lexer_file_buf_t, fb);
- return NULL;
- }
- UINT n;
- f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
- fb->len = n;
- fb->pos = 0;
- return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_byte_t)file_buf_next_byte, (mp_lexer_stream_close_t)file_buf_close);
-}
-
-#endif // MICROPY_VFS_FAT
diff --git a/extmod/vfs_fat_reader.c b/extmod/vfs_fat_reader.c
new file mode 100644
index 0000000000..7a00f18de3
--- /dev/null
+++ b/extmod/vfs_fat_reader.c
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ *
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "py/mperrno.h"
+#include "py/reader.h"
+
+#if MICROPY_READER_FATFS
+
+#include "lib/fatfs/ff.h"
+#include "extmod/vfs_fat_file.h"
+
+typedef struct _mp_reader_fatfs_t {
+ FIL fp;
+ uint16_t len;
+ uint16_t pos;
+ byte buf[20];
+} mp_reader_fatfs_t;
+
+STATIC mp_uint_t mp_reader_fatfs_readbyte(void *data) {
+ mp_reader_fatfs_t *reader = (mp_reader_fatfs_t*)data;
+ if (reader->pos >= reader->len) {
+ if (reader->len < sizeof(reader->buf)) {
+ return MP_READER_EOF;
+ } else {
+ UINT n;
+ f_read(&reader->fp, reader->buf, sizeof(reader->buf), &n);
+ if (n == 0) {
+ return MP_READER_EOF;
+ }
+ reader->len = n;
+ reader->pos = 0;
+ }
+ }
+ return reader->buf[reader->pos++];
+}
+
+STATIC void mp_reader_fatfs_close(void *data) {
+ mp_reader_fatfs_t *reader = (mp_reader_fatfs_t*)data;
+ f_close(&reader->fp);
+ m_del_obj(mp_reader_fatfs_t, reader);
+}
+
+int mp_reader_new_file(mp_reader_t *reader, const char *filename) {
+ mp_reader_fatfs_t *rf = m_new_obj_maybe(mp_reader_fatfs_t);
+ if (rf == NULL) {
+ return MP_ENOMEM;
+ }
+ FRESULT res = f_open(&rf->fp, filename, FA_READ);
+ if (res != FR_OK) {
+ return fresult_to_errno_table[res];
+ }
+ UINT n;
+ f_read(&rf->fp, rf->buf, sizeof(rf->buf), &n);
+ rf->len = n;
+ rf->pos = 0;
+ reader->data = rf;
+ reader->readbyte = mp_reader_fatfs_readbyte;
+ reader->close = mp_reader_fatfs_close;
+ return 0; // success
+}
+
+#endif