diff options
| -rw-r--r-- | py/builtin.c | 25 | ||||
| -rw-r--r-- | py/builtin.h | 5 | ||||
| -rw-r--r-- | py/modsys.c | 3 | ||||
| -rw-r--r-- | py/pfenv.h | 3 | ||||
| -rw-r--r-- | py/pfenv_printf.c | 199 | ||||
| -rw-r--r-- | py/py.mk | 1 | ||||
| -rw-r--r-- | py/qstrdefs.h | 1 | ||||
| -rw-r--r-- | py/stream.c | 88 | ||||
| -rw-r--r-- | stmhal/file.c | 10 | ||||
| -rw-r--r-- | stmhal/file.h | 2 | ||||
| -rw-r--r-- | stmhal/main.c | 8 | ||||
| -rw-r--r-- | stmhal/modos.c | 63 | ||||
| -rw-r--r-- | stmhal/modpyb.c | 10 | ||||
| -rw-r--r-- | stmhal/modtime.c | 36 | ||||
| -rw-r--r-- | stmhal/mpconfigport.h | 2 | ||||
| -rw-r--r-- | stmhal/portmodules.h | 5 | ||||
| -rw-r--r-- | stmhal/printf.c | 172 | ||||
| -rw-r--r-- | stmhal/pybstdio.c | 44 | ||||
| -rw-r--r-- | stmhal/pybstdio.h | 5 | ||||
| -rw-r--r-- | stmhal/pyexec.c | 3 | ||||
| -rw-r--r-- | stmhal/qstrdefsport.h | 2 | ||||
| -rw-r--r-- | stmhal/readline.c | 3 | ||||
| -rw-r--r-- | stmhal/uart.c | 6 | ||||
| -rw-r--r-- | stmhal/uart.h | 3 | ||||
| -rw-r--r-- | stmhal/usb.c | 4 | ||||
| -rw-r--r-- | stmhal/usb.h | 1 | ||||
| -rwxr-xr-x | tests/run-tests | 2 | ||||
| -rw-r--r-- | tests/unicode/data/utf-8_2.txt | 1 | ||||
| -rw-r--r-- | tests/unicode/file2.py | 12 | ||||
| -rw-r--r-- | unix/file.c | 9 | ||||
| -rw-r--r-- | unix/mpconfigport.h | 2 | 
31 files changed, 484 insertions, 246 deletions
diff --git a/py/builtin.c b/py/builtin.c index e723fad33..725613385 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -36,6 +36,8 @@  #include "runtime0.h"  #include "runtime.h"  #include "builtin.h" +#include "stream.h" +#include "pfenv.h"  #if MICROPY_PY_BUILTINS_FLOAT  #include <math.h> @@ -424,13 +426,36 @@ STATIC mp_obj_t mp_builtin_print(uint n_args, const mp_obj_t *args, mp_map_t *kw      if (end_elem != NULL && end_elem->value != mp_const_none) {          end_data = mp_obj_str_get_data(end_elem->value, &end_len);      } +    #if MICROPY_PY_IO +    mp_obj_t stream_obj = &mp_sys_stdout_obj; +    mp_map_elem_t *file_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_file), MP_MAP_LOOKUP); +    if (file_elem != NULL && file_elem->value != mp_const_none) { +        stream_obj = file_elem->value; +    } + +    pfenv_t pfenv; +    pfenv.data = stream_obj; +    pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write; +    #endif      for (int i = 0; i < n_args; i++) {          if (i > 0) { +            #if MICROPY_PY_IO +            mp_stream_write(stream_obj, sep_data, sep_len); +            #else              printf("%.*s", sep_len, sep_data); +            #endif          } +        #if MICROPY_PY_IO +        mp_obj_print_helper((void (*)(void *env, const char *fmt, ...))pfenv_printf, &pfenv, args[i], PRINT_STR); +        #else          mp_obj_print(args[i], PRINT_STR); +        #endif      } +    #if MICROPY_PY_IO +    mp_stream_write(stream_obj, end_data, end_len); +    #else      printf("%.*s", end_len, end_data); +    #endif      return mp_const_none;  } diff --git a/py/builtin.h b/py/builtin.h index 361cef604..425cfec09 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -81,5 +81,10 @@ extern const mp_obj_module_t mp_module_struct;  extern const mp_obj_module_t mp_module_sys;  extern const mp_obj_module_t mp_module_gc; +struct _dummy_t; +extern struct _dummy_t mp_sys_stdin_obj; +extern struct _dummy_t mp_sys_stdout_obj; +extern struct _dummy_t mp_sys_stderr_obj; +  // extmod modules  extern const mp_obj_module_t mp_module_uctypes; diff --git a/py/modsys.c b/py/modsys.c index d21584676..c248e5626 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -44,9 +44,6 @@  // only addresses.  struct _dummy_t;  extern struct _dummy_t mp_sys_exit_obj; -extern struct _dummy_t mp_sys_stdin_obj; -extern struct _dummy_t mp_sys_stdout_obj; -extern struct _dummy_t mp_sys_stderr_obj;  extern mp_obj_int_t mp_maxsize_obj; diff --git a/py/pfenv.h b/py/pfenv.h index 22b1fc849..781738f4d 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -49,3 +49,6 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int  #if MICROPY_PY_BUILTINS_FLOAT  int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);  #endif + +//int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args); +int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...); diff --git a/py/pfenv_printf.c b/py/pfenv_printf.c new file mode 100644 index 000000000..003314e8f --- /dev/null +++ b/py/pfenv_printf.c @@ -0,0 +1,199 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdarg.h> + +#include "mpconfig.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "pfenv.h" + +#if MICROPY_PY_BUILTINS_FLOAT +#include "formatfloat.h" +#endif + +int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args) { +    int chrs = 0; +    for (;;) { +        { +            const char *f = fmt; +            while (*f != '\0' && *f != '%') { +                ++f; // XXX UTF8 advance char +            } +            if (f > fmt) { +                pfenv->print_strn(pfenv->data, fmt, f - fmt); +                chrs += f - fmt; +                fmt = f; +            } +        } + +        if (*fmt == '\0') { +            break; +        } + +        // move past % character +        ++fmt; + +        // parse flags, if they exist +        int flags = 0; +        char fill = ' '; +        while (*fmt != '\0') { +            if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST; +            else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN; +            else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN; +            else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ; +            else if (*fmt == '0') { +                flags |= PF_FLAG_PAD_AFTER_SIGN; +                fill = '0'; +            } else break; +            ++fmt; +        } + +        // parse width, if it exists +        int width = 0; +        for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { +            width = width * 10 + *fmt - '0'; +        } + +        // parse precision, if it exists +        int prec = -1; +        if (*fmt == '.') { +            ++fmt; +            if (*fmt == '*') { +                ++fmt; +                prec = va_arg(args, int); +            } else { +                prec = 0; +                for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { +                    prec = prec * 10 + *fmt - '0'; +                } +            } +            if (prec < 0) { +                prec = 0; +            } +        } + +        // parse long specifiers (current not used) +        //bool long_arg = false; +        if (*fmt == 'l') { +            ++fmt; +            //long_arg = true; +        } + +        if (*fmt == '\0') { +            break; +        } + +        switch (*fmt) { +            case 'b': +                if (va_arg(args, int)) { +                    chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width); +                } else { +                    chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width); +                } +                break; +            case 'c': +            { +                char str = va_arg(args, int); +                chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width); +                break; +            } +            case 's': +            { +                const char *str = va_arg(args, const char*); +                if (str) { +                    if (prec < 0) { +                        prec = strlen(str); +                    } +                    chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width); +                } else { +                    chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width); +                } +                break; +            } +            case 'u': +                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width); +                break; +            case 'd': +                chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width); +                break; +            case 'x': +            case 'p': // ? +                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width); +                break; +            case 'X': +            case 'P': // ? +                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width); +                break; +#if MICROPY_PY_BUILTINS_FLOAT +            case 'e': +            case 'E': +            case 'f': +            case 'F': +            case 'g': +            case 'G': +            { +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +                mp_float_t f = va_arg(args, double); +                chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec); +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +                // Currently pfenv_print_float uses snprintf, but snprintf +                // itself may be implemented in terms of pfenv_vprintf() for +                // some ports. So, for extra caution, this case is handled +                // with assert below. Note that currently ports which +                // use MICROPY_FLOAT_IMPL_DOUBLE, don't call pfenv_vprintf() +                // with float format specifier at all. +                // TODO: resolve this completely +                assert(0); +//#error Calling pfenv_print_float with double not supported from within printf +#else +#error Unknown MICROPY FLOAT IMPL +#endif +                break; +            } +#endif +            default: +                pfenv->print_strn(pfenv->data, fmt, 1); +                chrs += 1; +                break; +        } +        ++fmt; +    } +    return chrs; +} + +int pfenv_printf(const pfenv_t *pfenv, const char *fmt, ...) { +    va_list ap; +    va_start(ap, fmt); +    int ret = pfenv_vprintf(pfenv, fmt, ap); +    va_end(ap); +    return ret; +} @@ -102,6 +102,7 @@ PY_O_BASENAME = \  	repl.o \  	smallint.o \  	pfenv.o \ +	pfenv_printf.o \  	../extmod/moductypes.o  # prepend the build destination prefix to the py object files diff --git a/py/qstrdefs.h b/py/qstrdefs.h index e3a4dc01a..0deb646c7 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -413,6 +413,7 @@ Q(TextIOWrapper)  Q(StringIO)  Q(BytesIO)  Q(getvalue) +Q(file)  #endif  #if MICROPY_PY_GC diff --git a/py/stream.c b/py/stream.c index 2b4410728..4c8b8a570 100644 --- a/py/stream.c +++ b/py/stream.c @@ -67,6 +67,9 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {          nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Operation not supported"));      } +    // What to do if sz < -1?  Python docs don't specify this case. +    // CPython does a readall, but here we silently let negatives through, +    // and they will cause a MemoryError.      mp_int_t sz;      if (n_args == 1 || ((sz = mp_obj_get_int(args[1])) == -1)) {          return stream_readall(args[0]); @@ -74,7 +77,90 @@ STATIC mp_obj_t stream_read(uint n_args, const mp_obj_t *args) {      #if MICROPY_PY_BUILTINS_STR_UNICODE      if (!o->type->stream_p->is_bytes) { -        mp_not_implemented("Reading from unicode text streams by character count"); +        // We need to read sz number of unicode characters.  Because we don't have any +        // buffering, and because the stream API can only read bytes, we must read here +        // in units of bytes and must never over read.  If we want sz chars, then reading +        // sz bytes will never over-read, so we follow this approach, in a loop to keep +        // reading until we have exactly enough chars.  This will be 1 read for text +        // with ASCII-only chars, and about 2 reads for text with a couple of non-ASCII +        // chars.  For text with lots of non-ASCII chars, it'll be pretty inefficient +        // in time and memory. + +        vstr_t vstr; +        vstr_init(&vstr, sz); +        mp_uint_t more_bytes = sz; +        mp_uint_t last_buf_offset = 0; +        while (more_bytes > 0) { +            char *p = vstr_add_len(&vstr, more_bytes); +            if (p == NULL) { +                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); +            } +            int error; +            mp_int_t out_sz = o->type->stream_p->read(o, p, more_bytes, &error); +            if (out_sz == -1) { +                vstr_cut_tail_bytes(&vstr, more_bytes); +                if (is_nonblocking_error(error)) { +                    // With non-blocking streams, we read as much as we can. +                    // If we read nothing, return None, just like read(). +                    // Otherwise, return data read so far. +                    // TODO what if we have read only half a non-ASCII char? +                    if (vstr.len == 0) { +                        vstr_clear(&vstr); +                        return mp_const_none; +                    } +                    break; +                } +                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d]", error)); +            } + +            if (out_sz == 0) { +                // Finish reading. +                // TODO what if we have read only half a non-ASCII char? +                vstr_cut_tail_bytes(&vstr, more_bytes); +                break; +            } + +            // count chars from bytes just read +            for (mp_uint_t off = last_buf_offset;;) { +                byte b = vstr.buf[off]; +                int n; +                if (!UTF8_IS_NONASCII(b)) { +                    // 1-byte ASCII char +                    n = 1; +                } else if ((b & 0xe0) == 0xc0) { +                    // 2-byte char +                    n = 2; +                } else if ((b & 0xf0) == 0xe0) { +                    // 3-byte char +                    n = 3; +                } else if ((b & 0xf8) == 0xf0) { +                    // 4-byte char +                    n = 4; +                } else { +                    // TODO +                    n = 5; +                } +                if (off + n <= vstr.len) { +                    // got a whole char in n bytes +                    off += n; +                    sz -= 1; +                    last_buf_offset = off; +                    if (off >= vstr.len) { +                        more_bytes = sz; +                        break; +                    } +                } else { +                    // didn't get a whole char, so work out how many extra bytes are needed for +                    // this partial char, plus bytes for additional chars that we want +                    more_bytes = (off + n - vstr.len) + (sz - 1); +                    break; +                } +            } +        } + +        mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_str, (byte*)vstr.buf, vstr.len); +        vstr_clear(&vstr); +        return ret;      }      #endif diff --git a/stmhal/file.c b/stmhal/file.c index 2d33a8f7b..c1a292490 100644 --- a/stmhal/file.c +++ b/stmhal/file.c @@ -41,7 +41,7 @@ extern const mp_obj_type_t mp_type_fileio;  extern const mp_obj_type_t mp_type_textio;  // this table converts from FRESULT to POSIX errno -STATIC const byte fresult_to_errno_table[] = { +const byte fresult_to_errno_table[20] = {      [FR_OK] = 0,      [FR_DISK_ERR] = EIO,      [FR_INT_ERR] = EIO, @@ -95,6 +95,13 @@ STATIC mp_int_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size      return sz_out;  } +STATIC mp_obj_t file_obj_flush(mp_obj_t self_in) { +    pyb_file_obj_t *self = self_in; +    f_sync(&self->fp); +    return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_flush_obj, file_obj_flush); +  mp_obj_t file_obj_close(mp_obj_t self_in) {      pyb_file_obj_t *self = self_in;      f_close(&self->fp); @@ -218,6 +225,7 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = {      { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},      { MP_OBJ_NEW_QSTR(MP_QSTR_readlines), (mp_obj_t)&mp_stream_unbuffered_readlines_obj},      { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, +    { MP_OBJ_NEW_QSTR(MP_QSTR_flush), (mp_obj_t)&file_obj_flush_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_seek), (mp_obj_t)&file_obj_seek_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_tell), (mp_obj_t)&file_obj_tell_obj }, diff --git a/stmhal/file.h b/stmhal/file.h index 350785f74..7522a337d 100644 --- a/stmhal/file.h +++ b/stmhal/file.h @@ -24,4 +24,6 @@   * THE SOFTWARE.   */ +const byte fresult_to_errno_table[20]; +  MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj); diff --git a/stmhal/main.c b/stmhal/main.c index ae4ff5141..9e1798b3b 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -43,7 +43,6 @@  #include "stackctrl.h"  #include "gc.h"  #include "gccollect.h" -#include "pybstdio.h"  #include "readline.h"  #include "pyexec.h"  #include "i2c.h" @@ -64,6 +63,7 @@  #include "servo.h"  #include "dac.h"  #include "pybwlan.h" +#include "pybstdio.h"  void SystemClock_Config(void); @@ -311,12 +311,10 @@ soft_reset:              MP_OBJ_NEW_SMALL_INT(PYB_UART_6),              MP_OBJ_NEW_SMALL_INT(115200),          }; -        pyb_uart_global_debug = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, -                                                       MP_ARRAY_SIZE(args), -                                                       0, args); +        pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);      }  #else -    pyb_uart_global_debug = NULL; +    pyb_stdio_uart = NULL;  #endif      // Micro Python init diff --git a/stmhal/modos.c b/stmhal/modos.c index dd6fd67ec..35979ae97 100644 --- a/stmhal/modos.c +++ b/stmhal/modos.c @@ -32,10 +32,12 @@  #include "misc.h"  #include "qstr.h"  #include "obj.h" +#include "objtuple.h"  #include "systick.h"  #include "rng.h"  #include "storage.h"  #include "ff.h" +#include "file.h"  #include "portmodules.h"  #if _USE_LFN @@ -107,8 +109,7 @@ STATIC mp_obj_t os_listdir(uint n_args, const mp_obj_t *args) {      return dir_list;  } - -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_listdir_obj, 0, 1, os_listdir);  STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {      const char *path = mp_obj_str_get_str(path_o); @@ -123,8 +124,7 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) {              nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path));      }  } - -MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir);  STATIC mp_obj_t os_remove(mp_obj_t path_o) {      const char *path = mp_obj_str_get_str(path_o); @@ -137,8 +137,7 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) {              nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path));      }  } - -MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove);  STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {      const char *path = mp_obj_str_get_str(path_o); @@ -151,15 +150,57 @@ STATIC mp_obj_t os_rmdir(mp_obj_t path_o) {              nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing directory '%s'", path));      }  } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir); + +STATIC mp_obj_t os_stat(mp_obj_t path_in) { +    const char *path = mp_obj_str_get_str(path_in); + +    FILINFO fno; +#if _USE_LFN +    fno.lfname = NULL; +    fno.lfsize = 0; +#endif -MP_DEFINE_CONST_FUN_OBJ_1(os_rmdir_obj, os_rmdir); +    FRESULT res = f_stat(path, &fno); +    if (res != FR_OK) { +        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); +    } + +    mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL); +    mp_int_t mode = 0; +    if (fno.fattrib & AM_DIR) { +        mode |= 0x4000; // stat.S_IFDIR +    } else { +        mode |= 0x8000; // stat.S_IFREG +    } +    mp_int_t seconds = mod_time_seconds_since_2000( +        1980 + ((fno.fdate >> 9) & 0x7f), +        (fno.fdate >> 5) & 0x0f, +        fno.fdate & 0x1f, +        (fno.ftime >> 11) & 0x1f, +        (fno.ftime >> 5) & 0x3f, +        2 * (fno.ftime & 0x1f) +    ); +    t->items[0] = MP_OBJ_NEW_SMALL_INT(mode); // st_mode +    t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino +    t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev +    t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink +    t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid +    t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid +    t->items[6] = MP_OBJ_NEW_SMALL_INT(fno.fsize); // st_size +    t->items[7] = MP_OBJ_NEW_SMALL_INT(seconds); // st_atime +    t->items[8] = MP_OBJ_NEW_SMALL_INT(seconds); // st_mtime +    t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime + +    return t; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat);  STATIC mp_obj_t os_sync(void) {      storage_flush();      return mp_const_none;  } - -MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);  STATIC mp_obj_t os_urandom(mp_obj_t num) {      mp_int_t n = mp_obj_get_int(num); @@ -170,8 +211,7 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {      }      return mp_obj_str_builder_end(o);  } - -MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);  STATIC const mp_map_elem_t os_module_globals_table[] = {      { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_os) }, @@ -180,6 +220,7 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {      { MP_OBJ_NEW_QSTR(MP_QSTR_mkdir), (mp_obj_t)&os_mkdir_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_remove), (mp_obj_t)&os_remove_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_rmdir), (mp_obj_t)&os_rmdir_obj }, +    { MP_OBJ_NEW_QSTR(MP_QSTR_stat), (mp_obj_t)&os_stat_obj },      { MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove      { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj }, diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 8b594332b..38a680da2 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -37,7 +37,6 @@  #include "gc.h"  #include "gccollect.h"  #include "systick.h" -#include "pybstdio.h"  #include "pyexec.h"  #include "led.h"  #include "pin.h" @@ -57,6 +56,7 @@  #include "dac.h"  #include "lcd.h"  #include "usb.h" +#include "pybstdio.h"  #include "ff.h"  #include "portmodules.h" @@ -307,16 +307,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);  /// Get or set the UART object that the REPL is repeated on.  STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {      if (n_args == 0) { -        if (pyb_uart_global_debug == NULL) { +        if (pyb_stdio_uart == NULL) {              return mp_const_none;          } else { -            return pyb_uart_global_debug; +            return pyb_stdio_uart;          }      } else {          if (args[0] == mp_const_none) { -            pyb_uart_global_debug = NULL; +            pyb_stdio_uart = NULL;          } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) { -            pyb_uart_global_debug = args[0]; +            pyb_stdio_uart = args[0];          } else {              nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object"));          } diff --git a/stmhal/modtime.c b/stmhal/modtime.c index ea4e3210a..f13bb15f8 100644 --- a/stmhal/modtime.c +++ b/stmhal/modtime.c @@ -34,22 +34,36 @@  #include "portmodules.h"  #include "rtc.h" -STATIC const uint days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +STATIC const uint16_t days_since_jan1[]= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; -STATIC bool is_leap_year(uint year) { +STATIC bool is_leap_year(mp_uint_t year) {      return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;  }  // compute the day of the year, between 1 and 366  // month should be between 1 and 12, date should start at 1 -STATIC uint year_day(uint year, uint month, uint date) { -    uint yday = days_since_jan1[month - 1] + date; +mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) { +    mp_uint_t yday = days_since_jan1[month - 1] + date;      if (month >= 3 && is_leap_year(year)) {          yday += 1;      }      return yday;  } +// returns the number of seconds, as an integer, since 1/1/2000 +mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { +    return +        second +        + minute * 60 +        + hour * 3600 +        + (mod_time_year_day(year, month, date) - 1 +            + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001 +            - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001 +            + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001 +            ) * 86400 +        + (year - 2000) * 31536000; +} +  // returns time stored in RTC as: (year, month, date, hour, minute, second, weekday)  // weekday is 0-6 for Mon-Sun  STATIC mp_obj_t time_localtime(void) { @@ -67,7 +81,7 @@ STATIC mp_obj_t time_localtime(void) {          mp_obj_new_int(time.Minutes),          mp_obj_new_int(time.Seconds),          mp_obj_new_int(date.WeekDay - 1), -        mp_obj_new_int(year_day(2000 + date.Year, date.Month, date.Date)), +        mp_obj_new_int(mod_time_year_day(2000 + date.Year, date.Month, date.Date)),      };      return mp_obj_new_tuple(8, tuple);  } @@ -95,17 +109,7 @@ STATIC mp_obj_t time_time(void) {      RTC_TimeTypeDef time;      HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN);      HAL_RTC_GetDate(&RTCHandle, &date, FORMAT_BIN); -    return mp_obj_new_int( -        time.Seconds -        + time.Minutes * 60 -        + time.Hours * 3600 -        + (year_day(2000 + date.Year, date.Month, date.Date) - 1 -            + ((date.Year + 3) / 4) // add a day each 4 years starting with 2001 -            - ((date.Year + 99) / 100) // subtract a day each 100 years starting with 2001 -            + ((date.Year + 399) / 400) // add a day each 400 years starting with 2001 -            ) * 86400 -        + date.Year * 31536000 -    ); +    return mp_obj_new_int(mod_time_seconds_since_2000(2000 + date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds));  }  MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 00afa989c..95f142ca4 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -44,7 +44,7 @@  */  #define MICROPY_ENABLE_LFN          (1)  #define MICROPY_LFN_CODE_PAGE       (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ -#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1)  #define MICROPY_PY_BUILTINS_FROZENSET (1)  #define MICROPY_PY_SYS_EXIT         (1)  #define MICROPY_PY_SYS_STDFILES     (1) diff --git a/stmhal/portmodules.h b/stmhal/portmodules.h index f38feafe7..d8a3d8f87 100644 --- a/stmhal/portmodules.h +++ b/stmhal/portmodules.h @@ -28,3 +28,8 @@ extern const mp_obj_module_t os_module;  extern const mp_obj_module_t pyb_module;  extern const mp_obj_module_t stm_module;  extern const mp_obj_module_t time_module; + +// additional helper functions exported by the modules + +mp_uint_t mod_time_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); +mp_uint_t mod_time_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); diff --git a/stmhal/printf.c b/stmhal/printf.c index c4731aa88..db611f3d9 100644 --- a/stmhal/printf.c +++ b/stmhal/printf.c @@ -40,184 +40,30 @@  #endif  #include "uart.h"  #include "usb.h" +#include "pybstdio.h"  #if MICROPY_PY_BUILTINS_FLOAT  #include "formatfloat.h"  #endif -void pfenv_prints(const pfenv_t *pfenv, const char *str) { -    pfenv->print_strn(pfenv->data, str, strlen(str)); -} - -int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) { -    int chrs = 0; -    for (;;) { -        { -            const char *f = fmt; -            while (*f != '\0' && *f != '%') { -                ++f; // XXX UTF8 advance char -            } -            if (f > fmt) { -                pfenv->print_strn(pfenv->data, fmt, f - fmt); -                chrs += f - fmt; -                fmt = f; -            } -        } +int pfenv_vprintf(const pfenv_t *pfenv, const char *fmt, va_list args); -        if (*fmt == '\0') { -            break; -        } - -        // move past % character -        ++fmt; - -        // parse flags, if they exist -        int flags = 0; -        char fill = ' '; -        while (*fmt != '\0') { -            if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST; -            else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN; -            else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN; -            else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ; -            else if (*fmt == '0') { -                flags |= PF_FLAG_PAD_AFTER_SIGN; -                fill = '0'; -            } else break; -            ++fmt; -        } - -        // parse width, if it exists -        int width = 0; -        for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { -            width = width * 10 + *fmt - '0'; -        } - -        // parse precision, if it exists -        int prec = -1; -        if (*fmt == '.') { -            ++fmt; -            if (*fmt == '*') { -                ++fmt; -                prec = va_arg(args, int); -            } else { -                prec = 0; -                for (; '0' <= *fmt && *fmt <= '9'; ++fmt) { -                    prec = prec * 10 + *fmt - '0'; -                } -            } -            if (prec < 0) { -                prec = 0; -            } -        } - -        // parse long specifiers (current not used) -        //bool long_arg = false; -        if (*fmt == 'l') { -            ++fmt; -            //long_arg = true; -        } - -        if (*fmt == '\0') { -            break; -        } - -        switch (*fmt) { -            case 'b': -                if (va_arg(args, int)) { -                    chrs += pfenv_print_strn(pfenv, "true", 4, flags, fill, width); -                } else { -                    chrs += pfenv_print_strn(pfenv, "false", 5, flags, fill, width); -                } -                break; -            case 'c': -            { -                char str = va_arg(args, int); -                chrs += pfenv_print_strn(pfenv, &str, 1, flags, fill, width); -                break; -            } -            case 's': -            { -                const char *str = va_arg(args, const char*); -                if (str) { -                    if (prec < 0) { -                        prec = strlen(str); -                    } -                    chrs += pfenv_print_strn(pfenv, str, prec, flags, fill, width); -                } else { -                    chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, fill, width); -                } -                break; -            } -            case 'u': -                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, fill, width); -                break; -            case 'd': -                chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, fill, width); -                break; -            case 'x': -            case 'p': // ? -                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, fill, width); -                break; -            case 'X': -            case 'P': // ? -                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, fill, width); -                break; -#if MICROPY_PY_BUILTINS_FLOAT -            case 'e': -            case 'E': -            case 'f': -            case 'F': -            case 'g': -            case 'G': -            { -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -                mp_float_t f = va_arg(args, double); -                chrs += pfenv_print_float(pfenv, f, *fmt, flags, fill, width, prec); -#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -                // Currently pfenv_print_float uses snprintf, so if you want -                // to use pfenv_print_float with doubles then you'll need -                // fix it to not use snprintf first. Otherwise you'll have -                // inifinite recursion. -#error Calling pfenv_print_float with double not supported from within printf -#else -#error Unknown MICROPY FLOAT IMPL -#endif -                break; -            } -#endif -            default: -                pfenv->print_strn(pfenv->data, fmt, 1); -                chrs += 1; -                break; -        } -        ++fmt; -    } -    return chrs; -} - -STATIC void stdout_print_strn(void *data, const char *str, unsigned int len) { -    // TODO this needs to be replaced with a proper stdio interface ala CPython -    // send stdout to UART and USB CDC VCP -    if (pyb_uart_global_debug != PYB_UART_NONE) { -        uart_tx_strn_cooked(pyb_uart_global_debug, str, len); -    } -    if (usb_vcp_is_enabled()) { -        usb_vcp_send_strn_cooked(str, len); -    } +STATIC void stdout_print_strn(void *dummy_env, const char *str, unsigned int len) { +    stdout_tx_strn_cooked(str, len);  } -static const pfenv_t pfenv_stdout = {0, stdout_print_strn}; +STATIC const pfenv_t pfenv_stdout = {0, stdout_print_strn};  int printf(const char *fmt, ...) {      va_list ap;      va_start(ap, fmt); -    int ret = pfenv_printf(&pfenv_stdout, fmt, ap); +    int ret = pfenv_vprintf(&pfenv_stdout, fmt, ap);      va_end(ap);      return ret;  }  int vprintf(const char *fmt, va_list ap) { -    return pfenv_printf(&pfenv_stdout, fmt, ap); +    return pfenv_vprintf(&pfenv_stdout, fmt, ap);  }  #if MICROPY_DEBUG_PRINTERS @@ -225,7 +71,7 @@ int DEBUG_printf(const char *fmt, ...) {      (void)stream;      va_list ap;      va_start(ap, fmt); -    int ret = pfenv_printf(&pfenv_stdout, fmt, ap); +    int ret = pfenv_vprintf(&pfenv_stdout, fmt, ap);      va_end(ap);      return ret;  } @@ -268,7 +114,7 @@ int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {      pfenv_t pfenv;      pfenv.data = &strn_pfenv;      pfenv.print_strn = strn_print_strn; -    int len = pfenv_printf(&pfenv, fmt, ap); +    int len = pfenv_vprintf(&pfenv, fmt, ap);      // add terminating null byte      if (size > 0) {          if (strn_pfenv.remain == 0) { diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index 2a4386e09..9846ce045 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -26,6 +26,7 @@  #include <stdio.h>  #include <stdint.h> +#include <string.h>  #include "mpconfig.h"  #include "misc.h" @@ -34,31 +35,41 @@  #include "obj.h"  #include "stream.h"  #include MICROPY_HAL_H -#include "pybstdio.h"  #include "usb.h"  #include "uart.h" +#include "pybstdio.h"  // TODO make stdin, stdout and stderr writable objects so they can -// be changed by Python code. +// be changed by Python code.  This requires some changes, as these +// objects are in a read-only module (py/modsys.c). + +// stdio is repeated on this UART object if it's not null +pyb_uart_obj_t *pyb_stdio_uart = NULL;  void stdout_tx_str(const char *str) { -    if (pyb_uart_global_debug != PYB_UART_NONE) { -        uart_tx_str(pyb_uart_global_debug, str); -    } -#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD -    lcd_print_str(str); -#endif -    usb_vcp_send_str(str); +    stdout_tx_strn(str, strlen(str));  } -void stdout_tx_strn(const char *str, uint len) { -    if (pyb_uart_global_debug != PYB_UART_NONE) { -        uart_tx_strn(pyb_uart_global_debug, str, len); +void stdout_tx_strn(const char *str, mp_uint_t len) { +    if (pyb_stdio_uart != PYB_UART_NONE) { +        uart_tx_strn(pyb_stdio_uart, str, len);      }  #if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD      lcd_print_strn(str, len);  #endif -    usb_vcp_send_strn(str, len); +    if (usb_vcp_is_enabled()) { +        usb_vcp_send_strn(str, len); +    } +} + +void stdout_tx_strn_cooked(const char *str, mp_uint_t len) { +    // send stdout to UART and USB CDC VCP +    if (pyb_stdio_uart != PYB_UART_NONE) { +        uart_tx_strn_cooked(pyb_stdio_uart, str, len); +    } +    if (usb_vcp_is_enabled()) { +        usb_vcp_send_strn_cooked(str, len); +    }  }  int stdin_rx_chr(void) { @@ -74,14 +85,13 @@ int stdin_rx_chr(void) {  #endif          if (usb_vcp_rx_num() != 0) {              return usb_vcp_rx_get(); -        } else if (pyb_uart_global_debug != PYB_UART_NONE && uart_rx_any(pyb_uart_global_debug)) { -            return uart_rx_char(pyb_uart_global_debug); +        } else if (pyb_stdio_uart != PYB_UART_NONE && uart_rx_any(pyb_stdio_uart)) { +            return uart_rx_char(pyb_stdio_uart);          }          __WFI();      }  } -  /******************************************************************************/  // Micro Python bindings @@ -120,7 +130,7 @@ STATIC mp_int_t stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *err  STATIC mp_int_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {      pyb_stdio_obj_t *self = self_in;      if (self->fd == STDIO_FD_OUT || self->fd == STDIO_FD_ERR) { -        stdout_tx_strn(buf, size); +        stdout_tx_strn_cooked(buf, size);          *errcode = 0;          return size;      } else { diff --git a/stmhal/pybstdio.h b/stmhal/pybstdio.h index 5beab893d..cdb7acfe5 100644 --- a/stmhal/pybstdio.h +++ b/stmhal/pybstdio.h @@ -24,6 +24,9 @@   * THE SOFTWARE.   */ +extern pyb_uart_obj_t *pyb_stdio_uart; +  void stdout_tx_str(const char *str); -void stdout_tx_strn(const char *str, uint len); +void stdout_tx_strn(const char *str, mp_uint_t len); +void stdout_tx_strn_cooked(const char *str, mp_uint_t len);  int stdin_rx_chr(void); diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 93f4d62a9..cac6f0cf0 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -44,10 +44,11 @@  #include "gccollect.h"  #include MICROPY_HAL_H  #include "systick.h" -#include "pybstdio.h"  #include "readline.h"  #include "pyexec.h"  #include "usb.h" +#include "uart.h" +#include "pybstdio.h"  #include "genhdr/py-version.h"  pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index eb22d616b..8d277fded 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -61,6 +61,7 @@ Q(rng)  Q(SD)  Q(SDcard)  Q(FileIO) +Q(flush)  // Entries for sys.path  Q(0:/)  Q(0:/lib) @@ -238,6 +239,7 @@ Q(remove)  Q(rmdir)  Q(unlink)  Q(sep) +Q(stat)  Q(urandom)  // for time module diff --git a/stmhal/readline.c b/stmhal/readline.c index 0703dcf4e..14c9b9fb9 100644 --- a/stmhal/readline.c +++ b/stmhal/readline.c @@ -34,9 +34,10 @@  #include "misc.h"  #include "obj.h"  #include MICROPY_HAL_H -#include "pybstdio.h"  #include "readline.h"  #include "usb.h" +#include "uart.h" +#include "pybstdio.h"  #if 0 // print debugging info  #define DEBUG_PRINT (1) diff --git a/stmhal/uart.c b/stmhal/uart.c index 9436c2938..0418e8f3d 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -65,8 +65,6 @@ struct _pyb_uart_obj_t {      UART_HandleTypeDef uart;  }; -pyb_uart_obj_t *pyb_uart_global_debug = NULL; -  // assumes Init parameters have been set up correctly  bool uart_init2(pyb_uart_obj_t *uart_obj) {      USART_TypeDef *UARTx = NULL; @@ -219,10 +217,6 @@ void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {      HAL_UART_Transmit(&uart_obj->uart, &ch, 1, 100000);  } -void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str) { -    HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, strlen(str), 100000); -} -  void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {      HAL_UART_Transmit(&uart_obj->uart, (uint8_t*)str, len, 100000);  } diff --git a/stmhal/uart.h b/stmhal/uart.h index 13ac92cbf..7499473c1 100644 --- a/stmhal/uart.h +++ b/stmhal/uart.h @@ -43,14 +43,11 @@ typedef enum {  } pyb_uart_t;  typedef struct _pyb_uart_obj_t pyb_uart_obj_t; - -extern pyb_uart_obj_t *pyb_uart_global_debug;  extern const mp_obj_type_t pyb_uart_type;  bool uart_init(pyb_uart_obj_t *uart_obj, uint32_t baudrate);  bool uart_rx_any(pyb_uart_obj_t *uart_obj);  int uart_rx_char(pyb_uart_obj_t *uart_obj); -void uart_tx_str(pyb_uart_obj_t *uart_obj, const char *str);  void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);  void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len); diff --git a/stmhal/usb.c b/stmhal/usb.c index 50848f455..85dd2b4ea 100644 --- a/stmhal/usb.c +++ b/stmhal/usb.c @@ -107,10 +107,6 @@ char usb_vcp_rx_get(void) {      return USBD_CDC_RxGet();  } -void usb_vcp_send_str(const char *str) { -    usb_vcp_send_strn(str, strlen(str)); -} -  void usb_vcp_send_strn(const char *str, int len) {  #ifdef USE_DEVICE_MODE      if (dev_is_enabled) { diff --git a/stmhal/usb.h b/stmhal/usb.h index 3bd30ba92..4eb29c9de 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -48,7 +48,6 @@ bool usb_vcp_is_connected(void);  void usb_vcp_set_interrupt_char(int c);  int usb_vcp_rx_num(void);  char usb_vcp_rx_get(void); -void usb_vcp_send_str(const char* str);  void usb_vcp_send_strn(const char* str, int len);  void usb_vcp_send_strn_cooked(const char *str, int len);  void usb_hid_send_report(uint8_t *buf); // 4 bytes for mouse: ?, x, y, ? diff --git a/tests/run-tests b/tests/run-tests index 71a94f946..4b48421de 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -134,7 +134,7 @@ def main():          if args.test_dirs is None:              if pyb is None:                  # run PC tests -                test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc') +                test_dirs = ('basics', 'micropython', 'float', 'import', 'io', 'misc', 'unicode')              else:                  # run pyboard tests                  test_dirs = ('basics', 'micropython', 'float', 'pyb', 'pybnative', 'inlineasm') diff --git a/tests/unicode/data/utf-8_2.txt b/tests/unicode/data/utf-8_2.txt new file mode 100644 index 000000000..ab0eaa4e0 --- /dev/null +++ b/tests/unicode/data/utf-8_2.txt @@ -0,0 +1 @@ +aαbβcγdδ diff --git a/tests/unicode/file2.py b/tests/unicode/file2.py new file mode 100644 index 000000000..aca2e0e0e --- /dev/null +++ b/tests/unicode/file2.py @@ -0,0 +1,12 @@ +# test reading a given number of characters + +def do(mode): +    f = open('unicode/data/utf-8_2.txt', mode) +    print(f.read(1)) +    print(f.read(1)) +    print(f.read(2)) +    print(f.read(4)) +    f.close() + +do('rb') +do('rt') diff --git a/unix/file.c b/unix/file.c index 056a7b6e8..7cf0a5193 100644 --- a/unix/file.c +++ b/unix/file.c @@ -39,6 +39,10 @@  #include "runtime.h"  #include "stream.h" +#ifdef _WIN32 +#define fsync _commit +#endif +  typedef struct _mp_obj_fdfile_t {      mp_obj_base_t base;      int fd; @@ -83,12 +87,9 @@ STATIC mp_int_t fdfile_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int  }  STATIC mp_obj_t fdfile_flush(mp_obj_t self_in) { -#ifndef _WIN32      mp_obj_fdfile_t *self = self_in; +    check_fd_is_open(self);      fsync(self->fd); -#else -    //TODO -#endif      return mp_const_none;  }  STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_flush_obj, fdfile_flush); diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 0831e3fd3..ce4365d36 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -43,7 +43,7 @@  #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)  #define MICROPY_STREAMS_NON_BLOCK   (1)  #define MICROPY_OPT_COMPUTED_GOTO   (1) -#define MICROPY_PY_BUILTINS_STR_UNICODE (0) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1)  #define MICROPY_PY_BUILTINS_FROZENSET (1)  #define MICROPY_PY_SYS_EXIT         (1)  #define MICROPY_PY_SYS_PLATFORM     "linux"  | 
