فهرست منبع

[update] extmod folder

SummerGift 6 سال پیش
والد
کامیت
30adcd6fcc

+ 148 - 85
extmod/machine_i2c.c

@@ -180,9 +180,9 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
 }
 }
 
 
 // return value:
 // return value:
-//  >=0 - number of acks received
+//  >=0 - success; for read it's 0, for write it's number of acks received
 //   <0 - error, with errno being the negative of the return value
 //   <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) {
+int mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
     machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
     machine_i2c_obj_t *self = (machine_i2c_obj_t*)self_in;
 
 
     // start the I2C transaction
     // start the I2C transaction
@@ -192,7 +192,7 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin
     }
     }
 
 
     // write the slave address
     // write the slave address
-    ret = mp_hal_i2c_write_byte(self, addr << 1);
+    ret = mp_hal_i2c_write_byte(self, (addr << 1) | (flags & MP_MACHINE_I2C_FLAG_READ));
     if (ret < 0) {
     if (ret < 0) {
         return ret;
         return ret;
     } else if (ret != 0) {
     } else if (ret != 0) {
@@ -201,69 +201,102 @@ int mp_machine_soft_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uin
         return -MP_ENODEV;
         return -MP_ENODEV;
     }
     }
 
 
-    // write the buffer to the I2C memory
-    int num_acks = 0;
-    while (len--) {
-        ret = mp_hal_i2c_write_byte(self, *src++);
-        if (ret < 0) {
-            return ret;
-        } else if (ret != 0) {
-            // nack received, stop sending
-            break;
+    int transfer_ret = 0;
+    for (; n--; ++bufs) {
+        size_t len = bufs->len;
+        uint8_t *buf = bufs->buf;
+        if (flags & MP_MACHINE_I2C_FLAG_READ) {
+            // read bytes from the slave into the given buffer(s)
+            while (len--) {
+                ret = mp_hal_i2c_read_byte(self, buf++, (n | len) == 0);
+                if (ret != 0) {
+                    return ret;
+                }
+            }
+        } else {
+            // write bytes from the given buffer(s) to the slave
+            while (len--) {
+                ret = mp_hal_i2c_write_byte(self, *buf++);
+                if (ret < 0) {
+                    return ret;
+                } else if (ret != 0) {
+                    // nack received, stop sending
+                    n = 0;
+                    break;
+                }
+                ++transfer_ret; // count the number of acks
+            }
         }
         }
-        ++num_acks;
     }
     }
 
 
     // finish the I2C transaction
     // finish the I2C transaction
-    if (stop) {
+    if (flags & MP_MACHINE_I2C_FLAG_STOP) {
         ret = mp_hal_i2c_stop(self);
         ret = mp_hal_i2c_stop(self);
         if (ret != 0) {
         if (ret != 0) {
             return ret;
             return ret;
         }
         }
     }
     }
 
 
-    return num_acks;
+    return transfer_ret;
 }
 }
 
 
-// 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;
-
-    // start the I2C transaction
-    int ret = mp_hal_i2c_start(self);
-    if (ret != 0) {
-        return ret;
-    }
-
-    // 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--) {
-        ret = mp_hal_i2c_read_byte(self, dest++, len == 0);
-        if (ret != 0) {
-            return ret;
+/******************************************************************************/
+// Generic helper functions
+
+// For use by ports that require a single buffer of data for a read/write transfer
+int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
+    size_t len;
+    uint8_t *buf;
+    if (n == 1) {
+        // Use given single buffer
+        len = bufs[0].len;
+        buf = bufs[0].buf;
+    } else {
+        // Combine buffers into a single one
+        len = 0;
+        for (size_t i = 0; i < n; ++i) {
+            len += bufs[i].len;
+        }
+        buf = m_new(uint8_t, len);
+        if (!(flags & MP_MACHINE_I2C_FLAG_READ)) {
+            len = 0;
+            for (size_t i = 0; i < n; ++i) {
+                memcpy(buf + len, bufs[i].buf, bufs[i].len);
+                len += bufs[i].len;
+            }
         }
         }
     }
     }
 
 
-    // finish the I2C transaction
-    if (stop) {
-        ret = mp_hal_i2c_stop(self);
-        if (ret != 0) {
-            return ret;
+    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+    int ret = i2c_p->transfer_single(self, addr, len, buf, flags);
+
+    if (n > 1) {
+        if (flags & MP_MACHINE_I2C_FLAG_READ) {
+            // Copy data from single buffer to individual ones
+            len = 0;
+            for (size_t i = 0; i < n; ++i) {
+                memcpy(bufs[i].buf, buf + len, bufs[i].len);
+                len += bufs[i].len;
+            }
         }
         }
+        m_del(uint8_t, buf, len);
     }
     }
 
 
-    return 0; // success
+    return ret;
+}
+
+STATIC int mp_machine_i2c_readfrom(mp_obj_base_t *self, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
+    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+    mp_machine_i2c_buf_t buf = {.len = len, .buf = dest};
+    unsigned int flags = MP_MACHINE_I2C_FLAG_READ | (stop ? MP_MACHINE_I2C_FLAG_STOP : 0);
+    return i2c_p->transfer(self, addr, 1, &buf, flags);
+}
+
+STATIC int mp_machine_i2c_writeto(mp_obj_base_t *self, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
+    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+    mp_machine_i2c_buf_t buf = {.len = len, .buf = (uint8_t*)src};
+    unsigned int flags = stop ? MP_MACHINE_I2C_FLAG_STOP : 0;
+    return i2c_p->transfer(self, addr, 1, &buf, flags);
 }
 }
 
 
 /******************************************************************************/
 /******************************************************************************/
@@ -318,11 +351,10 @@ 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) {
 STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) {
     mp_obj_base_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);
     mp_obj_t list = mp_obj_new_list(0, NULL);
     // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
     // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
     for (int addr = 0x08; addr < 0x78; ++addr) {
     for (int addr = 0x08; addr < 0x78; ++addr) {
-        int ret = i2c_p->writeto(self, addr, NULL, 0, true);
+        int ret = mp_machine_i2c_writeto(self, addr, NULL, 0, true);
         if (ret == 0) {
         if (ret == 0) {
             mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
             mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr));
         }
         }
@@ -407,12 +439,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_write_obj, machine_i2c_write);
 
 
 STATIC mp_obj_t machine_i2c_readfrom(size_t n_args, const mp_obj_t *args) {
 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_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_int_t addr = mp_obj_get_int(args[1]);
     vstr_t vstr;
     vstr_t vstr;
     vstr_init_len(&vstr, mp_obj_get_int(args[2]));
     vstr_init_len(&vstr, mp_obj_get_int(args[2]));
     bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
     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);
+    int ret = mp_machine_i2c_readfrom(self, addr, (uint8_t*)vstr.buf, vstr.len, stop);
     if (ret < 0) {
     if (ret < 0) {
         mp_raise_OSError(-ret);
         mp_raise_OSError(-ret);
     }
     }
@@ -422,12 +453,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_obj, 3, 4, machine_i2c_
 
 
 STATIC mp_obj_t machine_i2c_readfrom_into(size_t n_args, const mp_obj_t *args) {
 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_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_int_t addr = mp_obj_get_int(args[1]);
     mp_buffer_info_t bufinfo;
     mp_buffer_info_t bufinfo;
     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_WRITE);
     bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
     bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
-    int ret = i2c_p->readfrom(self, addr, bufinfo.buf, bufinfo.len, stop);
+    int ret = mp_machine_i2c_readfrom(self, addr, bufinfo.buf, bufinfo.len, stop);
     if (ret < 0) {
     if (ret < 0) {
         mp_raise_OSError(-ret);
         mp_raise_OSError(-ret);
     }
     }
@@ -437,12 +467,11 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_readfrom_into_obj, 3, 4, machine
 
 
 STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {
 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_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_int_t addr = mp_obj_get_int(args[1]);
     mp_buffer_info_t bufinfo;
     mp_buffer_info_t bufinfo;
     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
     mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
     bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
     bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
-    int ret = i2c_p->writeto(self, addr,  bufinfo.buf, bufinfo.len, stop);
+    int ret = mp_machine_i2c_writeto(self, addr, bufinfo.buf, bufinfo.len, stop);
     if (ret < 0) {
     if (ret < 0) {
         mp_raise_OSError(-ret);
         mp_raise_OSError(-ret);
     }
     }
@@ -451,53 +480,87 @@ STATIC mp_obj_t machine_i2c_writeto(size_t n_args, const mp_obj_t *args) {
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_i2c_writeto_obj, 3, 4, machine_i2c_writeto);
 
 
+STATIC mp_obj_t machine_i2c_writevto(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_int_t addr = mp_obj_get_int(args[1]);
+
+    // Get the list of data buffer(s) to write
+    size_t nitems;
+    const mp_obj_t *items;
+    mp_obj_get_array(args[2], &nitems, (mp_obj_t**)&items);
+
+    // Get the stop argument
+    bool stop = (n_args == 3) ? true : mp_obj_is_true(args[3]);
+
+    // Extract all buffer data, skipping zero-length buffers
+    size_t alloc = nitems == 0 ? 1 : nitems;
+    size_t nbufs = 0;
+    mp_machine_i2c_buf_t *bufs = mp_local_alloc(alloc * sizeof(mp_machine_i2c_buf_t));
+    for (; nitems--; ++items) {
+        mp_buffer_info_t bufinfo;
+        mp_get_buffer_raise(*items, &bufinfo, MP_BUFFER_READ);
+        if (bufinfo.len > 0) {
+            bufs[nbufs].len = bufinfo.len;
+            bufs[nbufs++].buf = bufinfo.buf;
+        }
+    }
+
+    // Make sure there is at least one buffer, empty if needed
+    if (nbufs == 0) {
+        bufs[0].len = 0;
+        bufs[0].buf = NULL;
+        nbufs = 1;
+    }
+
+    // Do the I2C transfer
+    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+    int ret = i2c_p->transfer(self, addr, nbufs, bufs, stop ? MP_MACHINE_I2C_FLAG_STOP : 0);
+    mp_local_free(bufs);
+
+    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_writevto_obj, 3, 4, machine_i2c_writevto);
+
 STATIC int read_mem(mp_obj_t self_in, uint16_t addr, uint32_t memaddr, uint8_t addrsize, uint8_t *buf, size_t len) {
 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_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];
     uint8_t memaddr_buf[4];
     size_t memaddr_len = 0;
     size_t memaddr_len = 0;
     for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
     for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
         memaddr_buf[memaddr_len++] = memaddr >> i;
         memaddr_buf[memaddr_len++] = memaddr >> i;
     }
     }
-    int ret = i2c_p->writeto(self, addr, memaddr_buf, memaddr_len, false);
+    int ret = mp_machine_i2c_writeto(self, addr, memaddr_buf, memaddr_len, false);
     if (ret != memaddr_len) {
     if (ret != memaddr_len) {
         // must generate STOP
         // must generate STOP
-        i2c_p->writeto(self, addr, NULL, 0, true);
+        mp_machine_i2c_writeto(self, addr, NULL, 0, true);
         return ret;
         return ret;
     }
     }
