diff options
Diffstat (limited to 'extmod')
-rw-r--r-- | extmod/fsusermount.c | 3 | ||||
-rw-r--r-- | extmod/machine_i2c.c | 150 | ||||
-rw-r--r-- | extmod/machine_pulse.c | 2 | ||||
-rw-r--r-- | extmod/machine_spi.c | 86 | ||||
-rw-r--r-- | extmod/machine_spi.h | 15 | ||||
-rw-r--r-- | extmod/modbtree.c | 5 | ||||
-rw-r--r-- | extmod/modframebuf.c | 1 | ||||
-rw-r--r-- | extmod/modlwip.c | 49 | ||||
-rw-r--r-- | extmod/modubinascii.c | 5 | ||||
-rw-r--r-- | extmod/moductypes.c | 3 | ||||
-rw-r--r-- | extmod/moduhashlib.c | 1 | ||||
-rw-r--r-- | extmod/moduheapq.c | 1 | ||||
-rw-r--r-- | extmod/modujson.c | 108 | ||||
-rw-r--r-- | extmod/modurandom.c | 1 | ||||
-rw-r--r-- | extmod/modure.c | 1 | ||||
-rw-r--r-- | extmod/modussl_axtls.c | 5 | ||||
-rw-r--r-- | extmod/modussl_mbedtls.c | 303 | ||||
-rw-r--r-- | extmod/moduzlib.c | 16 | ||||
-rw-r--r-- | extmod/modwebrepl.c | 3 | ||||
-rw-r--r-- | extmod/modwebsocket.c | 1 | ||||
-rw-r--r-- | extmod/utime_mphal.c | 89 | ||||
-rw-r--r-- | extmod/utime_mphal.h | 36 | ||||
-rw-r--r-- | extmod/uzlib/tinf.h | 1 | ||||
-rw-r--r-- | extmod/uzlib/tinfgzip.c | 110 | ||||
-rw-r--r-- | extmod/uzlib/tinflate.c | 3 | ||||
-rw-r--r-- | extmod/vfs_fat.c | 84 | ||||
-rw-r--r-- | extmod/vfs_fat_file.c | 47 | ||||
-rw-r--r-- | extmod/vfs_fat_misc.c | 4 |
28 files changed, 904 insertions, 229 deletions
diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index cbc1e36220..5882aba991 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -31,6 +31,7 @@ #include "py/nlr.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "lib/fatfs/ff.h" #include "extmod/fsusermount.h" @@ -183,7 +184,7 @@ mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { } if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + mp_raise_OSError(MP_EINVAL); } fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index ceddf0730e..e201b23990 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -34,6 +34,9 @@ #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; @@ -53,6 +56,11 @@ STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) { STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { 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) { + mp_hal_delay_us_fast(1); + } } STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) { @@ -71,7 +79,6 @@ STATIC void 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); - mp_hal_i2c_delay(self); mp_hal_i2c_sda_low(self); mp_hal_i2c_delay(self); } @@ -81,7 +88,6 @@ STATIC void mp_hal_i2c_stop(machine_i2c_obj_t *self) { mp_hal_i2c_sda_low(self); mp_hal_i2c_delay(self); mp_hal_i2c_scl_release(self); - mp_hal_i2c_delay(self); mp_hal_i2c_sda_release(self); mp_hal_i2c_delay(self); } @@ -108,14 +114,12 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) { } mp_hal_i2c_delay(self); mp_hal_i2c_scl_release(self); - mp_hal_i2c_delay(self); mp_hal_i2c_scl_low(self); } mp_hal_i2c_sda_release(self); mp_hal_i2c_delay(self); mp_hal_i2c_scl_release(self); - mp_hal_i2c_delay(self); int ret = mp_hal_i2c_sda_read(self); mp_hal_i2c_delay(self); @@ -124,24 +128,6 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) { return !ret; } -STATIC void mp_hal_i2c_write(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) { - mp_hal_i2c_start(self); - if (!mp_hal_i2c_write_byte(self, addr << 1)) { - goto er; - } - while (len--) { - if (!mp_hal_i2c_write_byte(self, *data++)) { - goto er; - } - } - 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 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); @@ -150,7 +136,6 @@ 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); - mp_hal_i2c_delay(self); data = (data << 1) | mp_hal_i2c_sda_read(self); mp_hal_i2c_scl_low(self); mp_hal_i2c_delay(self); @@ -163,40 +148,33 @@ 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_release(self); - mp_hal_i2c_delay(self); mp_hal_i2c_scl_low(self); mp_hal_i2c_sda_release(self); return 1; // success } -STATIC void mp_hal_i2c_read(machine_i2c_obj_t *self, uint8_t addr, uint8_t *data, size_t len) { - mp_hal_i2c_start(self); - if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) { - goto er; +// 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 } - while (len--) { - if (!mp_hal_i2c_read_byte(self, data++, len == 0)) { - goto er; + for (int16_t i = addrsize - 8; i >= 0; i -= 8) { + if (!mp_hal_i2c_write_byte(self, memaddr >> i)) { + return 0; // error } } - 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")); + return 1; // success } -STATIC void mp_hal_i2c_write_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, const uint8_t *src, size_t len) { +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); // write the slave address and the memory address within the slave - if (!mp_hal_i2c_write_byte(self, addr << 1)) { - goto er; - } - if (!mp_hal_i2c_write_byte(self, memaddr)) { + if (!mp_hal_i2c_write_addresses(self, addr, memaddr, addrsize)) { goto er; } @@ -216,20 +194,30 @@ er: nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error")); } -STATIC void mp_hal_i2c_read_mem(machine_i2c_obj_t *self, uint8_t addr, uint16_t memaddr, uint8_t *dest, size_t len) { +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); - // write the slave address and the memory address within the slave - if (!mp_hal_i2c_write_byte(self, addr << 1)) { - goto er; + 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; + } + + // i2c_read will do a repeated start, and then read the I2C memory + mp_hal_i2c_start(self); } - if (!mp_hal_i2c_write_byte(self, memaddr)) { + + if (!mp_hal_i2c_write_byte(self, (addr << 1) | 1)) { goto er; } - - // i2c_read will do a repeated start, and then read the I2C memory - mp_hal_i2c_read(self, addr, dest, len); + while (len--) { + if (!mp_hal_i2c_read_byte(self, dest++, len == 0)) { + goto er; + } + } + mp_hal_i2c_stop(self); return; er: @@ -237,6 +225,14 @@ er: 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); +} + +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); +} + /******************************************************************************/ // MicroPython bindings for I2C @@ -276,7 +272,7 @@ STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { // 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) | 1); + int ack = mp_hal_i2c_write_byte(self, (addr << 1)); if (ack) { mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); } @@ -365,68 +361,64 @@ STATIC mp_obj_t machine_i2c_writeto(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t } 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} }, + { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_arg, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, +}; + 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 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_n, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - //{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO - }; machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + 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); // create the buffer to store data into vstr_t vstr; - vstr_init_len(&vstr, args[ARG_n].u_int); + 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, (uint8_t*)vstr.buf, vstr.len); + mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, (uint8_t*)vstr.buf, vstr.len); 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); + 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 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - //{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO - }; machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + 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); // get the buffer to store data into mp_buffer_info_t bufinfo; 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, bufinfo.buf, bufinfo.len); + mp_hal_i2c_read_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); 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 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_memaddr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - //{ MP_QSTR_addrsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, TODO - }; machine_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + 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); // get the buffer to write the data from mp_buffer_info_t bufinfo; 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, bufinfo.buf, bufinfo.len); + mp_hal_i2c_write_mem(self, args[ARG_addr].u_int, args[ARG_memaddr].u_int, + args[ARG_addrsize].u_int, bufinfo.buf, bufinfo.len); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem); diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c index 8c8bff510c..b2a78d72ee 100644 --- a/extmod/machine_pulse.c +++ b/extmod/machine_pulse.c @@ -58,7 +58,7 @@ STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { } mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); if (us == (mp_uint_t)-1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); + mp_raise_OSError(MP_ETIMEDOUT); } return mp_obj_new_int(us); } diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index 6b6202a221..e3d72ab588 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -25,26 +25,85 @@ */ #include <stdio.h> +#include <string.h> #include "py/runtime.h" #include "extmod/machine_spi.h" #if MICROPY_PY_MACHINE_SPI -STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest) { +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; + + // only MSB transfer is implemented + + // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY + if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + mp_hal_pin_write(self->sck, 1 - self->polarity); + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + mp_hal_pin_write(self->sck, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + return; + } + #endif + + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, 1 - self->polarity); + } else { + mp_hal_pin_write(self->sck, 1 - self->polarity); + mp_hal_delay_us_fast(delay_half); + } + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, self->polarity); + } else { + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_delay_us_fast(delay_half); + } + } + if (dest != NULL) { + dest[i] = data_in; + } + + // Some ports need a regular callback, but probably we don't need + // to do this every byte, or even at all. + #ifdef MICROPY_EVENT_POLL_HOOK + MICROPY_EVENT_POLL_HOOK; + #endif + } +} + +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; - spi_p->transfer(s, slen, src, dlen, dest); + spi_p->transfer(s, len, src, dest); } STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } vstr_t vstr; vstr_init_len(&vstr, mp_obj_get_int(args[1])); - mp_machine_spi_transfer(args[0], 1, &write_byte, vstr.len, (uint8_t*)vstr.buf); + memset(vstr.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, vstr.len); + mp_machine_spi_transfer(args[0], vstr.len, vstr.buf, vstr.buf); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); @@ -52,11 +111,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_sp STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - mp_machine_spi_transfer(args[0], 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf); + memset(bufinfo.buf, n_args == 3 ? mp_obj_get_int(args[2]) : 0, bufinfo.len); + mp_machine_spi_transfer(args[0], bufinfo.len, bufinfo.buf, bufinfo.buf); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); @@ -64,7 +120,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machin STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { mp_buffer_info_t src; mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); - mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, 0, NULL); + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, NULL); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); @@ -75,9 +131,9 @@ STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp mp_buffer_info_t dest; mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); if (src.len != dest.len) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length")); + mp_raise_ValueError("buffers must be the same length"); } - mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, dest.len, (uint8_t*)dest.buf); + mp_machine_spi_transfer(self, src.len, src.buf, dest.buf); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index 26d716fc11..316d06646e 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -28,12 +28,25 @@ #define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H #include "py/obj.h" +#include "py/mphal.h" // SPI protocol typedef struct _mp_machine_spi_p_t { - void (*transfer)(mp_obj_base_t *obj, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest); + void (*transfer)(mp_obj_base_t *obj, size_t len, const uint8_t *src, uint8_t *dest); } mp_machine_spi_p_t; +typedef struct _mp_machine_soft_spi_obj_t { + mp_obj_base_t base; + uint32_t delay_half; // microsecond delay for half SCK period + uint8_t polarity; + uint8_t phase; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t mosi; + mp_hal_pin_obj_t miso; +} mp_machine_soft_spi_obj_t; + +void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest); + MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_read_obj); MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_readinto_obj); MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_obj); diff --git a/extmod/modbtree.c b/extmod/modbtree.c index ea2ea582c8..f5ec5bfca1 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -58,7 +58,7 @@ STATIC const mp_obj_type_t btree_type; #define CHECK_ERROR(res) \ if (res == RET_ERROR) { \ - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno))); \ + mp_raise_OSError(errno); \ } void __dbpanic(DB *db) { @@ -370,7 +370,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t DB *db = __bt_open(pos_args[0], &btree_stream_fvtable, &openinfo, /*dflags*/0); if (db == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno))); + mp_raise_OSError(errno); } return MP_OBJ_FROM_PTR(btree_new(db)); } @@ -387,7 +387,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_btree_globals, mp_module_btree_globals_tab const mp_obj_module_t mp_module_btree = { .base = { &mp_type_module }, - .name = MP_QSTR_btree, .globals = (mp_obj_dict_t*)&mp_module_btree_globals, }; diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 3c884c6898..cd7f1c5e4b 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -213,7 +213,6 @@ STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_tab const mp_obj_module_t mp_module_framebuf = { .base = { &mp_type_module }, - .name = MP_QSTR_framebuf, .globals = (mp_obj_dict_t*)&framebuf_module_globals, }; diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 80df662647..11ba6e4231 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -598,11 +598,11 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break; case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break; //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; - default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); + default: mp_raise_OSError(MP_EINVAL); } if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); + mp_raise_OSError(MP_ENOMEM); } switch (socket->type) { @@ -686,7 +686,7 @@ STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { } if (err != ERR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err]))); + mp_raise_OSError(error_lookup_table[-err]); } return mp_const_none; @@ -698,15 +698,15 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_int_t backlog = mp_obj_get_int(backlog_in); if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); + mp_raise_OSError(MP_EBADF); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); + mp_raise_OSError(MP_EOPNOTSUPP); } struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog); if (new_pcb == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); + mp_raise_OSError(MP_ENOMEM); } socket->pcb.tcp = new_pcb; tcp_accept(new_pcb, _lwip_tcp_accept); @@ -719,15 +719,15 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); + mp_raise_OSError(MP_EBADF); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); + mp_raise_OSError(MP_EOPNOTSUPP); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); + mp_raise_OSError(MP_EINVAL); } // accept incoming connection @@ -738,7 +738,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); + mp_raise_OSError(MP_ETIMEDOUT); } } else { while (socket->incoming.connection == NULL) { @@ -785,7 +785,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); + mp_raise_OSError(MP_EBADF); } // get address @@ -800,9 +800,9 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { case MOD_NETWORK_SOCK_STREAM: { if (socket->state != STATE_NEW) { if (socket->state == STATE_CONNECTED) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EALREADY))); + mp_raise_OSError(MP_EALREADY); } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINPROGRESS))); + mp_raise_OSError(MP_EINPROGRESS); } } // Register our recieve callback. @@ -811,7 +811,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected); if (err != ERR_OK) { socket->state = STATE_NEW; - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err]))); + mp_raise_OSError(error_lookup_table[-err]); } socket->peer_port = (mp_uint_t)port; memcpy(socket->peer, &dest, sizeof(socket->peer)); @@ -822,7 +822,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { if (socket->state != STATE_CONNECTING) break; } if (socket->state == STATE_CONNECTING) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); + mp_raise_OSError(MP_ETIMEDOUT); } } else { while (socket->state == STATE_CONNECTING) { @@ -843,7 +843,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { } if (err != ERR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err]))); + mp_raise_OSError(error_lookup_table[-err]); } return mp_const_none; @@ -855,7 +855,7 @@ STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) { // not connected int _errno = error_lookup_table[-socket->state]; socket->state = _ERR_BADF; - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } } @@ -880,7 +880,7 @@ STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { } } if (ret == -1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } return mp_obj_new_int_from_uint(ret); @@ -909,7 +909,7 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { } } if (ret == -1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } if (ret == 0) { @@ -944,7 +944,7 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t } } if (ret == -1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } return mp_obj_new_int_from_uint(ret); @@ -977,7 +977,7 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { } } if (ret == -1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } mp_obj_t tuple[2]; @@ -1010,7 +1010,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { // most useful behavior is: check whether we will be able to send all of input // data without EAGAIN, and if won't be, raise it without sending any. if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EAGAIN))); + mp_raise_OSError(MP_EAGAIN); } } // TODO: In CPython3.5, socket timeout should apply to the @@ -1018,7 +1018,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { while (bufinfo.len != 0) { ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno); if (ret == -1) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); } bufinfo.len -= ret; bufinfo.buf = (char*)bufinfo.buf + ret; @@ -1259,7 +1259,7 @@ STATIC mp_obj_t lwip_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { if (state.status < 0) { // TODO: CPython raises gaierror, we raise with native lwIP negative error // values, to differentiate from normal errno's at least in such way. - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(state.status))); + mp_raise_OSError(state.status); } mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); @@ -1309,7 +1309,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table const mp_obj_module_t mp_module_lwip = { .base = { &mp_type_module }, - .name = MP_QSTR_lwip, .globals = (mp_obj_dict_t*)&mp_module_lwip_globals, }; diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 562c754b52..2ef1a6f21d 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -208,9 +208,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); - uint32_t crc = (n_args > 1) ? mp_obj_get_int(args[1]) : 0; + uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0; crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); - return MP_OBJ_NEW_SMALL_INT(crc ^ 0xffffffff); + return mp_obj_new_int_from_uint(crc ^ 0xffffffff); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); #endif @@ -232,7 +232,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globa const mp_obj_module_t mp_module_ubinascii = { .base = { &mp_type_module }, - .name = MP_QSTR_ubinascii, .globals = (mp_obj_dict_t*)&mp_module_binascii_globals, }; diff --git a/extmod/moductypes.c b/extmod/moductypes.c index a3071af987..6249a49406 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -125,7 +125,7 @@ STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args mp_arg_check_num(n_args, n_kw, 2, 3, false); mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); o->base.type = type; - o->addr = (void*)(uintptr_t)mp_obj_get_int(args[0]); + o->addr = (void*)(uintptr_t)mp_obj_int_get_truncated(args[0]); o->desc = args[1]; o->flags = LAYOUT_NATIVE; if (n_args == 3) { @@ -710,7 +710,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals const mp_obj_module_t mp_module_uctypes = { .base = { &mp_type_module }, - .name = MP_QSTR_uctypes, .globals = (mp_obj_dict_t*)&mp_module_uctypes_globals, }; diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 6cd690a676..13525cc3fa 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -151,7 +151,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals const mp_obj_module_t mp_module_uhashlib = { .base = { &mp_type_module }, - .name = MP_QSTR_uhashlib, .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals, }; diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c index 84ffe54f98..567ee83da6 100644 --- a/extmod/moduheapq.c +++ b/extmod/moduheapq.c @@ -116,7 +116,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uheapq_globals, mp_module_uheapq_globals_t const mp_obj_module_t mp_module_uheapq = { .base = { &mp_type_module }, - .name = MP_QSTR_uheapq, .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals, }; diff --git a/extmod/modujson.c b/extmod/modujson.c index 4e080c9756..ca4e6df104 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -1,9 +1,9 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-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 @@ -28,8 +28,10 @@ #include "py/nlr.h" #include "py/objlist.h" +#include "py/objstringio.h" #include "py/parsenum.h" #include "py/runtime.h" +#include "py/stream.h" #if MICROPY_PY_UJSON @@ -42,7 +44,7 @@ STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); -// This function implements a simple non-recursive JSON parser. +// The function below implements a simple non-recursive JSON parser. // // The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt // The parser here will parse any valid JSON and return the correct @@ -52,13 +54,35 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); // input is outside it's specs. // // Most of the work is parsing the primitives (null, false, true, numbers, -// strings). It does 1 pass over the input string and so is easily extended to -// being able to parse from a non-seekable stream. It tries to be fast and +// strings). It does 1 pass over the input stream. It tries to be fast and // small in code size, while not using more RAM than necessary. -STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { - mp_uint_t len; - const char *s = mp_obj_str_get_data(obj, &len); - const char *top = s + len; + +typedef struct _ujson_stream_t { + mp_obj_t stream_obj; + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + int errcode; + byte cur; +} ujson_stream_t; + +#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker +#define S_END(s) ((s).cur == S_EOF) +#define S_CUR(s) ((s).cur) +#define S_NEXT(s) (ujson_stream_next(&(s))) + +STATIC byte ujson_stream_next(ujson_stream_t *s) { + mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode); + if (s->errcode != 0) { + mp_raise_OSError(s->errcode); + } + if (ret == 0) { + s->cur = S_EOF; + } + return s->cur; +} + +STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ); + ujson_stream_t s = {stream_obj, stream_p->read, 0, 0}; vstr_t vstr; vstr_init(&vstr, 8); mp_obj_list_t stack; // we use a list as a simple stack for nested JSON @@ -67,41 +91,43 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { mp_obj_t stack_top = MP_OBJ_NULL; mp_obj_type_t *stack_top_type = NULL; mp_obj_t stack_key = MP_OBJ_NULL; + S_NEXT(s); for (;;) { cont: - if (s == top) { + if (S_END(s)) { break; } mp_obj_t next = MP_OBJ_NULL; bool enter = false; - switch (*s) { + byte cur = S_CUR(s); + S_NEXT(s); + switch (cur) { case ',': case ':': case ' ': case '\t': case '\n': case '\r': - s += 1; goto cont; case 'n': - if (s + 3 < top && s[1] == 'u' && s[2] == 'l' && s[3] == 'l') { - s += 4; + if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') { + S_NEXT(s); next = mp_const_none; } else { goto fail; } break; case 'f': - if (s + 4 < top && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e') { - s += 5; + if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') { + S_NEXT(s); next = mp_const_false; } else { goto fail; } break; case 't': - if (s + 3 < top && s[1] == 'r' && s[2] == 'u' && s[3] == 'e') { - s += 4; + if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') { + S_NEXT(s); next = mp_const_true; } else { goto fail; @@ -109,11 +135,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { break; case '"': vstr_reset(&vstr); - for (s++; s < top && *s != '"';) { - byte c = *s; + for (; !S_END(s) && S_CUR(s) != '"';) { + byte c = S_CUR(s); if (c == '\\') { - s++; - c = *s; + c = S_NEXT(s); switch (c) { case 'b': c = 0x08; break; case 'f': c = 0x0c; break; @@ -121,10 +146,9 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { case 'r': c = 0x0d; break; case 't': c = 0x09; break; case 'u': { - if (s + 4 >= top) { goto fail; } mp_uint_t num = 0; for (int i = 0; i < 4; i++) { - c = (*++s | 0x20) - '0'; + c = (S_NEXT(s) | 0x20) - '0'; if (c > 9) { c -= ('a' - ('9' + 1)); } @@ -137,27 +161,29 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { } vstr_add_byte(&vstr, c); str_cont: - s++; + S_NEXT(s); } - if (s == top) { + if (S_END(s)) { goto fail; } - s++; + S_NEXT(s); next = mp_obj_new_str(vstr.buf, vstr.len, false); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { bool flt = false; vstr_reset(&vstr); - for (; s < top; s++) { - if (*s == '.' || *s == 'E' || *s == 'e') { + for (;;) { + vstr_add_byte(&vstr, cur); + cur = S_CUR(s); + if (cur == '.' || cur == 'E' || cur == 'e') { flt = true; - } else if (*s == '-' || unichar_isdigit(*s)) { + } else if (cur == '-' || unichar_isdigit(cur)) { // pass } else { break; } - vstr_add_byte(&vstr, *s); + S_NEXT(s); } if (flt) { next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL); @@ -169,16 +195,13 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { case '[': next = mp_obj_new_list(0, NULL); enter = true; - s += 1; break; case '{': next = mp_obj_new_dict(0); enter = true; - s += 1; break; case '}': case ']': { - s += 1; if (stack_top == MP_OBJ_NULL) { // no object at all goto fail; @@ -231,10 +254,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { } success: // eat trailing whitespace - while (s < top && unichar_isspace(*s)) { - s++; + while (unichar_isspace(S_CUR(s))) { + S_NEXT(s); } - if (s < top) { + if (!S_END(s)) { // unexpected chars goto fail; } @@ -248,11 +271,21 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { fail: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "syntax error in JSON")); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); + +STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { + mp_uint_t len; + const char *buf = mp_obj_str_get_data(obj, &len); + vstr_t vstr = {len, len, (char*)buf, true}; + mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0}; + return mod_ujson_load(MP_OBJ_FROM_PTR(&sio)); +} STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, + { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, }; @@ -260,7 +293,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_ujson_globals, mp_module_ujson_globals_tab const mp_obj_module_t mp_module_ujson = { .base = { &mp_type_module }, - .name = MP_QSTR_ujson, .globals = (mp_obj_dict_t*)&mp_module_ujson_globals, }; diff --git a/extmod/modurandom.c b/extmod/modurandom.c index 27d7177207..995b0a2665 100644 --- a/extmod/modurandom.c +++ b/extmod/modurandom.c @@ -215,7 +215,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals const mp_obj_module_t mp_module_urandom = { .base = { &mp_type_module }, - .name = MP_QSTR_urandom, .globals = (mp_obj_dict_t*)&mp_module_urandom_globals, }; diff --git a/extmod/modure.c b/extmod/modure.c index 9821e235a6..b8c242429b 100644 --- a/extmod/modure.c +++ b/extmod/modure.c @@ -237,7 +237,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table); const mp_obj_module_t mp_module_ure = { .base = { &mp_type_module }, - .name = MP_QSTR_ure, .globals = (mp_obj_dict_t*)&mp_module_re_globals, }; diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c index ce86263c2c..5bc69fe261 100644 --- a/extmod/modussl_axtls.c +++ b/extmod/modussl_axtls.c @@ -56,7 +56,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) { uint32_t options = SSL_SERVER_VERIFY_LATER; if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + mp_raise_OSError(MP_EINVAL); } if (server_side) { @@ -69,7 +69,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) { if ((res = ssl_handshake_status(o->ssl_sock)) != SSL_OK) { printf("ssl_handshake_status: %d\n", res); ssl_display_error(res); - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EIO))); + mp_raise_OSError(MP_EIO); } } @@ -196,7 +196,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); const mp_obj_module_t mp_module_ussl = { .base = { &mp_type_module }, - .name = MP_QSTR_ussl, .globals = (mp_obj_dict_t*)&mp_module_ssl_globals, }; diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c new file mode 100644 index 0000000000..5a7a745d82 --- /dev/null +++ b/extmod/modussl_mbedtls.c @@ -0,0 +1,303 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Ltd. + * + * 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_USSL && MICROPY_SSL_MBEDTLS + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/stream.h" + +// mbedtls_time_t +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/ssl.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/pk.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/debug.h" + +typedef struct _mp_obj_ssl_socket_t { + mp_obj_base_t base; + mp_obj_t sock; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_ssl_context ssl; + mbedtls_ssl_config conf; + mbedtls_x509_crt cacert; + mbedtls_x509_crt cert; + mbedtls_pk_context pkey; +} mp_obj_ssl_socket_t; + +struct ssl_args { + mp_arg_val_t key; + mp_arg_val_t cert; + mp_arg_val_t server_side; + mp_arg_val_t server_hostname; +}; + +STATIC const mp_obj_type_t ussl_socket_type; + +static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { + printf("DBG:%s:%04d: %s\n", file, line, str); +} + +// TODO: FIXME! +int null_entropy_func(void *data, unsigned char *output, size_t len) { + // enjoy random bytes + return 0; +} + +int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t*)ctx; + + const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE); + int err; + + int out_sz = sock_stream->write(sock, buf, len, &err); + if (out_sz == MP_STREAM_ERROR) { + return -err; + } else { + return out_sz; + } +} + +int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { + mp_obj_t sock = *(mp_obj_t*)ctx; + + const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ); + int err; + + int out_sz = sock_stream->read(sock, buf, len, &err); + if (out_sz == MP_STREAM_ERROR) { + return -err; + } else { + return out_sz; + } +} + + +STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { + mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); + o->base.type = &ussl_socket_type; + + int ret; + mbedtls_ssl_init(&o->ssl); + mbedtls_ssl_config_init(&o->conf); + mbedtls_x509_crt_init(&o->cacert); + mbedtls_x509_crt_init(&o->cert); + mbedtls_pk_init(&o->pkey); + mbedtls_ctr_drbg_init(&o->ctr_drbg); + // Debug level (0-4) + mbedtls_debug_set_threshold(0); + + mbedtls_entropy_init(&o->entropy); + const byte seed[] = "upy"; + ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed)); + if (ret != 0) { + printf("ret=%d\n", ret); + assert(0); + } + + ret = mbedtls_ssl_config_defaults(&o->conf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + if (ret != 0) { + assert(0); + } + + mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); + mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); + + ret = mbedtls_ssl_setup(&o->ssl, &o->conf); + if (ret != 0) { + assert(0); + } + + if (args->server_hostname.u_obj != mp_const_none) { + const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); + ret = mbedtls_ssl_set_hostname(&o->ssl, sni); + if (ret != 0) { + assert(0); + } + } + + o->sock = sock; + mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); + + if (args->key.u_obj != MP_OBJ_NULL) { + mp_uint_t key_len; + const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); + // len should include terminating null + ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); + assert(ret == 0); + + mp_uint_t cert_len; + const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); + // len should include terminating null + ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); + assert(ret == 0); + + ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); + assert(ret == 0); + } + + if (args->server_side.u_bool) { + assert(0); + } else { + while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + //assert(0); + printf("mbedtls_ssl_handshake error: -%x\n", -ret); + mp_raise_OSError(MP_EIO); + } + } + } + + return o; +} + +STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "<_SSLSocket %p>", self); +} + +STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + int ret = mbedtls_ssl_read(&o->ssl, buf, size); + if (ret >= 0) { + return ret; + } + *errcode = ret; + return MP_STREAM_ERROR; +} + +STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); + + int ret = mbedtls_ssl_write(&o->ssl, buf, size); + if (ret >= 0) { + return ret; + } + *errcode = ret; + return MP_STREAM_ERROR; +} + +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + // Currently supports only blocking mode + (void)self_in; + if (!mp_obj_is_true(flag_in)) { + mp_not_implemented(""); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC mp_obj_t socket_close(mp_obj_t self_in) { + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); + + mbedtls_x509_crt_free(&self->cacert); + mbedtls_ssl_free(&self->ssl); + mbedtls_ssl_config_free(&self->conf); + mbedtls_ctr_drbg_free(&self->ctr_drbg); + mbedtls_entropy_free(&self->entropy); + + mp_obj_t dest[2]; + mp_load_method(self->sock, MP_QSTR_close, dest); + return mp_call_method_n_kw(0, 0, dest); +} +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) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); + +STATIC const mp_stream_p_t ussl_socket_stream_p = { + .read = socket_read, + .write = socket_write, +}; + +STATIC const mp_obj_type_t ussl_socket_type = { + { &mp_type_type }, + // Save on qstr's, reuse same as for module + .name = MP_QSTR_ussl, + .print = socket_print, + .getiter = NULL, + .iternext = NULL, + .protocol = &ussl_socket_stream_p, + .locals_dict = (void*)&ussl_socket_locals_dict, +}; + +STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // TODO: Implement more args + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // TODO: Check that sock implements stream protocol + mp_obj_t sock = pos_args[0]; + + struct ssl_args args; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); + + return MP_OBJ_FROM_PTR(socket_new(sock, &args)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); + +STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); + +const mp_obj_module_t mp_module_ussl = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ssl_globals, +}; + +#endif // MICROPY_PY_USSL diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 65cbc5eb01..c5d4c48120 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -59,7 +59,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { byte c; mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); if (out_sz == MP_STREAM_ERROR) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); + mp_raise_OSError(err); } if (out_sz == 0) { nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); @@ -81,10 +81,18 @@ STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size if (n_args > 1) { dict_opt = mp_obj_get_int(args[1]); } - if (dict_opt >= 0) { + + if (dict_opt >= 16) { + int st = uzlib_gzip_parse_header(&o->decomp); + if (st != TINF_OK) { + goto header_error; + } + dict_sz = 1 << (dict_opt - 16); + } else if (dict_opt >= 0) { dict_opt = uzlib_zlib_parse_header(&o->decomp); if (dict_opt < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "zlib header")); +header_error: + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "compression header")); } dict_sz = 1 << dict_opt; } else { @@ -204,7 +212,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_tab const mp_obj_module_t mp_module_uzlib = { .base = { &mp_type_module }, - .name = MP_QSTR_uzlib, .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals, }; @@ -213,6 +220,7 @@ const mp_obj_module_t mp_module_uzlib = { #include "uzlib/tinflate.c" #include "uzlib/tinfzlib.c" +#include "uzlib/tinfgzip.c" #include "uzlib/adler32.c" #include "uzlib/crc32.c" diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 858d2c1c0b..8e05809662 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -340,7 +340,7 @@ STATIC const mp_obj_type_t webrepl_type = { }; STATIC const mp_map_elem_t webrepl_module_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_websocket) }, + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR__webrepl) }, { MP_OBJ_NEW_QSTR(MP_QSTR__webrepl), (mp_obj_t)&webrepl_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_password), (mp_obj_t)&webrepl_set_password_obj }, }; @@ -349,7 +349,6 @@ STATIC MP_DEFINE_CONST_DICT(webrepl_module_globals, webrepl_module_globals_table const mp_obj_module_t mp_module_webrepl = { .base = { &mp_type_module }, - .name = MP_QSTR__webrepl, .globals = (mp_obj_dict_t*)&webrepl_module_globals, }; diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index f46dac1773..8200ea708a 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -313,7 +313,6 @@ STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_t const mp_obj_module_t mp_module_websocket = { .base = { &mp_type_module }, - .name = MP_QSTR_websocket, .globals = (mp_obj_dict_t*)&websocket_module_globals, }; diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c new file mode 100644 index 0000000000..3ecdc94469 --- /dev/null +++ b/extmod/utime_mphal.c @@ -0,0 +1,89 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 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 "py/mpconfig.h" +#if MICROPY_PY_UTIME_MP_HAL + +#include <string.h> + +#include "py/obj.h" +#include "py/mphal.h" +#include "py/smallint.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + #if MICROPY_PY_BUILTINS_FLOAT + mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o)); + #else + mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); + #endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); + +STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { + mp_int_t ms = mp_obj_get_int(arg); + if (ms > 0) { + mp_hal_delay_ms(ms); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms); + +STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { + mp_int_t us = mp_obj_get_int(arg); + if (us > 0) { + mp_hal_delay_us(us); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); + +STATIC mp_obj_t time_ticks_ms(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); + +STATIC mp_obj_t time_ticks_us(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); + +STATIC mp_obj_t time_ticks_cpu(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); + +STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { + // we assume that the arguments come from ticks_xx so are small ints + uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); + +#endif // MICROPY_PY_UTIME_MP_HAL diff --git a/extmod/utime_mphal.h b/extmod/utime_mphal.h new file mode 100644 index 0000000000..4f2395a090 --- /dev/null +++ b/extmod/utime_mphal.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 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 "py/obj.h" + +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_us_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_ms_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_us_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_cpu_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_diff_obj); diff --git a/extmod/uzlib/tinf.h b/extmod/uzlib/tinf.h index 3545bbd883..106203a099 100644 --- a/extmod/uzlib/tinf.h +++ b/extmod/uzlib/tinf.h @@ -32,6 +32,7 @@ extern "C" { #define TINF_DONE 1 #define TINF_DATA_ERROR (-3) #define TINF_CHKSUM_ERROR (-4) +#define TINF_DICT_ERROR (-5) /* checksum types */ #define TINF_CHKSUM_NONE 0 diff --git a/extmod/uzlib/tinfgzip.c b/extmod/uzlib/tinfgzip.c new file mode 100644 index 0000000000..f1afdd0b8d --- /dev/null +++ b/extmod/uzlib/tinfgzip.c @@ -0,0 +1,110 @@ +/* + * tinfgzip - tiny gzip decompressor + * + * Copyright (c) 2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * Copyright (c) 2014-2016 by Paul Sokolovsky + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +#include "tinf.h" + +#define FTEXT 1 +#define FHCRC 2 +#define FEXTRA 4 +#define FNAME 8 +#define FCOMMENT 16 + +void tinf_skip_bytes(TINF_DATA *d, int num); +uint16_t tinf_get_uint16(TINF_DATA *d); + +void tinf_skip_bytes(TINF_DATA *d, int num) +{ + while (num--) uzlib_get_byte(d); +} + +uint16_t tinf_get_uint16(TINF_DATA *d) +{ + unsigned int v = uzlib_get_byte(d); + v = (uzlib_get_byte(d) << 8) | v; + return v; +} + +int uzlib_gzip_parse_header(TINF_DATA *d) +{ + unsigned char flg; + + /* -- check format -- */ + + /* check id bytes */ + if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR; + + /* check method is deflate */ + if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR; + + /* get flag byte */ + flg = uzlib_get_byte(d); + + /* check that reserved bits are zero */ + if (flg & 0xe0) return TINF_DATA_ERROR; + + /* -- find start of compressed data -- */ + + /* skip rest of base header of 10 bytes */ + tinf_skip_bytes(d, 6); + + /* skip extra data if present */ + if (flg & FEXTRA) + { + unsigned int xlen = tinf_get_uint16(d); + tinf_skip_bytes(d, xlen); + } + + /* skip file name if present */ + if (flg & FNAME) { while (uzlib_get_byte(d)); } + + /* skip file comment if present */ + if (flg & FCOMMENT) { while (uzlib_get_byte(d)); } + + /* check header crc if present */ + if (flg & FHCRC) + { + /*unsigned int hcrc =*/ tinf_get_uint16(d); + + // TODO: Check! +// if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff)) +// return TINF_DATA_ERROR; + } + + /* initialize for crc32 checksum */ + d->checksum_type = TINF_CHKSUM_CRC; + d->checksum = ~0; + + return TINF_OK; +} diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index 0e53f7f072..58850eb4a2 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -361,6 +361,9 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); if (d->dict_ring) { + if (offs > d->dict_size) { + return TINF_DICT_ERROR; + } d->lzOff = d->dict_idx - offs; if (d->lzOff < 0) { d->lzOff += d->dict_size; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index eea075f6b0..6e827fc664 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -31,6 +31,7 @@ #include <string.h> #include "py/nlr.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" @@ -76,25 +77,42 @@ STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_listdir_obj, 1, 2, fat_vfs_listdir_func); -STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; +STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) { const char *path = mp_obj_str_get_str(path_in); - // TODO check that path is actually a file before trying to unlink it - FRESULT res = f_unlink(path); - if (res == FR_OK) { + + FILINFO fno; +#if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; +#endif + FRESULT res = f_stat(path, &fno); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + // check if path is a file or directory + if ((fno.fattrib & AM_DIR) == attr) { + res = f_unlink(path); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } return mp_const_none; } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR); } } + +STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + return fat_vfs_remove_internal(path_in, 0); // 0 == file attribute +} STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); STATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) { - // TODO: Currently just redirects to fat_vfs_remove(), which are - // backed by the same underlying FatFs function. Should at least - // check that path is actually a dir. - return fat_vfs_remove(vfs_in, path_in); + (void) vfs_in; + return fat_vfs_remove_internal(path_in, AM_DIR); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir); @@ -106,8 +124,7 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_ if (res == FR_OK) { return mp_const_none; } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } } @@ -120,8 +137,7 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { if (res == FR_OK) { return mp_const_none; } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); @@ -139,8 +155,7 @@ STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } return mp_const_none; @@ -154,7 +169,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { FRESULT res = f_getcwd(buf, sizeof buf); if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } return mp_obj_new_str(buf, strlen(buf), false); @@ -215,8 +230,7 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { res = f_stat(path, &fno); } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } } @@ -250,6 +264,35 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); +// Get the status of a VFS. +STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + const char *path = mp_obj_str_get_str(path_in); + + FATFS *fatfs; + DWORD nclst; + FRESULT res = f_getfree(path, &nclst, &fatfs); + if (FR_OK != res) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); + + t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * fatfs->ssize); // f_bsize + t->items[1] = t->items[0]; // f_frsize + t->items[2] = MP_OBJ_NEW_SMALL_INT((fatfs->n_fatent - 2) * fatfs->csize); // f_blocks + t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree + t->items[4] = t->items[3]; // f_bavail + t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files + t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree + t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail + t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags + t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax + + return MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); + // Unmount the filesystem STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]); @@ -268,6 +311,7 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 0cd61e4605..ecc9ed70f9 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -35,6 +35,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "lib/fatfs/ff.h" #include "extmod/vfs_fat_file.h" @@ -49,25 +50,25 @@ extern const mp_obj_type_t mp_type_textio; // this table converts from FRESULT to POSIX errno const byte fresult_to_errno_table[20] = { [FR_OK] = 0, - [FR_DISK_ERR] = EIO, - [FR_INT_ERR] = EIO, - [FR_NOT_READY] = EBUSY, - [FR_NO_FILE] = ENOENT, - [FR_NO_PATH] = ENOENT, - [FR_INVALID_NAME] = EINVAL, - [FR_DENIED] = EACCES, - [FR_EXIST] = EEXIST, - [FR_INVALID_OBJECT] = EINVAL, - [FR_WRITE_PROTECTED] = EROFS, - [FR_INVALID_DRIVE] = ENODEV, - [FR_NOT_ENABLED] = ENODEV, - [FR_NO_FILESYSTEM] = ENODEV, - [FR_MKFS_ABORTED] = EIO, - [FR_TIMEOUT] = EIO, - [FR_LOCKED] = EIO, - [FR_NOT_ENOUGH_CORE] = ENOMEM, - [FR_TOO_MANY_OPEN_FILES] = EMFILE, - [FR_INVALID_PARAMETER] = EINVAL, + [FR_DISK_ERR] = MP_EIO, + [FR_INT_ERR] = MP_EIO, + [FR_NOT_READY] = MP_EBUSY, + [FR_NO_FILE] = MP_ENOENT, + [FR_NO_PATH] = MP_ENOENT, + [FR_INVALID_NAME] = MP_EINVAL, + [FR_DENIED] = MP_EACCES, + [FR_EXIST] = MP_EEXIST, + [FR_INVALID_OBJECT] = MP_EINVAL, + [FR_WRITE_PROTECTED] = MP_EROFS, + [FR_INVALID_DRIVE] = MP_ENODEV, + [FR_NOT_ENABLED] = MP_ENODEV, + [FR_NO_FILESYSTEM] = MP_ENODEV, + [FR_MKFS_ABORTED] = MP_EIO, + [FR_TIMEOUT] = MP_EIO, + [FR_LOCKED] = MP_EIO, + [FR_NOT_ENOUGH_CORE] = MP_ENOMEM, + [FR_TOO_MANY_OPEN_FILES] = MP_EMFILE, + [FR_INVALID_PARAMETER] = MP_EINVAL, }; typedef struct _pyb_file_obj_t { @@ -101,7 +102,7 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz } if (sz_out != size) { // The FatFS documentation says that this means disk full. - *errcode = ENOSPC; + *errcode = MP_ENOSPC; return MP_STREAM_ERROR; } return sz_out; @@ -140,7 +141,7 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, case 1: // SEEK_CUR if (s->offset != 0) { - *errcode = ENOTSUP; + *errcode = MP_EOPNOTSUPP; return MP_STREAM_ERROR; } // no-operation @@ -155,7 +156,7 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, return 0; } else { - *errcode = EINVAL; + *errcode = MP_EINVAL; return MP_STREAM_ERROR; } } @@ -208,7 +209,7 @@ STATIC mp_obj_t file_open(const mp_obj_type_t *type, mp_arg_val_t *args) { FRESULT res = f_open(&o->fp, fname, mode); if (res != FR_OK) { m_del_obj(pyb_file_obj_t, o); - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } // for 'a' mode, we must begin at the end of the file diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 23fe4be88d..d3507a85f3 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -54,9 +54,7 @@ mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, - MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); - + mp_raise_OSError(fresult_to_errno_table[res]); } mp_obj_t dir_list = mp_obj_new_list(0, NULL); |