diff options
author | Damien George <damien.p.george@gmail.com> | 2017-08-13 21:33:40 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-08-13 21:33:40 +1000 |
commit | e52758da223e57b6cd9458f039f8ccc50ee76ddb (patch) | |
tree | 2d5218ad0e1f30c686f51f5807b5676fe0007fe5 /extmod | |
parent | be2387885bf251fb44b6b64aeadff147a4ae7266 (diff) | |
parent | 9b39263b118a4be65c58bf9c396203fa535bebe1 (diff) | |
download | micropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.tar.gz micropython-e52758da223e57b6cd9458f039f8ccc50ee76ddb.zip |
Merge tag 'v1.8.1' into parse-bytecode
Many ESP8266 improvements, enhanced WebREPL, and support for STM32L4 MCUs
This release brings general improvements and bug fixes, and some new
features. There is now a uerror module for consistent errno handling
across ports, as well as textual names of OS errors that are printed when
an OSError is raised. There is support for frozen packages, via both
frozen scripts and frozen bytecode. WebREPL on the ESP8266 is greatly
improved with many bug fixes and now supports an unlimited (or very large)
number of reconnects. The os module on the ESP8266 now has rename, chdir,
getcwd and stat. The unix port now includes the ussl module by default.
The stmhal port has support for STM32L4 MCUs including the STM32L476
Discovery board and the LimiFrog board.
README:
- add explicit note that subdirs contain more READMEs
- add "make deplibs" to quick build section
- "quick build": Use "make axtls" after all
CODECONVENTIONS.md:
- describe git commit messages conventions
py core:
- obj: add warning note about get_array return value and GC blocks
- objstr: binary type of str/bytes for buffer protocol is 'B'
- runtime: properly handle passing user mappings to ** keyword args
- repl: if there're no better alternatives, try to complete "import"
- mpz: fix bug with overflowing C-shift in division routine
- mpz: do Python style division/modulo within bignum divmod routine
- mpz: fix mpn_div so that it doesn't modify memory of denominator
- vstr: vstr_null_terminated_str(): Extend string by at most one byte
- vstr: change allocation policy, +16 to requested size, instead of *2
- add mperrno.h file with uPy defined errno constants
- add uerrno module, with errno constants and dict
- parse: add uerrno to list of modules to look for constants in
- mperrno: add EAFNOSUPPORT definition
- repl: fix handling of backslash in quotes when checking continuation
- gc: gc_dump_alloc_table(): Show byte/str and (byte)array objects
- gc: make (byte)array type dumping conditional on these types being enabled
- gc: use '=' char for tail blocks when dumping heap
- mperrno: add some more MP_Exxx constants, related to networking
- moduerrno: add more constants to the errno module
- add mp_errno_to_str() and use it to provide nicer OSError msgs
- objfloat, py/modmath: ensure M_PI and M_E defined
- emitglue: fix build on AArch64 (ARMv8, etc.) related to loading .mpy files
- objexcept: don't convert errno to str in constructor, do it in print
- moduerrno: add EACCES, pretty common error on Unix
- gc: gc_dump_alloc_table(): dump heap offset instead of actual address
- objstr: make dedicated splitlines function, supporting diff newlines
- objstringio: add TODO comment about avoiding copying on .getvalue()
- modstruct: raise ValueError on unsupported format char
- stream: support both "exact size" and "one underlying call" operations
- declare constant data as properly constant
- stream: add mp_stream_close() helper function
- mphal.h: provide default prototypes for mp_hal_delay_us/mp_hal_ticks_us
- rework frozen modules support to support packages
- objstr: implement str.center()
- allow to stat and import frozen mpy files using new frozen "VFS"
- makeqstrdata.py: allow to have double-quote characters in qstrs
- objnamedtuple: allow passing field names as a tuple
- moduerrno: add EEXIST, EISDIR, ECONNREFUSED
- modstruct: allow to have "0s" in struct format
extmod:
- modlwip: convert errno's to use MP_Exxx symbols
- modlwip: rework how Python accept callback is called
- when including extmod headers, prefix path with extmod/
- modwebsocket: add close() method
- modwebrepl: add close() method
- moduos_dupterm: dumpterm subsystem is responsible for closing stream
- modussl: make more compatible with non-default obj representations
- machine_i2c: redo mp_hal_pin macros to use open_drain and od_low
- virtpin: initial implementation of open-ended C-level Pin interface
- vfs_fat: replace text error messages by POSIX error numbers
- vfs_fat: add chdir() method
- vfs_fat: add getcwd() method
- vfs_fat: add vfs.stat() method
- add machine time_pulse_us function (at C and Python level)
- machine: add MICROPY_PY_MACHINE_PULSE config for time_pulse_us
lib:
- timeutils/timeutils: timeutils_mktime may accept negative time values
drivers:
- cc3000: rename timeval to cc3000_timeval, to avoid clash
- add C-level function to read DHT11 and DHT22 devices
- display/ssd1306: update SSD1306_SPI to work with new API
tools:
- make-frozen.py: properly escape hex chars when making C strings
- make-frozen.py: quick fix to support package-modules
- mpy-tool.py: add checks for critical configuration vars
- make-frozen.py: update for latest changes in frozen modules support
- mpy-tool.py: include .py extension in frozen filename
- mpy-tool.py: don't strip directories from the frozen source name
- upgrade upip to 0.7: SSL cert warning, use uerrno, better usage message
tests:
- run-tests: factor out list of supported external boards
- disable memoryview tests that overflow int conversion
- basics/string_splitlines: reinstate feature test for splitlines
- struct1: add testcase for an unknown type char
- add testcase for str.center()
- extmod/vfs_fat_ramdisk: add testcases for chdir(), getcwd()
- misc/recursive_iternext.py: increase depth N from 1000 to 2000
- misc/recursive_iternext.py: provide more fine-grained selection of N
- pyb/rtc: make RTC test on pyboard more reliable by calling init()
mpy-cross:
- add -s option to specify the embedded source filename
unix port:
- mphalport: add mp_hal_delay_us() for consistency with other ports
- enable uerrno module
- add ability to include frozen bytecode in the build
- mpconfigport_coverage.h: add dedicated config file for coverage build
- unix_mphal: implement mp_hal_ticks_us()
- support frozen packages
- Makefile: nanbox build is not compatible with modussl, disable
- enable "ussl" module
- mpconfigport.mk: document MICROPY_STANDALONE make-level option
- Makefile: "make axtls": automatically fetch submodules if missing
windows port:
- enable multi-processor compilation for msvc
stmhal port:
- l4: adapt DMA to be able to support STM32L4 MCU series
- l4: adapt startup code, clock configuration and interrupts
- l4: make CCM/DTCM RAM start-up conditional on MCU type
- l4: add support for machine.sleep on STM32L4 MCUs
- dma: make DAC DMA descriptors conditional on having a DAC
- add board files for LIMIFROG board
- for LIMIFROG board, add early-init function to get to DFU mode
- dma: fix builds for boards with an F4 or F7 but no DAC
- sdcard: fix initialisation of DMA TX so that writes work
- can: allow to get existing CAN obj if constructed without args
- fix clock configuration for STM32L476-discovery; also add I2C2
- convert to use internal errno symbols; enable uerrno module
- for network drivers, convert to use MP_Exxx errno symbols
- led: allow LEDs to be in PWM mode with TIM1 and channels 1-4
- i2c: expose I2CHandle3 for use by custom C code
- sdcard: allow to do unaligned read-from/write-to SD card
- support frozen packages using .mpy files
- moduos: getcwd(): use mp_obj_new_exception_arg1()
- dac: add DAC deinit() method
- uart: fix wrong baudrate calculation for stm32l4 series
esp8266 port:
- scripts/: remove use of pin.PULL_NONE
- scripts/inisetup: don't start WebREPL on boot in master branch
- scripts/: add fill() to NeoPixel
- scripts/webrepl: add optional password argument to webrepl.start()
- scripts/webrepl: add start_foreground() method
- main: bump heap size to 28K
- mpconfigport: reduce various parser-related allocation params
- help: add "sta_if.active(True)" command
- convert to use new MP_Exxx errno symbols
- enable uerrno module, weak linked also as errno
- change to use internal errno's
- moduos.c: addition of the rename method to module uos
- scripts/port_diag: add network diagnostic output
- scripts/webrepl_setup: show password placeholder char
- scripts/webrepl_setup: add max password length check
- README: add a very first start section
- add APA102 serial individually controllable LEDs support
- enable collections.OrderedDict
- main: update _boot module loading for recent frozen modules refactors
- scripts/port_diag: dump network interface IP settings
- esp_mphal: fix NLR buffer leak in call_dupterm_read()
- esp_mphal: handle Ctrl+C from dupterm (e.g. WebREPL)
- esp_mphal: mp_uos_dupterm_deactivate() may raise exception
- add mp_hal_pin_input() and mp_hal_pin_output() functions
- modpybspi: configure pins when initialising an SPI object
- xtirq: add xtirq.h for controlling xtensa irqs
- ets_alt_task: don't run ets_loop_iter if irqs are disabled
- modmachine: add disable_irq and enable_irq functions
- enable DHT C-level driver
- add dht.py script for high-level control of DHT11/DHT22 sensor
- Makefile: document "disable" value for UART_OS
- modnetwork: scan() is only supported by STA when it's enabled
- modnetwork: protect scan() callback against memory errors
- modnetwork: allow to press ctrl-C while scan() is running
- uart: properly initialise UART0 RXD pin in uart_config
- moduos: add chdir() and getcwd() functions
- scripts/ntptime: allow to override NTP server
- modmachine: add machine.time_pulse_us function
- enable MICROPY_PY_IO_FILEIO to get compliant text/binary streams
- moduos.c: add stat() to the module uos of esp8266
- rtc: set RTC user memory length to 0 on first boot
- provide a dedicated variable to disable ets_loop_iter
- modpybrtc: handle RTC overflow
docs:
- machine.UART: filter out unimplemented UART methods from esp8266 docs
- esp8266/quickref: new way to get MAC address
- esp8266/quickstart: remove i2c examples with stop=False
- ustruct: describe supported type codes
- ussl: add basic description of axTLS-based modussl
- esp8266: Include ussl module in the docs
- machine: make disable_irq and enable_irq docs available for all
- library/machine: add documentation for machine.time_pulse_us
- math, cmath: add port availability information
- library/index: add intro paragraph regarding availability of modules
- README: add some hints for PDF docs generation
- wipy/tutorial: add note about screen key bindings on OS X
- esp8266/quickref: update WebREPL section for 1.8.1 release
- esp8266: fix ESP8266 Network tutorial
- esp8266/quickref: use local image of Adafruit Huzzah board
- esp8266/general: add note about RTC overflow
travis:
- install gcc-arm-none-eabi with --force-yes for now
Diffstat (limited to 'extmod')
-rw-r--r-- | extmod/fsusermount.c | 2 | ||||
-rw-r--r-- | extmod/machine_i2c.c | 8 | ||||
-rw-r--r-- | extmod/machine_pulse.c | 67 | ||||
-rw-r--r-- | extmod/machine_pulse.h | 37 | ||||
-rw-r--r-- | extmod/misc.h | 1 | ||||
-rw-r--r-- | extmod/modlwip.c | 132 | ||||
-rw-r--r-- | extmod/modubinascii.c | 2 | ||||
-rw-r--r-- | extmod/moduos_dupterm.c | 15 | ||||
-rw-r--r-- | extmod/modussl.c | 36 | ||||
-rw-r--r-- | extmod/modwebrepl.c | 12 | ||||
-rw-r--r-- | extmod/modwebsocket.c | 18 | ||||
-rw-r--r-- | extmod/vfs_fat.c | 165 | ||||
-rw-r--r-- | extmod/vfs_fat_misc.c | 7 | ||||
-rw-r--r-- | extmod/virtpin.c | 39 | ||||
-rw-r--r-- | extmod/virtpin.h | 40 |
15 files changed, 469 insertions, 112 deletions
diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index 8f789ca033..9ddc98f3dd 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -32,7 +32,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs) { static const mp_arg_t allowed_args[] = { diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index e3bdb36925..ceddf0730e 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -48,7 +48,7 @@ STATIC void mp_hal_i2c_delay(machine_i2c_obj_t *self) { } STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) { - mp_hal_pin_low(self->scl); + mp_hal_pin_od_low(self->scl); } STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { @@ -56,7 +56,7 @@ STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) { } STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) { - mp_hal_pin_low(self->sda); + mp_hal_pin_od_low(self->sda); } STATIC void mp_hal_i2c_sda_release(machine_i2c_obj_t *self) { @@ -91,8 +91,8 @@ STATIC void mp_hal_i2c_init(machine_i2c_obj_t *self, uint32_t freq) { if (self->us_delay == 0) { self->us_delay = 1; } - mp_hal_pin_config_od(self->scl); - mp_hal_pin_config_od(self->sda); + mp_hal_pin_open_drain(self->scl); + mp_hal_pin_open_drain(self->sda); mp_hal_i2c_stop(self); } diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c new file mode 100644 index 0000000000..8c8bff510c --- /dev/null +++ b/extmod/machine_pulse.c @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/mperrno.h" +#include "extmod/machine_pulse.h" + +#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_uint_t start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) != pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-1; + } + } + start = mp_hal_ticks_us(); + while (mp_hal_pin_read(pin) == pulse_level) { + if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { + return (mp_uint_t)-1; + } + } + return mp_hal_ticks_us() - start; +} + +STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { + mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[0]); + int level = 0; + if (mp_obj_is_true(args[1])) { + level = 1; + } + mp_uint_t timeout_us = 1000000; + if (n_args > 2) { + timeout_us = mp_obj_get_int(args[2]); + } + mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); + if (us == (mp_uint_t)-1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); + } + return mp_obj_new_int(us); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); + +#endif diff --git a/extmod/machine_pulse.h b/extmod/machine_pulse.h new file mode 100644 index 0000000000..3d5d81c073 --- /dev/null +++ b/extmod/machine_pulse.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ +#define __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ + +#include "py/obj.h" +#include "py/mphal.h" + +mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); + +MP_DECLARE_CONST_FUN_OBJ(machine_time_pulse_us_obj); + +#endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ diff --git a/extmod/misc.h b/extmod/misc.h index 39bfd5ecb5..634ea924d0 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -34,6 +34,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM void mp_uos_dupterm_tx_strn(const char *str, size_t len); +void mp_uos_deactivate(const char *msg, mp_obj_t exc); #else #define mp_uos_dupterm_tx_strn(s, l) #endif diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 090e1005a8..cb7cc6596f 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -26,13 +26,13 @@ */ #include <string.h> -#include <errno.h> #include <stdio.h> #include "py/nlr.h" #include "py/objlist.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #include "py/mphal.h" #include "netutils.h" @@ -172,45 +172,45 @@ STATIC const mp_obj_type_t lwip_slip_type = { // investigate in more detail. #if LWIP_VERSION < 0x01040100 static const int error_lookup_table[] = { - 0, /* ERR_OK 0 No error, everything OK. */ - ENOMEM, /* ERR_MEM -1 Out of memory error. */ - ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ - EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ - EINVAL, /* ERR_VAL -6 Illegal value. */ - EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ - - ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ - ECONNRESET, /* ERR_RST -9 Connection reset. */ - ENOTCONN, /* ERR_CLSD -10 Connection closed. */ - ENOTCONN, /* ERR_CONN -11 Not connected. */ - EIO, /* ERR_ARG -12 Illegal argument. */ - EADDRINUSE, /* ERR_USE -13 Address in use. */ - -1, /* ERR_IF -14 Low-level netif error */ - EALREADY, /* ERR_ISCONN -15 Already connected. */ - EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_ECONNABORTED, /* ERR_ABRT -8 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -9 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -10 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -11 Not connected. */ + MP_EIO, /* ERR_ARG -12 Illegal argument. */ + MP_EADDRINUSE, /* ERR_USE -13 Address in use. */ + -1, /* ERR_IF -14 Low-level netif error */ + MP_EALREADY, /* ERR_ISCONN -15 Already connected. */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; #else static const int error_lookup_table[] = { - 0, /* ERR_OK 0 No error, everything OK. */ - ENOMEM, /* ERR_MEM -1 Out of memory error. */ - ENOBUFS, /* ERR_BUF -2 Buffer error. */ - EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ - EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ - EINVAL, /* ERR_VAL -6 Illegal value. */ - EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ - - EADDRINUSE, /* ERR_USE -8 Address in use. */ - EALREADY, /* ERR_ISCONN -9 Already connected. */ - ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ - ECONNRESET, /* ERR_RST -11 Connection reset. */ - ENOTCONN, /* ERR_CLSD -12 Connection closed. */ - ENOTCONN, /* ERR_CONN -13 Not connected. */ - EIO, /* ERR_ARG -14 Illegal argument. */ - -1, /* ERR_IF -15 Low-level netif error */ - EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ + 0, /* ERR_OK 0 No error, everything OK. */ + MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */ + MP_ENOBUFS, /* ERR_BUF -2 Buffer error. */ + MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ + MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ + MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + MP_EINVAL, /* ERR_VAL -6 Illegal value. */ + MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + + MP_EADDRINUSE, /* ERR_USE -8 Address in use. */ + MP_EALREADY, /* ERR_ISCONN -9 Already connected. */ + MP_ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + MP_ECONNRESET, /* ERR_RST -11 Connection reset. */ + MP_ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + MP_ENOTCONN, /* ERR_CONN -13 Not connected. */ + MP_EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ + MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */ }; #endif @@ -311,6 +311,17 @@ STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pb return ERR_BUF; } +// "Poll" (idle) callback to be called ASAP after accept callback +// to execute Python callback function, as it can't be executed +// from accept callback itself. +STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb) +{ + lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; + tcp_poll(pcb, NULL, 0); + exec_user_callback(socket); + return ERR_OK; +} + // Callback for incoming tcp connections. STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg; @@ -323,7 +334,12 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { return ERR_BUF; } else { socket->incoming.connection = newpcb; - exec_user_callback(socket); + if (socket->callback != MP_OBJ_NULL) { + // Schedule accept callback to be called when lwIP is done + // with processing this incoming connection on its side and + // is idle. + tcp_poll(newpcb, _lwip_tcp_accept_finished, 1); + } return ERR_OK; } } @@ -363,7 +379,7 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // FIXME: maybe PBUF_ROM? struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (p == NULL) { - *_errno = ENOMEM; + *_errno = MP_ENOMEM; return -1; } @@ -401,7 +417,7 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ if (socket->incoming.pbuf != NULL) break; } if (socket->incoming.pbuf == NULL) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return -1; } } else { @@ -444,7 +460,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui if (available == 0) { // Non-blocking socket if (socket->timeout == 0) { - *_errno = EAGAIN; + *_errno = MP_EAGAIN; return MP_STREAM_ERROR; } @@ -457,7 +473,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui // Avoid sending too small packets, so wait until at least 16 bytes available while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return MP_STREAM_ERROR; } poll_sockets(); @@ -491,14 +507,14 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ if (socket->state == STATE_PEER_CLOSED) { return 0; } - *_errno = EAGAIN; + *_errno = MP_EAGAIN; return -1; } mp_uint_t start = mp_hal_ticks_ms(); while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) { if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { - *_errno = ETIMEDOUT; + *_errno = MP_ETIMEDOUT; return -1; } poll_sockets(); @@ -570,11 +586,11 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break; case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break; //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; - default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); } if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); } switch (socket->type) { @@ -670,15 +686,15 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { mp_int_t backlog = mp_obj_get_int(backlog_in); if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); } struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog); if (new_pcb == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); } socket->pcb.tcp = new_pcb; tcp_accept(new_pcb, _lwip_tcp_accept); @@ -691,15 +707,15 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP))); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); } // accept incoming connection @@ -710,7 +726,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); } } else { while (socket->incoming.connection == NULL) { @@ -757,7 +773,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF))); } // get address @@ -772,9 +788,9 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { case MOD_NETWORK_SOCK_STREAM: { if (socket->state != STATE_NEW) { if (socket->state == STATE_CONNECTED) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EALREADY))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EALREADY))); } else { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINPROGRESS))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINPROGRESS))); } } // Register our recieve callback. @@ -794,7 +810,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { if (socket->state != STATE_CONNECTING) break; } if (socket->state == STATE_CONNECTING) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT))); } } else { while (socket->state == STATE_CONNECTING) { @@ -982,7 +998,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { // most useful behavior is: check whether we will be able to send all of input // data without EAGAIN, and if won't be, raise it without sending any. if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EAGAIN))); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EAGAIN))); } } // TODO: In CPython3.5, socket timeout should apply to the diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 82f910b0e7..3cceb991f1 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -31,7 +31,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/binary.h" -#include "modubinascii.h" +#include "extmod/modubinascii.h" mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { diff --git a/extmod/moduos_dupterm.c b/extmod/moduos_dupterm.c index 41b8b3c81e..4c9f9e4940 100644 --- a/extmod/moduos_dupterm.c +++ b/extmod/moduos_dupterm.c @@ -31,9 +31,20 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/objtuple.h" +#include "py/stream.h" #if MICROPY_PY_OS_DUPTERM +void mp_uos_deactivate(const char *msg, mp_obj_t exc) { + mp_obj_t term = MP_STATE_PORT(term_obj); + MP_STATE_PORT(term_obj) = NULL; + mp_printf(&mp_plat_print, msg); + if (exc != MP_OBJ_NULL) { + mp_obj_print_exception(&mp_plat_print, exc); + } + mp_stream_close(term); +} + void mp_uos_dupterm_tx_strn(const char *str, size_t len) { if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { nlr_buf_t nlr; @@ -44,9 +55,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) { mp_call_method_n_kw(1, 0, write_m); nlr_pop(); } else { - MP_STATE_PORT(term_obj) = NULL; - mp_printf(&mp_plat_print, "dupterm: Exception in write() method, deactivating: "); - mp_obj_print_exception(&mp_plat_print, nlr.ret_val); + mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); } } } diff --git a/extmod/modussl.c b/extmod/modussl.c index 51f4fead81..567033cf48 100644 --- a/extmod/modussl.c +++ b/extmod/modussl.c @@ -78,12 +78,12 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, bool server_side) { STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - mp_obj_ssl_socket_t *self = self_in; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); 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) { - mp_obj_ssl_socket_t *o = o_in; + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); while (o->bytes_left == 0) { mp_int_t r = ssl_read(o->ssl_sock, &o->buf); @@ -113,7 +113,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc } STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { - mp_obj_ssl_socket_t *o = o_in; + mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in); mp_int_t r = ssl_write(o->ssl_sock, buf, size); if (r < 0) { *errcode = r; @@ -123,7 +123,7 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in } STATIC mp_obj_t socket_close(mp_obj_t self_in) { - mp_obj_ssl_socket_t *self = self_in; + mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); ssl_free(self->ssl_sock); ssl_ctx_free(self->ssl_ctx); @@ -133,13 +133,13 @@ STATIC mp_obj_t socket_close(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); -STATIC const mp_map_elem_t ussl_socket_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, +STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, }; STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table); @@ -157,10 +157,10 @@ STATIC const mp_obj_type_t ussl_socket_type = { .getiter = NULL, .iternext = NULL, .stream_p = &ussl_socket_stream_p, - .locals_dict = (mp_obj_t)&ussl_socket_locals_dict, + .locals_dict = (void*)&ussl_socket_locals_dict, }; -STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_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 static const mp_arg_t allowed_args[] = { { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, @@ -175,13 +175,13 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - return socket_new(sock, args.server_side.u_bool); + return MP_OBJ_FROM_PTR(socket_new(sock, args.server_side.u_bool)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket); -STATIC const mp_map_elem_t mp_module_ssl_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_wrap_socket), (mp_obj_t)&mod_ssl_wrap_socket_obj }, +STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) }, + { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table); @@ -195,6 +195,8 @@ const mp_obj_module_t mp_module_ussl = { // These functions might be split to stream_posix.c. They are referenced by // axtls os_port.h . +ssize_t mp_stream_posix_write(void *sock_obj, const void *buf, size_t len); +ssize_t mp_stream_posix_read(void *sock_obj, void *buf, size_t len); int mp_stream_errno; diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index c160abea2f..8ecab922aa 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -250,8 +250,8 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz); int err; - mp_uint_t res = mp_stream_writeall(self->cur_file, filebuf, buf_sz, &err); - if(res == MP_STREAM_ERROR) { + mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err); + if (err != 0 || res != buf_sz) { assert(0); } @@ -284,6 +284,13 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size return stream_p->write(self->sock, buf, size, errcode); } +STATIC mp_obj_t webrepl_close(mp_obj_t self_in) { + mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in); + // TODO: This is a place to do cleanup + return mp_stream_close(self->sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); + STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { mp_uint_t len; const char *passwd = mp_obj_str_get_data(passwd_in, &len); @@ -297,6 +304,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password) STATIC const mp_map_elem_t webrepl_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&webrepl_close_obj }, }; STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table); diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c index 344933ded3..fc5e29a05e 100644 --- a/extmod/modwebsocket.c +++ b/extmod/modwebsocket.c @@ -240,9 +240,9 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si mp_call_method_n_kw(1, 0, dest); } - mp_uint_t out_sz = mp_stream_writeall(self->sock, header, hdr_sz, errcode); - if (out_sz != MP_STREAM_ERROR) { - out_sz = mp_stream_writeall(self->sock, buf, size, errcode); + mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode); + if (*errcode == 0) { + out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode); } if (self->opts & BLOCKING_WRITE) { @@ -250,6 +250,9 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si mp_call_method_n_kw(1, 0, dest); } + if (*errcode != 0) { + return MP_STREAM_ERROR; + } return out_sz; } @@ -269,10 +272,19 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t } } +STATIC mp_obj_t websocket_close(mp_obj_t self_in) { + mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in); + // TODO: Send close signaling to the other side, otherwise it's + // abrupt close (connection abort). + return mp_stream_close(self->sock); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close); + STATIC const mp_map_elem_t websocket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ioctl), (mp_obj_t)&mp_stream_ioctl_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&websocket_close_obj }, }; STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index c52adfbe08..a4a81370f9 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -28,12 +28,14 @@ #include "py/mpconfig.h" #if MICROPY_VFS_FAT +#include <string.h> #include "py/nlr.h" #include "py/runtime.h" #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" +#include "timeutils.h" #define mp_obj_fat_vfs_t fs_user_mount_t @@ -79,12 +81,11 @@ STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { const char *path = mp_obj_str_get_str(path_in); // TODO check that path is actually a file before trying to unlink it FRESULT res = f_unlink(path); - switch (res) { - case FR_OK: - return mp_const_none; - default: - // TODO: standard errno's - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error removing file '%s'", path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); @@ -94,11 +95,11 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_ const char *old_path = mp_obj_str_get_str(path_in); const char *new_path = mp_obj_str_get_str(path_out); FRESULT res = f_rename(old_path, new_path); - switch (res) { - case FR_OK: - return mp_const_none; - default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error renaming file '%s' to '%s'", old_path, new_path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } @@ -108,25 +109,149 @@ STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { (void)vfs_in; const char *path = mp_obj_str_get_str(path_o); FRESULT res = f_mkdir(path); - switch (res) { - case FR_OK: - return mp_const_none; - case FR_EXIST: - // TODO should be FileExistsError - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "File exists: '%s'", path)); - default: - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "Error creating directory '%s'", path)); + if (res == FR_OK) { + return mp_const_none; + } else { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); +/// Change current directory. +STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + const char *path; + path = mp_obj_str_get_str(path_in); + + FRESULT res = f_chdrive(path); + + if (res == FR_OK) { + res = f_chdir(path); + } + + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); + +/// Get the current directory. +STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { + (void)vfs_in; + char buf[MICROPY_ALLOC_PATH_MAX + 1]; + FRESULT res = f_getcwd(buf, sizeof buf); + + if (res != FR_OK) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } + + return mp_obj_new_str(buf, strlen(buf), false); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); + +// Checks for path equality, ignoring trailing slashes: +// path_equal(/, /) -> true +// second argument must be in canonical form (meaning no trailing slash, unless it's just /) +STATIC bool path_equal(const char *path, const char *path_canonical) { + while (*path_canonical != '\0' && *path == *path_canonical) { + ++path; + ++path_canonical; + } + if (*path_canonical != '\0') { + return false; + } + while (*path == '/') { + ++path; + } + return *path == '\0'; +} + +/// \function stat(path) +/// Get the status of a file or directory. +STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + const char *path = mp_obj_str_get_str(path_in); + + FILINFO fno; +#if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; +#endif + FRESULT res; + + if (path_equal(path, "/")) { + // stat root directory + fno.fsize = 0; + fno.fdate = 0; + fno.ftime = 0; + fno.fattrib = AM_DIR; + } else { + res = FR_NO_PATH; + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL && path_equal(path, vfs->str)) { + // stat mounted device directory + fno.fsize = 0; + fno.fdate = 0; + fno.ftime = 0; + fno.fattrib = AM_DIR; + res = FR_OK; + } + } + if (res == FR_NO_PATH) { + // stat normal file + 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_TO_PTR(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 = timeutils_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 MP_OBJ_FROM_PTR(t); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); + STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&fat_vfs_listdir_obj) }, { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&fat_vfs_mkdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&fat_vfs_chdir_obj) }, + { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&fat_vfs_getcwd_obj) }, { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, + { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 145b624c2b..23fe4be88d 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -35,7 +35,7 @@ #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" -#include "fsusermount.h" +#include "extmod/fsusermount.h" #include "py/lexer.h" #if _USE_LFN @@ -54,8 +54,9 @@ mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { - // TODO should be mp_type_FileNotFoundError - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "No such file or directory: '%s'", path)); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + } mp_obj_t dir_list = mp_obj_new_list(0, NULL); diff --git a/extmod/virtpin.c b/extmod/virtpin.c new file mode 100644 index 0000000000..a5817ab4d0 --- /dev/null +++ b/extmod/virtpin.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "extmod/virtpin.h" + +int mp_virtual_pin_read(mp_obj_t pin) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + return pin_p->ioctl(pin, MP_PIN_READ, 0, NULL); +} + +void mp_virtual_pin_write(mp_obj_t pin, int value) { + mp_obj_base_t* s = (mp_obj_base_t*)MP_OBJ_TO_PTR(pin); + mp_pin_p_t *pin_p = (mp_pin_p_t*)s->type->stream_p; + pin_p->ioctl(pin, MP_PIN_WRITE, value, NULL); +} diff --git a/extmod/virtpin.h b/extmod/virtpin.h new file mode 100644 index 0000000000..3821f9dec5 --- /dev/null +++ b/extmod/virtpin.h @@ -0,0 +1,40 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/obj.h" + +#define MP_PIN_READ (1) +#define MP_PIN_WRITE (2) +#define MP_PIN_INPUT (3) +#define MP_PIN_OUTPUT (4) + +// Pin protocol +typedef struct _mp_pin_p_t { + mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode); +} mp_pin_p_t; + +int mp_virtual_pin_read(mp_obj_t pin); +void mp_virtual_pin_write(mp_obj_t pin, int value); |