-    return i2c_p->readfrom(self, addr, buf, len, true);
+    return mp_machine_i2c_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) {
 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_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
+    // Create buffer with memory address
     size_t memaddr_len = 0;
     size_t memaddr_len = 0;
+    uint8_t memaddr_buf[4];
     for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
     for (int16_t i = addrsize - 8; i >= 0; i -= 8) {
-        buf2[memaddr_len++] = memaddr >> i;
+        memaddr_buf[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;
+    // Create partial write buffers
+    mp_machine_i2c_buf_t bufs[2] = {
+        {.len = memaddr_len, .buf = memaddr_buf},
+        {.len = len, .buf = (uint8_t*)buf},
+    };
+
+    // Do I2C transfer
+    mp_machine_i2c_p_t *i2c_p = (mp_machine_i2c_p_t*)self->type->protocol;
+    return i2c_p->transfer(self, addr, 2, bufs, MP_MACHINE_I2C_FLAG_STOP);
 }
 }
 
 
 STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
 STATIC const mp_arg_t machine_i2c_mem_allowed_args[] = {
@@ -584,6 +647,7 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) },
     { MP_ROM_QSTR(MP_QSTR_readfrom), MP_ROM_PTR(&machine_i2c_readfrom_obj) },
     { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) },
     { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&machine_i2c_readfrom_into_obj) },
     { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) },
     { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&machine_i2c_writeto_obj) },
+    { MP_ROM_QSTR(MP_QSTR_writevto), MP_ROM_PTR(&machine_i2c_writevto_obj) },
 
 
     // memory operations
     // memory operations
     { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) },
     { MP_ROM_QSTR(MP_QSTR_readfrom_mem), MP_ROM_PTR(&machine_i2c_readfrom_mem_obj) },
@@ -625,8 +689,7 @@ STATIC const mp_machine_i2c_p_t mp_machine_soft_i2c_p = {
     .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop,
     .stop = (int(*)(mp_obj_base_t*))mp_hal_i2c_stop,
     .read = mp_machine_soft_i2c_read,
     .read = mp_machine_soft_i2c_read,
     .write = mp_machine_soft_i2c_write,
     .write = mp_machine_soft_i2c_write,
-    .readfrom = mp_machine_soft_i2c_readfrom,
-    .writeto = mp_machine_soft_i2c_writeto,
+    .transfer = mp_machine_soft_i2c_transfer,
 };
 };
 
 
 const mp_obj_type_t machine_i2c_type = {
 const mp_obj_type_t machine_i2c_type = {

+ 13 - 4
extmod/machine_i2c.h

@@ -28,15 +28,24 @@
 
 
 #include "py/obj.h"
 #include "py/obj.h"
 
 
+#define MP_MACHINE_I2C_FLAG_READ (0x01) // if not set then it's a write
+#define MP_MACHINE_I2C_FLAG_STOP (0x02)
+
+typedef struct _mp_machine_i2c_buf_t {
+    size_t len;
+    uint8_t *buf;
+} mp_machine_i2c_buf_t;
+
 // I2C protocol
 // I2C protocol
 // the first 4 methods can be NULL, meaning operation is not supported
 // the first 4 methods can be NULL, meaning operation is not supported
+// transfer_single only needs to be set if transfer=mp_machine_i2c_transfer_adaptor
 typedef struct _mp_machine_i2c_p_t {
 typedef struct _mp_machine_i2c_p_t {
     int (*start)(mp_obj_base_t *obj);
     int (*start)(mp_obj_base_t *obj);
     int (*stop)(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 (*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 (*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);
+    int (*transfer)(mp_obj_base_t *obj, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
+    int (*transfer_single)(mp_obj_base_t *obj, uint16_t addr, size_t len, uint8_t *buf, unsigned int flags);
 } mp_machine_i2c_p_t;
 } mp_machine_i2c_p_t;
 
 
 typedef struct _mp_machine_soft_i2c_obj_t {
 typedef struct _mp_machine_soft_i2c_obj_t {
@@ -50,7 +59,7 @@ typedef struct _mp_machine_soft_i2c_obj_t {
 extern const mp_obj_type_t machine_i2c_type;
 extern const mp_obj_type_t machine_i2c_type;
 extern const mp_obj_dict_t mp_machine_soft_i2c_locals_dict;
 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);
+int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
+int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
 
 
 #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H
 #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_I2C_H

+ 1 - 1
extmod/machine_pulse.c

@@ -30,7 +30,7 @@
 
 
 #if MICROPY_PY_MACHINE_PULSE
 #if MICROPY_PY_MACHINE_PULSE
 
 
-mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
+MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
     mp_uint_t start = mp_hal_ticks_us();
     mp_uint_t start = mp_hal_ticks_us();
     while (mp_hal_pin_read(pin) != pulse_level) {
     while (mp_hal_pin_read(pin) != pulse_level) {
         if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {
         if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {

+ 3 - 2
extmod/machine_signal.c

@@ -43,13 +43,13 @@ typedef struct _machine_signal_t {
 } machine_signal_t;
 } machine_signal_t;
 
 
 STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
 STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
-    mp_obj_t pin = args[0];
+    mp_obj_t pin;
     bool invert = false;
     bool invert = false;
 
 
     #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
     #if defined(MICROPY_PY_MACHINE_PIN_MAKE_NEW)
     mp_pin_p_t *pin_p = NULL;
     mp_pin_p_t *pin_p = NULL;
 
 
-    if (mp_obj_is_obj(pin)) {
+    if (n_args > 0 && mp_obj_is_obj(args[0])) {
         mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
         mp_obj_base_t *pin_base = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[0]);
         pin_p = (mp_pin_p_t*)pin_base->type->protocol;
         pin_p = (mp_pin_p_t*)pin_base->type->protocol;
     }
     }
@@ -96,6 +96,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t
     // Otherwise there should be 1 or 2 args
     // Otherwise there should be 1 or 2 args
     {
     {
         if (n_args == 1) {
         if (n_args == 1) {
+            pin = args[0];
             if (n_kw == 0) {
             if (n_kw == 0) {
             } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
             } else if (n_kw == 1 && args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_invert)) {
                 invert = mp_obj_is_true(args[2]);
                 invert = mp_obj_is_true(args[2]);

+ 2 - 0
extmod/misc.h

@@ -35,6 +35,8 @@
 MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
 MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
 
 
 #if MICROPY_PY_OS_DUPTERM
 #if MICROPY_PY_OS_DUPTERM
+bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream);
+uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags);
 int mp_uos_dupterm_rx_chr(void);
 int mp_uos_dupterm_rx_chr(void);
 void mp_uos_dupterm_tx_strn(const char *str, size_t len);
 void mp_uos_dupterm_tx_strn(const char *str, size_t len);
 void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
 void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);

+ 8 - 2
extmod/modbtree.c

@@ -52,7 +52,9 @@ typedef struct _mp_obj_btree_t {
     byte next_flags;
     byte next_flags;
 } mp_obj_btree_t;
 } mp_obj_btree_t;
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_obj_type_t btree_type;
 STATIC const mp_obj_type_t btree_type;
+#endif
 
 
 #define CHECK_ERROR(res) \
 #define CHECK_ERROR(res) \
         if (res == RET_ERROR) { \
         if (res == RET_ERROR) { \
@@ -60,7 +62,7 @@ STATIC const mp_obj_type_t btree_type;
         }
         }
 
 
 void __dbpanic(DB *db) {
 void __dbpanic(DB *db) {
-    printf("__dbpanic(%p)\n", db);
+    mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
 }
 }
 
 
 STATIC mp_obj_btree_t *btree_new(DB *db) {
 STATIC mp_obj_btree_t *btree_new(DB *db) {
@@ -295,6 +297,7 @@ STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
     }
     }
 }
 }
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t btree_locals_dict_table[] = {
 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_close), MP_ROM_PTR(&btree_close_obj) },
     { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) },
     { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&btree_flush_obj) },
@@ -319,14 +322,16 @@ STATIC const mp_obj_type_t btree_type = {
     .subscr = btree_subscr,
     .subscr = btree_subscr,
     .locals_dict = (void*)&btree_locals_dict,
     .locals_dict = (void*)&btree_locals_dict,
 };
 };
+#endif
 
 
-STATIC FILEVTABLE btree_stream_fvtable = {
+STATIC const FILEVTABLE btree_stream_fvtable = {
     mp_stream_posix_read,
     mp_stream_posix_read,
     mp_stream_posix_write,
     mp_stream_posix_write,
     mp_stream_posix_lseek,
     mp_stream_posix_lseek,
     mp_stream_posix_fsync
     mp_stream_posix_fsync
 };
 };
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     static const mp_arg_t allowed_args[] = {
     static const mp_arg_t allowed_args[] = {
         { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
         { MP_QSTR_flags, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
@@ -373,5 +378,6 @@ const mp_obj_module_t mp_module_btree = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&mp_module_btree_globals,
     .globals = (mp_obj_dict_t*)&mp_module_btree_globals,
 };
 };
+#endif
 
 
 #endif // MICROPY_PY_BTREE
 #endif // MICROPY_PY_BTREE

+ 4 - 0
extmod/modframebuf.c

@@ -580,6 +580,7 @@ STATIC mp_obj_t framebuf_text(size_t n_args, const mp_obj_t *args) {
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_text_obj, 4, 5, framebuf_text);
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t framebuf_locals_dict_table[] = {
 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), 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_fill_rect), MP_ROM_PTR(&framebuf_fill_rect_obj) },
@@ -601,6 +602,7 @@ STATIC const mp_obj_type_t mp_type_framebuf = {
     .buffer_p = { .get_buffer = framebuf_get_buffer },
     .buffer_p = { .get_buffer = framebuf_get_buffer },
     .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict,
     .locals_dict = (mp_obj_dict_t*)&framebuf_locals_dict,
 };
 };
+#endif
 
 
 // this factory function is provided for backwards compatibility with old FrameBuffer1 class
 // 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) {
 STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) {
@@ -624,6 +626,7 @@ STATIC mp_obj_t legacy_framebuffer1(size_t n_args, const mp_obj_t *args) {
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(legacy_framebuffer1_obj, 3, 4, legacy_framebuffer1);
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
 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___name__), MP_ROM_QSTR(MP_QSTR_framebuf) },
     { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) },
     { MP_ROM_QSTR(MP_QSTR_FrameBuffer), MP_ROM_PTR(&mp_type_framebuf) },
@@ -644,5 +647,6 @@ const mp_obj_module_t mp_module_framebuf = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&framebuf_module_globals,
     .globals = (mp_obj_dict_t*)&framebuf_module_globals,
 };
 };
+#endif
 
 
 #endif // MICROPY_PY_FRAMEBUF
 #endif // MICROPY_PY_FRAMEBUF

+ 106 - 20
extmod/moducryptolib.c

@@ -41,10 +41,17 @@
 
 
 // values follow PEP 272
 // values follow PEP 272
 enum {
 enum {
-    UCRYPTOLIB_MODE_MIN = 0,
-    UCRYPTOLIB_MODE_ECB,
-    UCRYPTOLIB_MODE_CBC,
-    UCRYPTOLIB_MODE_MAX,
+    UCRYPTOLIB_MODE_ECB = 1,
+    UCRYPTOLIB_MODE_CBC = 2,
+    UCRYPTOLIB_MODE_CTR = 6,
+};
+
+struct ctr_params {
+    // counter is the IV of the AES context.
+
+    size_t offset; // in encrypted_counter
+    // encrypted counter
+    uint8_t encrypted_counter[16];
 };
 };
 
 
 #if MICROPY_SSL_AXTLS
 #if MICROPY_SSL_AXTLS
@@ -82,6 +89,19 @@ typedef struct _mp_obj_aes_t {
     uint8_t key_type: 2;
     uint8_t key_type: 2;
 } mp_obj_aes_t;
 } mp_obj_aes_t;
 
 
+static inline bool is_ctr_mode(int block_mode) {
+    #if MICROPY_PY_UCRYPTOLIB_CTR
+    return block_mode == UCRYPTOLIB_MODE_CTR;
+    #else
+    return false;
+    #endif
+}
+
+static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
+    // ctr_params follows aes object struct
+    return (struct ctr_params*)&o[1];
+}
+
 #if MICROPY_SSL_AXTLS
 #if MICROPY_SSL_AXTLS
 STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
 STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
     assert(16 == keysize || 32 == keysize);
     assert(16 == keysize || 32 == keysize);
@@ -119,6 +139,33 @@ STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *
         AES_cbc_decrypt(ctx, in, out, in_len);
         AES_cbc_decrypt(ctx, in, out, in_len);
     }
     }
 }
 }
+
+#if MICROPY_PY_UCRYPTOLIB_CTR
+// axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive.
+STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
+    size_t n = ctr_params->offset;
+    uint8_t *const counter = ctx->iv;
+
+    while (in_len--) {
+        if (n == 0) {
+            aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true);
+
+            // increment the 128-bit counter
+            for (int i = 15; i >= 0; --i) {
+                if (++counter[i] != 0) {
+                    break;
+                }
+            }
+        }
+
+        *out++ = *in++ ^ ctr_params->encrypted_counter[n];
+        n = (n + 1) & 0xf;
+    }
+
+    ctr_params->offset = n;
+}
+#endif
+
 #endif
 #endif
 
 
 #if MICROPY_SSL_MBEDTLS
 #if MICROPY_SSL_MBEDTLS
@@ -155,20 +202,38 @@ STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_
 STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
 STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
     mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);
     mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);
 }
 }
+
+#if MICROPY_PY_UCRYPTOLIB_CTR
+STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
+    mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out);
+}
+#endif
+
 #endif
 #endif
 
 
 STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
 STATIC mp_obj_t ucryptolib_aes_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, 2, 3, false);
     mp_arg_check_num(n_args, n_kw, 2, 3, false);
-    mp_obj_aes_t *o = m_new_obj(mp_obj_aes_t);
-    o->base.type = type;
 
 
-    o->block_mode = mp_obj_get_int(args[1]);
-    o->key_type = AES_KEYTYPE_NONE;
+    const mp_int_t block_mode = mp_obj_get_int(args[1]);
+
+    switch (block_mode) {
+        case UCRYPTOLIB_MODE_ECB:
+        case UCRYPTOLIB_MODE_CBC:
+        #if MICROPY_PY_UCRYPTOLIB_CTR
+        case UCRYPTOLIB_MODE_CTR:
+        #endif
+            break;
 
 
-    if (o->block_mode <= UCRYPTOLIB_MODE_MIN || o->block_mode >= UCRYPTOLIB_MODE_MAX) {
-        mp_raise_ValueError("mode");
+        default:
+            mp_raise_ValueError("mode");
     }
     }
 
 
+    mp_obj_aes_t *o = m_new_obj_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode));
+    o->base.type = type;
+
+    o->block_mode = block_mode;
+    o->key_type = AES_KEYTYPE_NONE;
+
     mp_buffer_info_t keyinfo;
     mp_buffer_info_t keyinfo;
     mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);
     mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);
     if (32 != keyinfo.len && 16 != keyinfo.len) {
     if (32 != keyinfo.len && 16 != keyinfo.len) {
@@ -183,10 +248,14 @@ STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args
         if (16 != ivinfo.len) {
         if (16 != ivinfo.len) {
             mp_raise_ValueError("IV");
             mp_raise_ValueError("IV");
         }
         }
-    } else if (o->block_mode == UCRYPTOLIB_MODE_CBC) {
+    } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) {
         mp_raise_ValueError("IV");
         mp_raise_ValueError("IV");
     }
     }
 
 
+    if (is_ctr_mode(block_mode)) {
+        ctr_params_from_aes(o)->offset = 0;
+    }
+
     aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);
     aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);
 
 
     return MP_OBJ_FROM_PTR(o);
     return MP_OBJ_FROM_PTR(o);
@@ -204,7 +273,7 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
     mp_buffer_info_t in_bufinfo;
     mp_buffer_info_t in_bufinfo;
     mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);
     mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);
 
 
-    if (in_bufinfo.len % 16 != 0) {
+    if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) {
         mp_raise_ValueError("blksize % 16");
         mp_raise_ValueError("blksize % 16");
     }
     }
 
 
@@ -224,7 +293,9 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
     }
     }
 
 
     if (AES_KEYTYPE_NONE == self->key_type) {
     if (AES_KEYTYPE_NONE == self->key_type) {
-        aes_final_set_key_impl(&self->ctx, encrypt);
+        // always set key for encryption if CTR mode.
+        const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode);
+        aes_final_set_key_impl(&self->ctx, encrypt_mode);
         self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;
         self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;
     } else {
     } else {
         if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||
         if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||
@@ -234,14 +305,26 @@ STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
         }
         }
     }
     }
 
 
-    if (self->block_mode == UCRYPTOLIB_MODE_ECB) {
-        uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;
-        uint8_t *top = in + in_bufinfo.len;
-        for (; in < top; in += 16, out += 16) {
-            aes_process_ecb_impl(&self->ctx, in, out, encrypt);
+    switch (self->block_mode) {
+        case UCRYPTOLIB_MODE_ECB: {
+            uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;
+            uint8_t *top = in + in_bufinfo.len;
+            for (; in < top; in += 16, out += 16) {
+                aes_process_ecb_impl(&self->ctx, in, out, encrypt);
+            }
+            break;
         }
         }
-    } else {
-        aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);
+
+        case UCRYPTOLIB_MODE_CBC:
+            aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);
+            break;
+
+        #if MICROPY_PY_UCRYPTOLIB_CTR
+        case UCRYPTOLIB_MODE_CTR:
+            aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len,
+                ctr_params_from_aes(self));
+            break;
+        #endif
     }
     }
 
 
     if (out_buf != MP_OBJ_NULL) {
     if (out_buf != MP_OBJ_NULL) {
@@ -279,6 +362,9 @@ STATIC const mp_rom_map_elem_t mp_module_ucryptolib_globals_table[] = {
 #if MICROPY_PY_UCRYPTOLIB_CONSTS
 #if MICROPY_PY_UCRYPTOLIB_CONSTS
     { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },
     { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },
     { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },
     { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },
+    #if MICROPY_PY_UCRYPTOLIB_CTR
+    { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) },
+    #endif
 #endif
 #endif
 };
 };
 
 

+ 3 - 3
extmod/moductypes.c

@@ -299,13 +299,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, ucty
 static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
 static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) {
     char struct_type = big_endian ? '>' : '<';
     char struct_type = big_endian ? '>' : '<';
     static const char type2char[16] = "BbHhIiQq------fd";
     static const char type2char[16] = "BbHhIiQq------fd";
-    return mp_binary_get_val(struct_type, type2char[val_type], &p);
+    return mp_binary_get_val(struct_type, type2char[val_type], p, &p);
 }
 }
 
 
 static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
 static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) {
     char struct_type = big_endian ? '>' : '<';
     char struct_type = big_endian ? '>' : '<';
     static const char type2char[16] = "BbHhIiQq------fd";
     static const char type2char[16] = "BbHhIiQq------fd";
-    mp_binary_set_val(struct_type, type2char[val_type], val, &p);
+    mp_binary_set_val(struct_type, type2char[val_type], val, p, &p);
 }
 }
 
 
 static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
 static inline mp_uint_t get_aligned_basic(uint val_type, void *p) {
@@ -558,7 +558,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob
             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
             uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
             arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
             if (index >= arr_sz) {
             if (index >= arr_sz) {
-                nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "struct: index out of range"));
+                mp_raise_msg(&mp_type_IndexError, "struct: index out of range");
             }
             }
 
 
             if (t->len == 2) {
             if (t->len == 2) {

+ 13 - 11
extmod/moduheapq.c

@@ -31,14 +31,14 @@
 
 
 // the algorithm here is modelled on CPython's heapq.py
 // the algorithm here is modelled on CPython's heapq.py
 
 
-STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
+STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
     if (!mp_obj_is_type(heap_in, &mp_type_list)) {
     if (!mp_obj_is_type(heap_in, &mp_type_list)) {
         mp_raise_TypeError("heap must be a list");
         mp_raise_TypeError("heap must be a list");
     }
     }
     return MP_OBJ_TO_PTR(heap_in);
     return MP_OBJ_TO_PTR(heap_in);
 }
 }
 
 
-STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
+STATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
     mp_obj_t item = heap->items[pos];
     mp_obj_t item = heap->items[pos];
     while (pos > start_pos) {
     while (pos > start_pos) {
         mp_uint_t parent_pos = (pos - 1) >> 1;
         mp_uint_t parent_pos = (pos - 1) >> 1;
@@ -53,7 +53,7 @@ STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t po
     heap->items[pos] = item;
     heap->items[pos] = item;
 }
 }
 
 
-STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
+STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
     mp_uint_t start_pos = pos;
     mp_uint_t start_pos = pos;
     mp_uint_t end_pos = heap->len;
     mp_uint_t end_pos = heap->len;
     mp_obj_t item = heap->items[pos];
     mp_obj_t item = heap->items[pos];
@@ -67,42 +67,43 @@ STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
         pos = child_pos;
         pos = child_pos;
     }
     }
     heap->items[pos] = item;
     heap->items[pos] = item;
-    heap_siftdown(heap, start_pos, pos);
+    uheapq_heap_siftdown(heap, start_pos, pos);
 }
 }
 
 
 STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
 STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
-    mp_obj_list_t *heap = get_heap(heap_in);
+    mp_obj_list_t *heap = uheapq_get_heap(heap_in);
     mp_obj_list_append(heap_in, item);
     mp_obj_list_append(heap_in, item);
-    heap_siftdown(heap, 0, heap->len - 1);
+    uheapq_heap_siftdown(heap, 0, heap->len - 1);
     return mp_const_none;
     return mp_const_none;
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
 
 
 STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
 STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
-    mp_obj_list_t *heap = get_heap(heap_in);
+    mp_obj_list_t *heap = uheapq_get_heap(heap_in);
     if (heap->len == 0) {
     if (heap->len == 0) {
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
+        mp_raise_msg(&mp_type_IndexError, "empty heap");
     }
     }
     mp_obj_t item = heap->items[0];
     mp_obj_t item = heap->items[0];
     heap->len -= 1;
     heap->len -= 1;
     heap->items[0] = heap->items[heap->len];
     heap->items[0] = heap->items[heap->len];
     heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
     heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
     if (heap->len) {
     if (heap->len) {
-        heap_siftup(heap, 0);
+        uheapq_heap_siftup(heap, 0);
     }
     }
     return item;
     return item;
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
 
 
 STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
 STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
-    mp_obj_list_t *heap = get_heap(heap_in);
+    mp_obj_list_t *heap = uheapq_get_heap(heap_in);
     for (mp_uint_t i = heap->len / 2; i > 0;) {
     for (mp_uint_t i = heap->len / 2; i > 0;) {
-        heap_siftup(heap, --i);
+        uheapq_heap_siftup(heap, --i);
     }
     }
     return mp_const_none;
     return mp_const_none;
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = {
 STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) },
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) },
     { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) },
     { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) },
@@ -116,5 +117,6 @@ const mp_obj_module_t mp_module_uheapq = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
     .globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
 };
 };
+#endif
 
 
 #endif //MICROPY_PY_UHEAPQ
 #endif //MICROPY_PY_UHEAPQ

+ 5 - 5
extmod/modujson.c

@@ -3,7 +3,7 @@
  *
  *
  * The MIT License (MIT)
  * The MIT License (MIT)
  *
  *
- * Copyright (c) 2014-2016 Damien P. George
+ * Copyright (c) 2014-2019 Damien P. George
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -185,7 +185,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
                     cur = S_CUR(s);
                     cur = S_CUR(s);
                     if (cur == '.' || cur == 'E' || cur == 'e') {
                     if (cur == '.' || cur == 'E' || cur == 'e') {
                         flt = true;
                         flt = true;
-                    } else if (cur == '-' || unichar_isdigit(cur)) {
+                    } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) {
                         // pass
                         // pass
                     } else {
                     } else {
                         break;
                         break;
@@ -281,9 +281,9 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load);
 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) {
 STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
-    size_t len;
-    const char *buf = mp_obj_str_get_data(obj, &len);
-    vstr_t vstr = {len, len, (char*)buf, true};
+    mp_buffer_info_t bufinfo;
+    mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ);
+    vstr_t vstr = {bufinfo.len, bufinfo.len, (char*)bufinfo.buf, true};
     mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
     mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
     return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));
     return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));
 }
 }

+ 15 - 0
extmod/modurandom.c

@@ -36,8 +36,10 @@
 // http://www.literatecode.com/yasmarang
 // http://www.literatecode.com/yasmarang
 // Public Domain
 // Public Domain
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
 STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
 STATIC uint8_t yasmarang_dat = 0;
 STATIC uint8_t yasmarang_dat = 0;
+#endif
 
 
 STATIC uint32_t yasmarang(void)
 STATIC uint32_t yasmarang(void)
 {
 {
@@ -200,8 +202,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
 
 
 #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
 #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
 
 
+#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+STATIC mp_obj_t mod_urandom___init__() {
+    mod_urandom_seed(MP_OBJ_NEW_SMALL_INT(MICROPY_PY_URANDOM_SEED_INIT_FUNC));
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__);
+#endif
+
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
 STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
+    #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+    { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) },
+    #endif
     { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },
     { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },
     { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) },
     { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) },
     #if MICROPY_PY_URANDOM_EXTRA_FUNCS
     #if MICROPY_PY_URANDOM_EXTRA_FUNCS
@@ -221,5 +235,6 @@ const mp_obj_module_t mp_module_urandom = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&mp_module_urandom_globals,
     .globals = (mp_obj_dict_t*)&mp_module_urandom_globals,
 };
 };
+#endif
 
 
 #endif //MICROPY_PY_URANDOM
 #endif //MICROPY_PY_URANDOM

+ 15 - 0
extmod/modure.c

@@ -144,6 +144,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end);
 
 
 #endif
 #endif
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t match_locals_dict_table[] = {
 STATIC const mp_rom_map_elem_t match_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },
     { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },
     #if MICROPY_PY_URE_MATCH_GROUPS
     #if MICROPY_PY_URE_MATCH_GROUPS
@@ -164,6 +165,7 @@ STATIC const mp_obj_type_t match_type = {
     .print = match_print,
     .print = match_print,
     .locals_dict = (void*)&match_locals_dict,
     .locals_dict = (void*)&match_locals_dict,
 };
 };
+#endif
 
 
 STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
 STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     (void)kind;
     (void)kind;
@@ -363,6 +365,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub);
 
 
 #endif
 #endif
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t re_locals_dict_table[] = {
 STATIC const mp_rom_map_elem_t re_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
     { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
     { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
     { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
@@ -380,8 +383,10 @@ STATIC const mp_obj_type_t re_type = {
     .print = re_print,
     .print = re_print,
     .locals_dict = (void*)&re_locals_dict,
     .locals_dict = (void*)&re_locals_dict,
 };
 };
+#endif
 
 
 STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
 STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
+    (void)n_args;
     const char *re_str = mp_obj_str_get_str(args[0]);
     const char *re_str = mp_obj_str_get_str(args[0]);
     int size = re1_5_sizecode(re_str);
     int size = re1_5_sizecode(re_str);
     if (size == -1) {
     if (size == -1) {
@@ -389,18 +394,22 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
     }
     }
     mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
     mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
     o->base.type = &re_type;
     o->base.type = &re_type;
+    #if MICROPY_PY_URE_DEBUG
     int flags = 0;
     int flags = 0;
     if (n_args > 1) {
     if (n_args > 1) {
         flags = mp_obj_get_int(args[1]);
         flags = mp_obj_get_int(args[1]);
     }
     }
+    #endif
     int error = re1_5_compilecode(&o->re, re_str);
     int error = re1_5_compilecode(&o->re, re_str);
     if (error != 0) {
     if (error != 0) {
 error:
 error:
         mp_raise_ValueError("Error in regex");
         mp_raise_ValueError("Error in regex");
     }
     }
+    #if MICROPY_PY_URE_DEBUG
     if (flags & FLAG_DEBUG) {
     if (flags & FLAG_DEBUG) {
         re1_5_dumpcode(&o->re);
         re1_5_dumpcode(&o->re);
     }
     }
+    #endif
     return MP_OBJ_FROM_PTR(o);
     return MP_OBJ_FROM_PTR(o);
 }
 }
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
@@ -432,6 +441,7 @@ STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) {
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
 #endif
 #endif
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
 STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) },
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) },
     { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
     { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
@@ -440,7 +450,9 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
     #if MICROPY_PY_URE_SUB
     #if MICROPY_PY_URE_SUB
     { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
     { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
     #endif
     #endif
+    #if MICROPY_PY_URE_DEBUG
     { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
     { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
+    #endif
 };
 };
 
 
 STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
 STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
@@ -449,13 +461,16 @@ const mp_obj_module_t mp_module_ure = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&mp_module_re_globals,
     .globals = (mp_obj_dict_t*)&mp_module_re_globals,
 };
 };
+#endif
 
 
 // Source files #include'd here to make sure they're compiled in
 // Source files #include'd here to make sure they're compiled in
 // only if module is enabled by config setting.
 // only if module is enabled by config setting.
 
 
 #define re1_5_fatal(x) assert(!x)
 #define re1_5_fatal(x) assert(!x)
 #include "re1.5/compilecode.c"
 #include "re1.5/compilecode.c"
+#if MICROPY_PY_URE_DEBUG
 #include "re1.5/dumpcode.c"
 #include "re1.5/dumpcode.c"
+#endif
 #include "re1.5/recursiveloop.c"
 #include "re1.5/recursiveloop.c"
 #include "re1.5/charclass.c"
 #include "re1.5/charclass.c"
 
 

+ 3 - 2
extmod/moduselect.c

@@ -4,6 +4,7 @@
  * The MIT License (MIT)
  * The MIT License (MIT)
  *
  *
  * Copyright (c) 2014 Damien P. George
  * Copyright (c) 2014 Damien P. George
+ * Copyright (c) 2015-2017 Paul Sokolovsky
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -111,7 +112,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
 }
 }
 
 
 /// \function select(rlist, wlist, xlist[, timeout])
 /// \function select(rlist, wlist, xlist[, timeout])
-STATIC mp_obj_t select_select(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
     // get array data from tuple/list arguments
     // get array data from tuple/list arguments
     size_t rwx_len[3];
     size_t rwx_len[3];
     mp_obj_t *r_array, *w_array, *x_array;
     mp_obj_t *r_array, *w_array, *x_array;
@@ -190,7 +191,7 @@ typedef struct _mp_obj_poll_t {
 } mp_obj_poll_t;
 } mp_obj_poll_t;
 
 
 /// \method register(obj[, eventmask])
 /// \method register(obj[, eventmask])
-STATIC mp_obj_t poll_register(uint n_args, const mp_obj_t *args) {
+STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
     mp_uint_t flags;
     mp_uint_t flags;
     if (n_args == 3) {
     if (n_args == 3) {

+ 49 - 32
extmod/modussl_axtls.c

@@ -3,7 +3,7 @@
  *
  *
  * The MIT License (MIT)
  * The MIT License (MIT)
  *
  *
- * Copyright (c) 2015-2017 Paul Sokolovsky
+ * Copyright (c) 2015-2019 Paul Sokolovsky
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -41,6 +41,7 @@ typedef struct _mp_obj_ssl_socket_t {
     SSL *ssl_sock;
     SSL *ssl_sock;
     byte *buf;
     byte *buf;
     uint32_t bytes_left;
     uint32_t bytes_left;
+    bool blocking;
 } mp_obj_ssl_socket_t;
 } mp_obj_ssl_socket_t;
 
 
 struct ssl_args {
 struct ssl_args {
@@ -48,11 +49,12 @@ struct ssl_args {
     mp_arg_val_t cert;
     mp_arg_val_t cert;
     mp_arg_val_t server_side;
     mp_arg_val_t server_side;
     mp_arg_val_t server_hostname;
     mp_arg_val_t server_hostname;
+    mp_arg_val_t do_handshake;
 };
 };
 
 
 STATIC const mp_obj_type_t ussl_socket_type;
 STATIC const mp_obj_type_t ussl_socket_type;
 
 
-STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
+STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) {
 #if MICROPY_PY_USSL_FINALISER
 #if MICROPY_PY_USSL_FINALISER
     mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
     mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
 #else
 #else
@@ -62,8 +64,12 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
     o->buf = NULL;
     o->buf = NULL;
     o->bytes_left = 0;
     o->bytes_left = 0;
     o->sock = sock;
     o->sock = sock;
+    o->blocking = true;
 
 
     uint32_t options = SSL_SERVER_VERIFY_LATER;
     uint32_t options = SSL_SERVER_VERIFY_LATER;
+    if (!args->do_handshake.u_bool) {
+        options |= SSL_CONNECT_IN_PARTS;
+    }
     if (args->key.u_obj != mp_const_none) {
     if (args->key.u_obj != mp_const_none) {
         options |= SSL_NO_DEFAULT_KEY;
         options |= SSL_NO_DEFAULT_KEY;
     }
     }
@@ -97,17 +103,14 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
 
 
         o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext);
         o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext);
 
 
-        int res = ssl_handshake_status(o->ssl_sock);
-        // Pointer to SSL_EXTENSIONS as being passed to ssl_client_new()
-        // is saved in ssl_sock->extensions.
-        // As of axTLS 2.1.3, extensions aren't used beyond the initial
-        // handshake, and that's pretty much how it's expected to be. So
-        // we allocate them on stack and reset the pointer after handshake.
+        if (args->do_handshake.u_bool) {
+            int res = ssl_handshake_status(o->ssl_sock);
 
 
-        if (res != SSL_OK) {
-            printf("ssl_handshake_status: %d\n", res);
-            ssl_display_error(res);
-            mp_raise_OSError(MP_EIO);
+            if (res != SSL_OK) {
+                printf("ssl_handshake_status: %d\n", res);
+                ssl_display_error(res);
+                mp_raise_OSError(MP_EIO);
+            }
         }
         }
 
 
     }
     }
@@ -115,13 +118,13 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
     return o;
     return o;
 }
 }
 
 
-STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     (void)kind;
     (void)kind;
     mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
     mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
     mp_printf(print, "<_SSLSocket %p>", self->ssl_sock);
     mp_printf(print, "<_SSLSocket %p>", self->ssl_sock);
 }
 }
 
 
-STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+STATIC mp_uint_t ussl_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);
     mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
 
 
     if (o->ssl_sock == NULL) {
     if (o->ssl_sock == NULL) {
@@ -133,8 +136,18 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
         mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
         mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
         if (r == SSL_OK) {
         if (r == SSL_OK) {
             // SSL_OK from ssl_read() means "everything is ok, but there's
             // SSL_OK from ssl_read() means "everything is ok, but there's
-            // no user data yet". So, we just keep reading.
-            continue;
+            // no user data yet". It may happen e.g. if handshake is not
+            // finished yet. The best way we can treat it is by returning
+            // EAGAIN. This may be a bit unexpected in blocking mode, but
+            // default is to perform complete handshake in constructor, so
+            // this should not happen in blocking mode. On the other hand,
+            // in nonblocking mode EAGAIN (comparing to the alternative of
+            // looping) is really preferrable.
+            if (o->blocking) {
+                continue;
+            } else {
+                goto eagain;
+            }
         }
         }
         if (r < 0) {
         if (r < 0) {
             if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
             if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
@@ -142,6 +155,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
                 return 0;
                 return 0;
             }
             }
             if (r == SSL_EAGAIN) {
             if (r == SSL_EAGAIN) {
+eagain:
                 r = MP_EAGAIN;
                 r = MP_EAGAIN;
             }
             }
             *errcode = r;
             *errcode = r;
@@ -159,7 +173,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
     return size;
     return size;
 }
 }
 
 
-STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
+STATIC mp_uint_t ussl_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);
     mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
 
 
     if (o->ssl_sock == NULL) {
     if (o->ssl_sock == NULL) {
@@ -175,7 +189,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
     return r;
     return r;
 }
 }
 
 
-STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+STATIC mp_uint_t ussl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
     mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
     mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
     if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {
     if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {
         ssl_free(self->ssl_sock);
         ssl_free(self->ssl_sock);
@@ -186,22 +200,24 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
     return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
     return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
 }
 }
 
 
-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_raise_NotImplementedError(NULL);
-    }
-    return mp_const_none;
+STATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
+    mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
+    mp_obj_t sock = o->sock;
+    mp_obj_t dest[3];
+    mp_load_method(sock, MP_QSTR_setblocking, dest);
+    dest[2] = flag_in;
+    mp_obj_t res = mp_call_method_n_kw(1, 0, dest);
+    o->blocking = mp_obj_is_true(flag_in);
+    return res;
 }
 }
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking);
 
 
 STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
 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_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_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_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_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_setblocking), MP_ROM_PTR(&ussl_socket_setblocking_obj) },
     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
 #if MICROPY_PY_USSL_FINALISER
 #if MICROPY_PY_USSL_FINALISER
     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
@@ -211,16 +227,16 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
 STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
 STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
 
 
 STATIC const mp_stream_p_t ussl_socket_stream_p = {
 STATIC const mp_stream_p_t ussl_socket_stream_p = {
-    .read = socket_read,
-    .write = socket_write,
-    .ioctl = socket_ioctl,
+    .read = ussl_socket_read,
+    .write = ussl_socket_write,
+    .ioctl = ussl_socket_ioctl,
 };
 };
 
 
 STATIC const mp_obj_type_t ussl_socket_type = {
 STATIC const mp_obj_type_t ussl_socket_type = {
     { &mp_type_type },
     { &mp_type_type },
     // Save on qstr's, reuse same as for module
     // Save on qstr's, reuse same as for module
     .name = MP_QSTR_ussl,
     .name = MP_QSTR_ussl,
-    .print = socket_print,
+    .print = ussl_socket_print,
     .getiter = NULL,
     .getiter = NULL,
     .iternext = NULL,
     .iternext = NULL,
     .protocol = &ussl_socket_stream_p,
     .protocol = &ussl_socket_stream_p,
@@ -234,6 +250,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_
         { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
         { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
         { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
         { 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_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
         { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
+        { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
     };
     };
 
 
     // TODO: Check that sock implements stream protocol
     // TODO: Check that sock implements stream protocol
@@ -243,7 +260,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_
     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_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);
         MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
 
 
-    return MP_OBJ_FROM_PTR(socket_new(sock, &args));
+    return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args));
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
 
 

+ 41 - 11
extmod/modussl_mbedtls.c

@@ -4,6 +4,7 @@
  * The MIT License (MIT)
  * The MIT License (MIT)
  *
  *
  * Copyright (c) 2016 Linaro Ltd.
  * Copyright (c) 2016 Linaro Ltd.
+ * Copyright (c) 2019 Paul Sokolovsky
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +61,7 @@ struct ssl_args {
     mp_arg_val_t cert;
     mp_arg_val_t cert;
     mp_arg_val_t server_side;
     mp_arg_val_t server_side;
     mp_arg_val_t server_hostname;
     mp_arg_val_t server_hostname;
+    mp_arg_val_t do_handshake;
 };
 };
 
 
 STATIC const mp_obj_type_t ussl_socket_type;
 STATIC const mp_obj_type_t ussl_socket_type;
@@ -167,27 +169,37 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
 
 
     mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
     mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
 
 
-    if (args->key.u_obj != MP_OBJ_NULL) {
+    if (args->key.u_obj != mp_const_none) {
         size_t key_len;
         size_t key_len;
         const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len);
         const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len);
         // len should include terminating null
         // len should include terminating null
         ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
         ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
-        assert(ret == 0);
+        if (ret != 0) {
+            ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
+            goto cleanup;
+        }
 
 
         size_t cert_len;
         size_t cert_len;
         const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
         const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
         // len should include terminating null
         // len should include terminating null
         ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
         ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
-        assert(ret == 0);
+        if (ret != 0) {
+            ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors
+            goto cleanup;
+        }
 
 
         ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
         ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
-        assert(ret == 0);
+        if (ret != 0) {
+            goto cleanup;
+        }
     }
     }
 
 
-    while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
-        if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
-            printf("mbedtls_ssl_handshake error: -%x\n", -ret);
-            goto cleanup;
+    if (args->do_handshake.u_bool) {
+        while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
+            if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+                printf("mbedtls_ssl_handshake error: -%x\n", -ret);
+                goto cleanup;
+            }
         }
         }
     }
     }
 
 
@@ -204,6 +216,10 @@ cleanup:
 
 
     if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
     if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
         mp_raise_OSError(MP_ENOMEM);
         mp_raise_OSError(MP_ENOMEM);
+    } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) {
+        mp_raise_ValueError("invalid key");
+    } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) {
+        mp_raise_ValueError("invalid cert");
     } else {
     } else {
         mp_raise_OSError(MP_EIO);
         mp_raise_OSError(MP_EIO);
     }
     }
@@ -215,6 +231,9 @@ STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
         mp_raise_NotImplementedError(NULL);
         mp_raise_NotImplementedError(NULL);
     }
     }
     const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);
     const mbedtls_x509_crt* peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);
+    if (peer_cert == NULL) {
+        return mp_const_none;
+    }
     return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
     return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
@@ -238,6 +257,11 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
     }
     }
     if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
     if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
         ret = MP_EWOULDBLOCK;
         ret = MP_EWOULDBLOCK;
+    } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+        // If handshake is not finished, read attempt may end up in protocol
+        // wanting to write next handshake message. The same may happen with
+        // renegotation.
+        ret = MP_EWOULDBLOCK;
     }
     }
     *errcode = ret;
     *errcode = ret;
     return MP_STREAM_ERROR;
     return MP_STREAM_ERROR;
@@ -252,6 +276,11 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
     }
     }
     if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
     if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
         ret = MP_EWOULDBLOCK;
         ret = MP_EWOULDBLOCK;
+    } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
+        // If handshake is not finished, write attempt may end up in protocol
+        // wanting to read next handshake message. The same may happen with
+        // renegotation.
+        ret = MP_EWOULDBLOCK;
     }
     }
     *errcode = ret;
     *errcode = ret;
     return MP_STREAM_ERROR;
     return MP_STREAM_ERROR;
@@ -317,10 +346,11 @@ STATIC const mp_obj_type_t ussl_socket_type = {
 STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 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
     // TODO: Implement more args
     static const mp_arg_t allowed_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_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
+        { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
         { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
         { 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} },
+        { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
+        { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
     };
     };
 
 
     // TODO: Check that sock implements stream protocol
     // TODO: Check that sock implements stream protocol

+ 12 - 12
extmod/modutimeq.c

@@ -55,7 +55,7 @@ typedef struct _mp_obj_utimeq_t {
 
 
 STATIC mp_uint_t utimeq_id;
 STATIC mp_uint_t utimeq_id;
 
 
-STATIC mp_obj_utimeq_t *get_heap(mp_obj_t heap_in) {
+STATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) {
     return MP_OBJ_TO_PTR(heap_in);
     return MP_OBJ_TO_PTR(heap_in);
 }
 }
 
 
@@ -85,7 +85,7 @@ STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t
     return MP_OBJ_FROM_PTR(o);
     return MP_OBJ_FROM_PTR(o);
 }
 }
 
 
-STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
+STATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
     struct qentry item = heap->items[pos];
     struct qentry item = heap->items[pos];
     while (pos > start_pos) {
     while (pos > start_pos) {
         mp_uint_t parent_pos = (pos - 1) >> 1;
         mp_uint_t parent_pos = (pos - 1) >> 1;
@@ -101,7 +101,7 @@ STATIC void heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t
     heap->items[pos] = item;
     heap->items[pos] = item;
 }
 }
 
 
-STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
+STATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
     mp_uint_t start_pos = pos;
     mp_uint_t start_pos = pos;
     mp_uint_t end_pos = heap->len;
     mp_uint_t end_pos = heap->len;
     struct qentry item = heap->items[pos];
     struct qentry item = heap->items[pos];
@@ -118,13 +118,13 @@ STATIC void heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
         pos = child_pos;
         pos = child_pos;
     }
     }
     heap->items[pos] = item;
     heap->items[pos] = item;
-    heap_siftdown(heap, start_pos, pos);
+    utimeq_heap_siftdown(heap, start_pos, pos);
 }
 }
 
 
 STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
 STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
     (void)n_args;
     (void)n_args;
     mp_obj_t heap_in = args[0];
     mp_obj_t heap_in = args[0];
-    mp_obj_utimeq_t *heap = get_heap(heap_in);
+    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
     if (heap->len == heap->alloc) {
     if (heap->len == heap->alloc) {
         mp_raise_msg(&mp_type_IndexError, "queue overflow");
         mp_raise_msg(&mp_type_IndexError, "queue overflow");
     }
     }
@@ -133,16 +133,16 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
     heap->items[l].id = utimeq_id++;
     heap->items[l].id = utimeq_id++;
     heap->items[l].callback = args[2];
     heap->items[l].callback = args[2];
     heap->items[l].args = args[3];
     heap->items[l].args = args[3];
-    heap_siftdown(heap, 0, heap->len);
+    utimeq_heap_siftdown(heap, 0, heap->len);
     heap->len++;
     heap->len++;
     return mp_const_none;
     return mp_const_none;
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush);
 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) {
 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);
+    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
     if (heap->len == 0) {
     if (heap->len == 0) {
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
+        mp_raise_msg(&mp_type_IndexError, "empty heap");
     }
     }
     mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
     mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
     if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
     if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
@@ -158,16 +158,16 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
     heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer
     heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer
     heap->items[heap->len].args = MP_OBJ_NULL;
     heap->items[heap->len].args = MP_OBJ_NULL;
     if (heap->len) {
     if (heap->len) {
-        heap_siftup(heap, 0);
+        utimeq_heap_siftup(heap, 0);
     }
     }
     return mp_const_none;
     return mp_const_none;
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
 
 
 STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
 STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
-    mp_obj_utimeq_t *heap = get_heap(heap_in);
+    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
     if (heap->len == 0) {
     if (heap->len == 0) {
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
+        mp_raise_msg(&mp_type_IndexError, "empty heap");
     }
     }
 
 
     struct qentry *item = &heap->items[0];
     struct qentry *item = &heap->items[0];
@@ -177,7 +177,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime);
 
 
 #if DEBUG
 #if DEBUG
 STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
 STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
-    mp_obj_utimeq_t *heap = get_heap(heap_in);
+    mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
     for (int i = 0; i < heap->len; i++) {
     for (int i = 0; i < heap->len; i++) {
         printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time,
         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));
             MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args));

+ 1 - 1
extmod/moduwebsocket.c

@@ -194,7 +194,7 @@ no_payload:
                     if (last_state == CONTROL) {
                     if (last_state == CONTROL) {
                         byte frame_type = self->last_flags & FRAME_OPCODE_MASK;
                         byte frame_type = self->last_flags & FRAME_OPCODE_MASK;
                         if (frame_type == FRAME_CLOSE) {
                         if (frame_type == FRAME_CLOSE) {
-                            static char close_resp[2] = {0x88, 0};
+                            static const char close_resp[2] = {0x88, 0};
                             int err;
                             int err;
                             websocket_write(self_in, close_resp, sizeof(close_resp), &err);
                             websocket_write(self_in, close_resp, sizeof(close_resp), &err);
                             return 0;
                             return 0;

+ 6 - 0
extmod/moduzlib.c

@@ -122,6 +122,7 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er
     return o->decomp.dest - (byte*)buf;
     return o->decomp.dest - (byte*)buf;
 }
 }
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {
 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_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
@@ -129,11 +130,13 @@ STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {
 };
 };
 
 
 STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
 STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
+#endif
 
 
 STATIC const mp_stream_p_t decompio_stream_p = {
 STATIC const mp_stream_p_t decompio_stream_p = {
     .read = decompio_read,
     .read = decompio_read,
 };
 };
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_obj_type_t decompio_type = {
 STATIC const mp_obj_type_t decompio_type = {
     { &mp_type_type },
     { &mp_type_type },
     .name = MP_QSTR_DecompIO,
     .name = MP_QSTR_DecompIO,
@@ -141,6 +144,7 @@ STATIC const mp_obj_type_t decompio_type = {
     .protocol = &decompio_stream_p,
     .protocol = &decompio_stream_p,
     .locals_dict = (void*)&decompio_locals_dict,
     .locals_dict = (void*)&decompio_locals_dict,
 };
 };
+#endif
 
 
 STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
 STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
     mp_obj_t data = args[0];
     mp_obj_t data = args[0];
@@ -201,6 +205,7 @@ error:
 }
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
 
 
+#if !MICROPY_ENABLE_DYNRUNTIME
 STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = {
 STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = {
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) },
     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) },
     { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) },
     { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) },
@@ -213,6 +218,7 @@ const mp_obj_module_t mp_module_uzlib = {
     .base = { &mp_type_module },
     .base = { &mp_type_module },
     .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,
     .globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,
 };
 };
+#endif
 
 
 // Source files #include'd here to make sure they're compiled in
 // Source files #include'd here to make sure they're compiled in
 // only if module is enabled by config setting.
 // only if module is enabled by config setting.

+ 20 - 12
extmod/modwebrepl.c

@@ -67,10 +67,9 @@ typedef struct _mp_obj_webrepl_t {
     mp_obj_t cur_file;
     mp_obj_t cur_file;
 } mp_obj_webrepl_t;
 } mp_obj_webrepl_t;
 
 
-// These get passed to functions which aren't force-l32, so can't be const
-STATIC char passwd_prompt[] = "Password: ";
-STATIC char connected_prompt[] = "\r\nWebREPL connected\r\n>>> ";
-STATIC char denied_prompt[] = "\r\nAccess denied\r\n";
+STATIC const char passwd_prompt[] = "Password: ";
+STATIC const char connected_prompt[] = "\r\nWebREPL connected\r\n>>> ";
+STATIC const char denied_prompt[] = "\r\nAccess denied\r\n";
 
 
 STATIC char webrepl_passwd[10];
 STATIC char webrepl_passwd[10];
 
 
@@ -108,6 +107,15 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_
     return o;
     return o;
 }
 }
 
 
+STATIC void check_file_op_finished(mp_obj_webrepl_t *self) {
+    if (self->data_to_recv == 0) {
+        mp_stream_close(self->cur_file);
+        self->hdr_to_recv = sizeof(struct webrepl_file);
+        DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type);
+        write_webrepl_resp(self->sock, 0);
+    }
+}
+
 STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
 STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
     const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);
     const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);
     byte readbuf[2 + 256];
     byte readbuf[2 + 256];
@@ -129,7 +137,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) {
 
 
     switch (self->hdr.type) {
     switch (self->hdr.type) {
         case GET_VER: {
         case GET_VER: {
-            static char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO};
+            static const char ver[] = {MICROPY_VERSION_MAJOR, MICROPY_VERSION_MINOR, MICROPY_VERSION_MICRO};
             write_webrepl(self->sock, ver, sizeof(ver));
             write_webrepl(self->sock, ver, sizeof(ver));
             self->hdr_to_recv = sizeof(struct webrepl_file);
             self->hdr_to_recv = sizeof(struct webrepl_file);
             return;
             return;
@@ -160,6 +168,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) {
 
 
     if (self->hdr.type == PUT_FILE) {
     if (self->hdr.type == PUT_FILE) {
         self->data_to_recv = self->hdr.size;
         self->data_to_recv = self->hdr.size;
+        check_file_op_finished(self);
     } else if (self->hdr.type == GET_FILE) {
     } else if (self->hdr.type == GET_FILE) {
         self->data_to_recv = 1;
         self->data_to_recv = 1;
     }
     }
@@ -236,7 +245,11 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int
     }
     }
 
 
     if (self->data_to_recv != 0) {
     if (self->data_to_recv != 0) {
-        static byte filebuf[512];
+        // Ports that don't have much available stack can make this filebuf static
+        #if MICROPY_PY_WEBREPL_STATIC_FILEBUF
+        static
+        #endif
+        byte filebuf[512];
         filebuf[0] = *(byte*)buf;
         filebuf[0] = *(byte*)buf;
         mp_uint_t buf_sz = 1;
         mp_uint_t buf_sz = 1;
         if (--self->data_to_recv != 0) {
         if (--self->data_to_recv != 0) {
@@ -266,12 +279,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int
             }
             }
         }
         }
 
 
-        if (self->data_to_recv == 0) {
-            mp_stream_close(self->cur_file);
-            self->hdr_to_recv = sizeof(struct webrepl_file);
-            DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type);
-            write_webrepl_resp(self->sock, 0);
-        }
+        check_file_op_finished(self);
 
 
         #ifdef MICROPY_PY_WEBREPL_DELAY
         #ifdef MICROPY_PY_WEBREPL_DELAY
         // Some platforms may have broken drivers and easily gets
         // Some platforms may have broken drivers and easily gets

+ 65 - 1
extmod/uos_dupterm.c

@@ -4,7 +4,7 @@
  * The MIT License (MIT)
  * The MIT License (MIT)
  *
  *
  * Copyright (c) 2016 Paul Sokolovsky
  * Copyright (c) 2016 Paul Sokolovsky
- * Copyright (c) 2017 Damien P. George
+ * Copyright (c) 2017-2019 Damien P. George
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +32,7 @@
 #include "py/objtuple.h"
 #include "py/objtuple.h"
 #include "py/objarray.h"
 #include "py/objarray.h"
 #include "py/stream.h"
 #include "py/stream.h"
+#include "extmod/misc.h"
 #include "lib/utils/interrupt_char.h"
 #include "lib/utils/interrupt_char.h"
 
 
 #if MICROPY_PY_OS_DUPTERM
 #if MICROPY_PY_OS_DUPTERM
@@ -52,12 +53,65 @@ void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
     }
     }
 }
 }
 
 
+uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) {
+    uintptr_t poll_flags_out = 0;
+
+    for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+        mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]);
+        if (s == MP_OBJ_NULL) {
+            continue;
+        }
+
+        int errcode = 0;
+        mp_uint_t ret = 0;
+        const mp_stream_p_t *stream_p = mp_get_stream(s);
+        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
+        if (mp_uos_dupterm_is_builtin_stream(s)) {
+            ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+        } else
+        #endif
+        {
+            nlr_buf_t nlr;
+            if (nlr_push(&nlr) == 0) {
+                ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+                nlr_pop();
+            } else {
+                // Ignore error with ioctl
+            }
+        }
+
+        if (ret != MP_STREAM_ERROR) {
+            poll_flags_out |= ret;
+            if (poll_flags_out == poll_flags) {
+                // Finish early if all requested flags are set
+                break;
+            }
+        }
+    }
+
+    return poll_flags_out;
+}
+
 int mp_uos_dupterm_rx_chr(void) {
 int mp_uos_dupterm_rx_chr(void) {
     for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
     for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
         if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
         if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
             continue;
             continue;
         }
         }
 
 
+        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
+        if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
+            byte buf[1];
+            int errcode = 0;
+            const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+            mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
+            if (errcode == 0 && out_sz != 0) {
+                return buf[0];
+             } else {
+                continue;
+             }
+        }
+        #endif
+
         nlr_buf_t nlr;
         nlr_buf_t nlr;
         if (nlr_push(&nlr) == 0) {
         if (nlr_push(&nlr) == 0) {
             byte buf[1];
             byte buf[1];
@@ -98,6 +152,16 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
         if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
         if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
             continue;
             continue;
         }
         }
+
+        #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
+        if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
+            int errcode = 0;
+            const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+            stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode);
+            continue;
+        }
+        #endif
+
         nlr_buf_t nlr;
         nlr_buf_t nlr;
         if (nlr_push(&nlr) == 0) {
         if (nlr_push(&nlr) == 0) {
             mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);
             mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);

+ 43 - 4
extmod/vfs.c

@@ -38,6 +38,10 @@
 #include "extmod/vfs_fat.h"
 #include "extmod/vfs_fat.h"
 #endif
 #endif
 
 
+#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
+#include "extmod/vfs_lfs.h"
+#endif
+
 #if MICROPY_VFS_POSIX
 #if MICROPY_VFS_POSIX
 #include "extmod/vfs_posix.h"
 #include "extmod/vfs_posix.h"
 #endif
 #endif
@@ -156,6 +160,44 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) {
     }
     }
 }
 }
 
 
+STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
+    #if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
+    nlr_buf_t nlr;
+    if (nlr_push(&nlr) == 0) {
+        mp_obj_t vfs = MP_OBJ_NULL;
+        mp_vfs_blockdev_t blockdev;
+        mp_vfs_blockdev_init(&blockdev, bdev_obj);
+        uint8_t buf[44];
+        mp_vfs_blockdev_read_ext(&blockdev, 0, 8, sizeof(buf), buf);
+        #if MICROPY_VFS_LFS1
+        if (memcmp(&buf[32], "littlefs", 8) == 0) {
+            // LFS1
+            vfs = mp_type_vfs_lfs1.make_new(&mp_type_vfs_lfs1, 1, 0, &bdev_obj);
+            nlr_pop();
+            return vfs;
+        }
+        #endif
+        #if MICROPY_VFS_LFS2
+        if (memcmp(&buf[0], "littlefs", 8) == 0) {
+            // LFS2
+            vfs = mp_type_vfs_lfs2.make_new(&mp_type_vfs_lfs2, 1, 0, &bdev_obj);
+            nlr_pop();
+            return vfs;
+        }
+        #endif
+        nlr_pop();
+    } else {
+        // Ignore exception (eg block device doesn't support extended readblocks)
+    }
+    #endif
+
+    #if MICROPY_VFS_FAT
+    return mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &bdev_obj);
+    #endif
+
+    return bdev_obj;
+}
+
 mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
 mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     enum { ARG_readonly, ARG_mkfs };
     enum { ARG_readonly, ARG_mkfs };
     static const mp_arg_t allowed_args[] = {
     static const mp_arg_t allowed_args[] = {
@@ -178,10 +220,7 @@ mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
     if (dest[0] == MP_OBJ_NULL) {
     if (dest[0] == MP_OBJ_NULL) {
         // Input object has no mount method, assume it's a block device and try to
         // Input object has no mount method, assume it's a block device and try to
         // auto-detect the filesystem and create the corresponding VFS entity.
         // auto-detect the filesystem and create the corresponding VFS entity.
-        // (At the moment we only support FAT filesystems.)
-        #if MICROPY_VFS_FAT
-        vfs_obj = mp_fat_vfs_type.make_new(&mp_fat_vfs_type, 1, 0, &vfs_obj);
-        #endif
+        vfs_obj = mp_vfs_autodetect(vfs_obj);
     }
     }
 
 
     // create new object
     // create new object

+ 34 - 5
extmod/vfs.h

@@ -38,18 +38,40 @@
 #define MP_S_IFDIR (0x4000)
 #define MP_S_IFDIR (0x4000)
 #define MP_S_IFREG (0x8000)
 #define MP_S_IFREG (0x8000)
 
 
+// these are the values for mp_vfs_blockdev_t.flags
+#define MP_BLOCKDEV_FLAG_NATIVE         (0x0001) // readblocks[2]/writeblocks[2] contain native func
+#define MP_BLOCKDEV_FLAG_FREE_OBJ       (0x0002) // fs_user_mount_t obj should be freed on umount
+#define MP_BLOCKDEV_FLAG_HAVE_IOCTL     (0x0004) // new protocol with ioctl
+#define MP_BLOCKDEV_FLAG_NO_FILESYSTEM  (0x0008) // the block device has no filesystem on it
+
 // constants for block protocol ioctl
 // constants for block protocol ioctl
-#define BP_IOCTL_INIT           (1)
-#define BP_IOCTL_DEINIT         (2)
-#define BP_IOCTL_SYNC           (3)
-#define BP_IOCTL_SEC_COUNT      (4)
-#define BP_IOCTL_SEC_SIZE       (5)
+#define MP_BLOCKDEV_IOCTL_INIT          (1)
+#define MP_BLOCKDEV_IOCTL_DEINIT        (2)
+#define MP_BLOCKDEV_IOCTL_SYNC          (3)
+#define MP_BLOCKDEV_IOCTL_BLOCK_COUNT   (4)
+#define MP_BLOCKDEV_IOCTL_BLOCK_SIZE    (5)
+#define MP_BLOCKDEV_IOCTL_BLOCK_ERASE   (6)
 
 
 // At the moment the VFS protocol just has import_stat, but could be extended to other methods
 // At the moment the VFS protocol just has import_stat, but could be extended to other methods
 typedef struct _mp_vfs_proto_t {
 typedef struct _mp_vfs_proto_t {
     mp_import_stat_t (*import_stat)(void *self, const char *path);
     mp_import_stat_t (*import_stat)(void *self, const char *path);
 } mp_vfs_proto_t;
 } mp_vfs_proto_t;
 
 
+typedef struct _mp_vfs_blockdev_t {
+    uint16_t flags;
+    size_t block_size;
+    mp_obj_t readblocks[5];
+    mp_obj_t writeblocks[5];
+    // new protocol uses just ioctl, old uses sync (optional) and count
+    union {
+        mp_obj_t ioctl[4];
+        struct {
+            mp_obj_t sync[2];
+            mp_obj_t count[2];
+        } old;
+    } u;
+} mp_vfs_blockdev_t;
+
 typedef struct _mp_vfs_mount_t {
 typedef struct _mp_vfs_mount_t {
     const char *str; // mount point with leading /
     const char *str; // mount point with leading /
     size_t len;
     size_t len;
@@ -57,6 +79,13 @@ typedef struct _mp_vfs_mount_t {
     struct _mp_vfs_mount_t *next;
     struct _mp_vfs_mount_t *next;
 } mp_vfs_mount_t;
 } mp_vfs_mount_t;
 
 
+void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev);
+int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf);
+int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf);
+int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf);
+int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, const uint8_t *buf);
+mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg);
+
 mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out);
 mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out);
 mp_import_stat_t mp_vfs_import_stat(const char *path);
 mp_import_stat_t mp_vfs_import_stat(const char *path);
 mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
 mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);

+ 16 - 22
extmod/vfs_fat.c

@@ -39,8 +39,8 @@
 #include "extmod/vfs_fat.h"
 #include "extmod/vfs_fat.h"
 #include "lib/timeutils/timeutils.h"
 #include "lib/timeutils/timeutils.h"
 
 
-#if _MAX_SS == _MIN_SS
-#define SECSIZE(fs) (_MIN_SS)
+#if FF_MAX_SS == FF_MIN_SS
+#define SECSIZE(fs) (FF_MIN_SS)
 #else
 #else
 #define SECSIZE(fs) ((fs)->ssize)
 #define SECSIZE(fs) ((fs)->ssize)
 #endif
 #endif
@@ -68,27 +68,18 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_
     // create new object
     // create new object
     fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t);
     fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t);
     vfs->base.type = type;
     vfs->base.type = type;
-    vfs->flags = FSUSER_FREE_OBJ;
     vfs->fatfs.drv = vfs;
     vfs->fatfs.drv = vfs;
 
 
-    // load block protocol methods
-    mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks);
-    mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks);
-    mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl);
-    if (vfs->u.ioctl[0] != MP_OBJ_NULL) {
-        // device supports new block protocol, so indicate it
-        vfs->flags |= FSUSER_HAVE_IOCTL;
-    } else {
-        // no ioctl method, so assume the device uses the old block protocol
-        mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync);
-        mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count);
-    }
+    // Initialise underlying block device
+    vfs->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ;
+    vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE
+    mp_vfs_blockdev_init(&vfs->blockdev, args[0]);
 
 
     // mount the block device so the VFS methods can be used
     // mount the block device so the VFS methods can be used
     FRESULT res = f_mount(&vfs->fatfs);
     FRESULT res = f_mount(&vfs->fatfs);
     if (res == FR_NO_FILESYSTEM) {
     if (res == FR_NO_FILESYSTEM) {
         // don't error out if no filesystem, to let mkfs()/mount() create one if wanted
         // don't error out if no filesystem, to let mkfs()/mount() create one if wanted
-        vfs->flags |= FSUSER_NO_FILESYSTEM;
+        vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_NO_FILESYSTEM;
     } else if (res != FR_OK) {
     } else if (res != FR_OK) {
         mp_raise_OSError(fresult_to_errno_table[res]);
         mp_raise_OSError(fresult_to_errno_table[res]);
     }
     }
@@ -111,8 +102,11 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
     fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));
     fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));
 
 
     // make the filesystem
     // make the filesystem
-    uint8_t working_buf[_MAX_SS];
+    uint8_t working_buf[FF_MAX_SS];
     FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
     FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
+    if (res == FR_MKFS_ABORTED) { // Probably doesn't support FAT16
+        res = f_mkfs(&vfs->fatfs, FM_FAT32, 0, working_buf, sizeof(working_buf));
+    }
     if (res != FR_OK) {
     if (res != FR_OK) {
         mp_raise_OSError(fresult_to_errno_table[res]);
         mp_raise_OSError(fresult_to_errno_table[res]);
     }
     }
@@ -363,7 +357,7 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) {
     t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
     t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
     t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
     t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
     t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
     t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
-    t->items[9] = MP_OBJ_NEW_SMALL_INT(_MAX_LFN); // f_namemax
+    t->items[9] = MP_OBJ_NEW_SMALL_INT(FF_MAX_LFN); // f_namemax
 
 
     return MP_OBJ_FROM_PTR(t);
     return MP_OBJ_FROM_PTR(t);
 }
 }
@@ -377,19 +371,19 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
     //  1. readonly=True keyword argument
     //  1. readonly=True keyword argument
     //  2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)
     //  2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already)
     if (mp_obj_is_true(readonly)) {
     if (mp_obj_is_true(readonly)) {
-        self->writeblocks[0] = MP_OBJ_NULL;
+        self->blockdev.writeblocks[0] = MP_OBJ_NULL;
     }
     }
 
 
     // check if we need to make the filesystem
     // check if we need to make the filesystem
-    FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;
+    FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;
     if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {
     if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {
-        uint8_t working_buf[_MAX_SS];
+        uint8_t working_buf[FF_MAX_SS];
         res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
         res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
     }
     }
     if (res != FR_OK) {
     if (res != FR_OK) {
         mp_raise_OSError(fresult_to_errno_table[res]);
         mp_raise_OSError(fresult_to_errno_table[res]);
     }
     }
-    self->flags &= ~FSUSER_NO_FILESYSTEM;
+    self->blockdev.flags &= ~MP_BLOCKDEV_FLAG_NO_FILESYSTEM;
 
 
     return mp_const_none;
     return mp_const_none;
 }
 }

+ 1 - 18
extmod/vfs_fat.h

@@ -26,30 +26,13 @@
 #ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H
 #ifndef MICROPY_INCLUDED_EXTMOD_VFS_FAT_H
 #define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H
 #define MICROPY_INCLUDED_EXTMOD_VFS_FAT_H
 
 
-#include "py/lexer.h"
 #include "py/obj.h"
 #include "py/obj.h"
 #include "lib/oofatfs/ff.h"
 #include "lib/oofatfs/ff.h"
 #include "extmod/vfs.h"
 #include "extmod/vfs.h"
 
 
-// these are the values for fs_user_mount_t.flags
-#define FSUSER_NATIVE       (0x0001) // readblocks[2]/writeblocks[2] contain native func
-#define FSUSER_FREE_OBJ     (0x0002) // fs_user_mount_t obj should be freed on umount
-#define FSUSER_HAVE_IOCTL   (0x0004) // new protocol with ioctl
-#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it
-
 typedef struct _fs_user_mount_t {
 typedef struct _fs_user_mount_t {
     mp_obj_base_t base;
     mp_obj_base_t base;
-    uint16_t flags;
-    mp_obj_t readblocks[4];
-    mp_obj_t writeblocks[4];
-    // new protocol uses just ioctl, old uses sync (optional) and count
-    union {
-        mp_obj_t ioctl[4];
-        struct {
-            mp_obj_t sync[2];
-            mp_obj_t count[2];
-        } old;
-    } u;
+    mp_vfs_blockdev_t blockdev;
     FATFS fatfs;
     FATFS fatfs;
 } fs_user_mount_t;
 } fs_user_mount_t;
 
 

+ 18 - 73
extmod/vfs_fat_diskio.c

@@ -38,16 +38,11 @@
 #include "py/runtime.h"
 #include "py/runtime.h"
 #include "py/binary.h"
 #include "py/binary.h"
 #include "py/objarray.h"
 #include "py/objarray.h"
+#include "py/mperrno.h"
 #include "lib/oofatfs/ff.h"
 #include "lib/oofatfs/ff.h"
 #include "lib/oofatfs/diskio.h"
 #include "lib/oofatfs/diskio.h"
 #include "extmod/vfs_fat.h"
 #include "extmod/vfs_fat.h"
 
 
-#if _MAX_SS == _MIN_SS
-#define SECSIZE(fs) (_MIN_SS)
-#else
-#define SECSIZE(fs) ((fs)->ssize)
-#endif
-
 typedef void *bdev_t;
 typedef void *bdev_t;
 STATIC fs_user_mount_t *disk_get_device(void *bdev) {
 STATIC fs_user_mount_t *disk_get_device(void *bdev) {
     return (fs_user_mount_t*)bdev;
     return (fs_user_mount_t*)bdev;
@@ -69,20 +64,9 @@ DRESULT disk_read (
         return RES_PARERR;
         return RES_PARERR;
     }
     }
 
 
-    if (vfs->flags & FSUSER_NATIVE) {
-        mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->readblocks[2];
-        if (f(buff, sector, count) != 0) {
-            return RES_ERROR;
-        }
-    } else {
-        mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff};
-        vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
-        vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar);
-        mp_call_method_n_kw(2, 0, vfs->readblocks);
-        // TODO handle error return
-    }
+    int ret = mp_vfs_blockdev_read(&vfs->blockdev, sector, count, buff);
 
 
-    return RES_OK;
+    return ret == 0 ? RES_OK : RES_ERROR;
 }
 }
 
 
 /*-----------------------------------------------------------------------*/
 /*-----------------------------------------------------------------------*/
@@ -101,25 +85,14 @@ DRESULT disk_write (
         return RES_PARERR;
         return RES_PARERR;
     }
     }
 
 
-    if (vfs->writeblocks[0] == MP_OBJ_NULL) {
+    int ret = mp_vfs_blockdev_write(&vfs->blockdev, sector, count, buff);
+
+    if (ret == -MP_EROFS) {
         // read-only block device
         // read-only block device
         return RES_WRPRT;
         return RES_WRPRT;
     }
     }
 
 
-    if (vfs->flags & FSUSER_NATIVE) {
-        mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)(uintptr_t)vfs->writeblocks[2];
-        if (f(buff, sector, count) != 0) {
-            return RES_ERROR;
-        }
-    } else {
-        mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff};
-        vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector);
-        vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar);
-        mp_call_method_n_kw(2, 0, vfs->writeblocks);
-        // TODO handle error return
-    }
-
-    return RES_OK;
+    return ret == 0 ? RES_OK : RES_ERROR;
 }
 }
 
 
 
 
@@ -139,42 +112,16 @@ DRESULT disk_ioctl (
     }
     }
 
 
     // First part: call the relevant method of the underlying block device
     // First part: call the relevant method of the underlying block device
+    static const uint8_t op_map[8] = {
+        [CTRL_SYNC] = MP_BLOCKDEV_IOCTL_SYNC,
+        [GET_SECTOR_COUNT] = MP_BLOCKDEV_IOCTL_BLOCK_COUNT,
+        [GET_SECTOR_SIZE] = MP_BLOCKDEV_IOCTL_BLOCK_SIZE,
+        [IOCTL_INIT] = MP_BLOCKDEV_IOCTL_INIT,
+    };
+    uint8_t bp_op = op_map[cmd & 7];
     mp_obj_t ret = mp_const_none;
     mp_obj_t ret = mp_const_none;
-    if (vfs->flags & FSUSER_HAVE_IOCTL) {
-        // new protocol with ioctl
-        static const uint8_t op_map[8] = {
-            [CTRL_SYNC] = BP_IOCTL_SYNC,
-            [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT,
-            [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE,
-            [IOCTL_INIT] = BP_IOCTL_INIT,
-        };
-        uint8_t bp_op = op_map[cmd & 7];
-        if (bp_op != 0) {
-            vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op);
-            vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused
-            ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl);
-        }
-    } else {
-        // old protocol with sync and count
-        switch (cmd) {
-            case CTRL_SYNC:
-                if (vfs->u.old.sync[0] != MP_OBJ_NULL) {
-                    mp_call_method_n_kw(0, 0, vfs->u.old.sync);
-                }
-                break;
-
-            case GET_SECTOR_COUNT:
-                ret = mp_call_method_n_kw(0, 0, vfs->u.old.count);
-                break;
-
-            case GET_SECTOR_SIZE:
-                // old protocol has fixed sector size of 512 bytes
-                break;
-
-            case IOCTL_INIT:
-                // old protocol doesn't have init
-                break;
-        }
+    if (bp_op != 0) {
+        ret = mp_vfs_blockdev_ioctl(&vfs->blockdev, bp_op, 0);
     }
     }
 
 
     // Second part: convert the result for return
     // Second part: convert the result for return
@@ -194,10 +141,8 @@ DRESULT disk_ioctl (
             } else {
             } else {
                 *((WORD*)buff) = mp_obj_get_int(ret);
                 *((WORD*)buff) = mp_obj_get_int(ret);
             }
             }
-            #if _MAX_SS != _MIN_SS
             // need to store ssize because we use it in disk_read/disk_write
             // need to store ssize because we use it in disk_read/disk_write
-            vfs->fatfs.ssize = *((WORD*)buff);
-            #endif
+            vfs->blockdev.block_size = *((WORD*)buff);
             return RES_OK;
             return RES_OK;
         }
         }
 
 
@@ -211,7 +156,7 @@ DRESULT disk_ioctl (
             if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
             if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) {
                 // error initialising
                 // error initialising
                 stat = STA_NOINIT;
                 stat = STA_NOINIT;
-            } else if (vfs->writeblocks[0] == MP_OBJ_NULL) {
+            } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) {
                 stat = STA_PROTECT;
                 stat = STA_PROTECT;
             } else {
             } else {
                 stat = 0;
                 stat = 0;

+ 8 - 8
extmod/vfs_fat_file.c

@@ -219,7 +219,7 @@ STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size
 
 
 // TODO gc hook to close the file if not already closed
 // TODO gc hook to close the file if not already closed
 
 
-STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
+STATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_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_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
@@ -234,10 +234,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
     { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
 };
 };
 
 
-STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
+STATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table);
 
 
 #if MICROPY_PY_IO_FILEIO
 #if MICROPY_PY_IO_FILEIO
-STATIC const mp_stream_p_t fileio_stream_p = {
+STATIC const mp_stream_p_t vfs_fat_fileio_stream_p = {
     .read = file_obj_read,
     .read = file_obj_read,
     .write = file_obj_write,
     .write = file_obj_write,
     .ioctl = file_obj_ioctl,
     .ioctl = file_obj_ioctl,
@@ -250,12 +250,12 @@ const mp_obj_type_t mp_type_vfs_fat_fileio = {
     .make_new = file_obj_make_new,
     .make_new = file_obj_make_new,
     .getiter = mp_identity_getiter,
     .getiter = mp_identity_getiter,
     .iternext = mp_stream_unbuffered_iter,
     .iternext = mp_stream_unbuffered_iter,
-    .protocol = &fileio_stream_p,
-    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+    .protocol = &vfs_fat_fileio_stream_p,
+    .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,
 };
 };
 #endif
 #endif
 
 
-STATIC const mp_stream_p_t textio_stream_p = {
+STATIC const mp_stream_p_t vfs_fat_textio_stream_p = {
     .read = file_obj_read,
     .read = file_obj_read,
     .write = file_obj_write,
     .write = file_obj_write,
     .ioctl = file_obj_ioctl,
     .ioctl = file_obj_ioctl,
@@ -269,8 +269,8 @@ const mp_obj_type_t mp_type_vfs_fat_textio = {
     .make_new = file_obj_make_new,
     .make_new = file_obj_make_new,
     .getiter = mp_identity_getiter,
     .getiter = mp_identity_getiter,
     .iternext = mp_stream_unbuffered_iter,
     .iternext = mp_stream_unbuffered_iter,
-    .protocol = &textio_stream_p,
-    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+    .protocol = &vfs_fat_textio_stream_p,
+    .locals_dict = (mp_obj_dict_t*)&vfs_fat_rawfile_locals_dict,
 };
 };
 
 
 // Factory function for I/O stream classes
 // Factory function for I/O stream classes

+ 1 - 0
extmod/vfs_posix.c

@@ -31,6 +31,7 @@
 
 
 #if MICROPY_VFS_POSIX
 #if MICROPY_VFS_POSIX
 
 
+#include <stdio.h>
 #include <string.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <dirent.h>
 #include <dirent.h>

+ 9 - 9
extmod/vfs_posix_file.c

@@ -44,7 +44,7 @@ typedef struct _mp_obj_vfs_posix_file_t {
 #ifdef MICROPY_CPYTHON_COMPAT
 #ifdef MICROPY_CPYTHON_COMPAT
 STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
 STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
     if (o->fd < 0) {
     if (o->fd < 0) {
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file"));
+        mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file");
     }
     }
 }
 }
 #else
 #else
@@ -200,7 +200,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
     }
     }
 }
 }
 
 
-STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
+STATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) },
     { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) },
     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
@@ -215,10 +215,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
     { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
     { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
 };
 };
 
 
-STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
+STATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table);
 
 
 #if MICROPY_PY_IO_FILEIO
 #if MICROPY_PY_IO_FILEIO
-STATIC const mp_stream_p_t fileio_stream_p = {
+STATIC const mp_stream_p_t vfs_posix_fileio_stream_p = {
     .read = vfs_posix_file_read,
     .read = vfs_posix_file_read,
     .write = vfs_posix_file_write,
     .write = vfs_posix_file_write,
     .ioctl = vfs_posix_file_ioctl,
     .ioctl = vfs_posix_file_ioctl,
@@ -231,12 +231,12 @@ const mp_obj_type_t mp_type_vfs_posix_fileio = {
     .make_new = vfs_posix_file_make_new,
     .make_new = vfs_posix_file_make_new,
     .getiter = mp_identity_getiter,
     .getiter = mp_identity_getiter,
     .iternext = mp_stream_unbuffered_iter,
     .iternext = mp_stream_unbuffered_iter,
-    .protocol = &fileio_stream_p,
-    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+    .protocol = &vfs_posix_fileio_stream_p,
+    .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,
 };
 };
 #endif
 #endif
 
 
-STATIC const mp_stream_p_t textio_stream_p = {
+STATIC const mp_stream_p_t vfs_posix_textio_stream_p = {
     .read = vfs_posix_file_read,
     .read = vfs_posix_file_read,
     .write = vfs_posix_file_write,
     .write = vfs_posix_file_write,
     .ioctl = vfs_posix_file_ioctl,
     .ioctl = vfs_posix_file_ioctl,
@@ -250,8 +250,8 @@ const mp_obj_type_t mp_type_vfs_posix_textio = {
     .make_new = vfs_posix_file_make_new,
     .make_new = vfs_posix_file_make_new,
     .getiter = mp_identity_getiter,
     .getiter = mp_identity_getiter,
     .iternext = mp_stream_unbuffered_iter,
     .iternext = mp_stream_unbuffered_iter,
-    .protocol = &textio_stream_p,
-    .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+    .protocol = &vfs_posix_textio_stream_p,
+    .locals_dict = (mp_obj_dict_t*)&vfs_posix_rawfile_locals_dict,
 };
 };
 
 
 const mp_obj_vfs_posix_file_t mp_sys_stdin_obj  = {{&mp_type_textio}, STDIN_FILENO};
 const mp_obj_vfs_posix_file_t mp_sys_stdin_obj  = {{&mp_type_textio}, STDIN_FILENO};