summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/esp8266/general.rst40
-rw-r--r--docs/esp8266/quickref.rst11
-rw-r--r--docs/library/network.rst38
-rw-r--r--docs/library/pyb.Accel.rst1
-rw-r--r--docs/library/pyb.CAN.rst1
-rw-r--r--docs/library/pyb.LCD.rst1
-rw-r--r--docs/library/pyb.Switch.rst1
-rw-r--r--docs/library/pyb.USB_HID.rst1
-rw-r--r--docs/library/pyb.USB_VCP.rst1
-rw-r--r--docs/library/ure.rst2
-rw-r--r--docs/library/uselect.rst10
-rw-r--r--docs/library/usocket.rst59
-rw-r--r--docs/library/ussl.rst14
-rw-r--r--docs/pyboard/quickref.rst54
-rw-r--r--docs/pyboard/tutorial/leds.rst8
-rw-r--r--docs/reference/isr_rules.rst2
-rw-r--r--drivers/display/ssd1306.py21
-rw-r--r--drivers/wiznet5k/ethernet/socket.c13
-rw-r--r--drivers/wiznet5k/ethernet/w5500/w5500.c10
-rw-r--r--drivers/wiznet5k/ethernet/w5500/w5500.h1
-rw-r--r--drivers/wiznet5k/ethernet/wizchip_conf.h2
-rw-r--r--examples/hwapi/hwconfig_console.py6
-rw-r--r--extmod/misc.h3
-rw-r--r--extmod/modlwip.c2
-rw-r--r--extmod/modussl_axtls.c9
-rw-r--r--extmod/modussl_mbedtls.c26
-rw-r--r--extmod/modutimeq.c2
-rw-r--r--extmod/modwebrepl.c2
-rw-r--r--extmod/uos_dupterm.c104
-rw-r--r--extmod/vfs.c7
m---------lib/axtls0
-rw-r--r--lib/libm/math.c10
-rw-r--r--ports/esp8266/esp_mphal.c37
-rw-r--r--ports/esp8266/machine_hspi.c2
-rw-r--r--ports/esp8266/machine_wdt.c2
-rw-r--r--ports/esp8266/main.c3
-rw-r--r--ports/esp8266/modnetwork.c44
-rw-r--r--ports/esp8266/modules/webrepl_setup.py9
-rw-r--r--ports/minimal/frozentest.mpybin255 -> 255 bytes
-rw-r--r--ports/stm32/Makefile6
-rw-r--r--ports/stm32/boards/stm32f767_af.csv8
-rw-r--r--ports/stm32/modnwcc3k.c2
-rw-r--r--ports/stm32/modnwwiznet5k.c48
-rw-r--r--ports/stm32/modpyb.c26
-rw-r--r--ports/stm32/moduos.c25
-rw-r--r--ports/stm32/modusocket.c55
-rw-r--r--ports/stm32/mpconfigport.h8
-rw-r--r--ports/stm32/mpconfigport.mk5
-rw-r--r--ports/stm32/mphalport.c26
-rw-r--r--ports/stm32/uart.c15
-rw-r--r--ports/stm32/uart.h1
-rw-r--r--ports/stm32/usb.c14
-rw-r--r--ports/stm32/usb.h1
-rw-r--r--ports/stm32/usbd_cdc_interface.c6
-rw-r--r--ports/stm32/usbd_cdc_interface.h4
-rw-r--r--ports/teensy/teensy_hal.c1
-rw-r--r--ports/teensy/uart.c2
-rw-r--r--ports/unix/Makefile2
-rw-r--r--ports/unix/modjni.c2
-rw-r--r--ports/unix/modusocket.c (renamed from ports/unix/modsocket.c)26
-rw-r--r--ports/unix/mpconfigport.h1
-rw-r--r--ports/unix/unix_mphal.c17
-rw-r--r--ports/zephyr/main.c5
-rw-r--r--ports/zephyr/prj_base.conf14
-rw-r--r--ports/zephyr/prj_qemu_cortex_m3.conf4
-rw-r--r--ports/zephyr/prj_qemu_x86.conf4
-rw-r--r--ports/zephyr/src/zephyr_start.c5
-rw-r--r--ports/zephyr/uart_core.c14
-rw-r--r--py/argcheck.c2
-rw-r--r--py/bc.c6
-rw-r--r--py/bc0.h4
-rw-r--r--py/emitnative.c43
-rw-r--r--py/formatfloat.c13
-rw-r--r--py/makeqstrdata.py10
-rw-r--r--py/mkenv.mk6
-rw-r--r--py/mkrules.mk6
-rw-r--r--py/modbuiltins.c25
-rw-r--r--py/modmath.c73
-rw-r--r--py/mpconfig.h22
-rw-r--r--py/mpstate.h2
-rw-r--r--py/nativeglue.c3
-rw-r--r--py/objarray.c2
-rw-r--r--py/objlist.c4
-rw-r--r--py/objtype.c98
-rw-r--r--py/persistentcode.c2
-rw-r--r--py/runtime.c7
-rw-r--r--py/runtime.h4
-rw-r--r--py/runtime0.h38
-rw-r--r--py/showbc.c4
-rw-r--r--py/vmentrytable.h4
-rw-r--r--shared-module/multiterminal/__init__.c8
-rw-r--r--tests/cmdline/cmd_showbc.py.exp14
-rw-r--r--tests/extmod/ure1.py5
-rw-r--r--tests/float/complex1.py1
-rw-r--r--tests/float/float1.py1
-rw-r--r--tests/float/math_domain.py51
-rw-r--r--tests/float/math_domain_special.py36
-rw-r--r--tests/micropython/viper_binop_divmod.py18
-rw-r--r--tests/micropython/viper_binop_divmod.py.exp28
-rw-r--r--tests/net_inet/test_tls_sites.py5
-rw-r--r--tests/net_inet/test_tls_sites.py.exp1
-rwxr-xr-xtests/run-tests9
-rw-r--r--tests/unix/extra_coverage.py.exp4
-rwxr-xr-xtools/mpy-tool.py8
-rwxr-xr-xtools/pyboard.py9
105 files changed, 1006 insertions, 476 deletions
diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst
index e23acb469..96a454532 100644
--- a/docs/esp8266/general.rst
+++ b/docs/esp8266/general.rst
@@ -145,3 +145,43 @@ or by an exeption, for example using try/finally::
# Use sock
finally:
sock.close()
+
+
+SSL/TLS limitations
+~~~~~~~~~~~~~~~~~~~
+
+ESP8266 uses `axTLS <http://axtls.sourceforge.net/>`_ library, which is one
+of the smallest TLS libraries with the compatible licensing. However, it
+also has some known issues/limitations:
+
+1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve
+ cryptography (ECC). This means it can't work with sites which force
+ the use of these features (it works ok with classic RSA certifactes).
+2. Half-duplex communication nature. axTLS uses a single buffer for both
+ sending and receiving, which leads to considerable memory saving and
+ works well with protocols like HTTP. But there may be problems with
+ protocols which don't follow classic request-response model.
+
+Besides axTLS own limitations, the configuration used for MicroPython is
+highly optimized for code size, which leads to additional limitations
+(these may be lifted in the future):
+
+3. Optimized RSA algorithms are not enabled, which may lead to slow
+ SSL handshakes.
+4. Stored sessions are not supported (may allow faster repeated connections
+ to the same site in some circumstances).
+
+Besides axTLS specific limitations described above, there's another generic
+limitation with usage of TLS on the low-memory devices:
+
+5. The TLS standard specifies the maximum length of the TLS record (unit
+ of TLS communication, the entire record must be buffered before it can
+ be processed) as 16KB. That's almost half of the available ESP8266 memory,
+ and inside a more or less advanced application would be hard to allocate
+ due to memory fragmentation issues. As a compromise, a smaller buffer is
+ used, with the idea that the most interesting usage for SSL would be
+ accessing various REST APIs, which usually require much smaller messages.
+ The buffers size is on the order of 5KB, and is adjusted from time to
+ time, taking as a reference being able to access https://google.com .
+ The smaller buffer hower means that some sites can't be accessed using
+ it, and it's not possible to stream large amounts of data.
diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst
index ccf6365c8..c510e4064 100644
--- a/docs/esp8266/quickref.rst
+++ b/docs/esp8266/quickref.rst
@@ -223,6 +223,17 @@ and is accessed via the :ref:`machine.I2C <machine.I2C>` class::
buf = bytearray(10) # create a buffer with 10 bytes
i2c.writeto(0x3a, buf) # write the given buffer to the slave
+Real time clock (RTC)
+---------------------
+
+See :ref:`machine.RTC <machine.RTC>` ::
+
+ from machine import RTC
+
+ rtc = RTC()
+ rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
+ rtc.datetime() # get date and time
+
Deep-sleep mode
---------------
diff --git a/docs/library/network.rst b/docs/library/network.rst
index def6bee74..99a7c242c 100644
--- a/docs/library/network.rst
+++ b/docs/library/network.rst
@@ -72,8 +72,7 @@ parameter should be `id`.
connection parameters. For various medium types, there are different
sets of predefined/recommended parameters, among them:
- * WiFi: *bssid* keyword to connect by BSSID (MAC address) instead
- of access point name
+ * WiFi: *bssid* keyword to connect to a specific BSSID (MAC address)
.. method:: disconnect()
@@ -225,7 +224,9 @@ parameter should be `id`.
==============
This class allows you to control WIZnet5x00 Ethernet adaptors based on
- the W5200 and W5500 chipsets (only W5200 tested).
+ the W5200 and W5500 chipsets. The particular chipset that is supported
+ by the firmware is selected at compile-time via the MICROPY_PY_WIZNET5K
+ option.
Example usage::
@@ -269,6 +270,11 @@ parameter should be `id`.
Methods
-------
+ .. method:: wiznet5k.isconnected()
+
+ Returns ``True`` if the physical Ethernet link is connected and up.
+ Returns ``False`` otherwise.
+
.. method:: wiznet5k.ifconfig([(ip, subnet, gateway, dns)])
Get/set IP address, subnet mask, gateway and DNS.
@@ -333,9 +339,12 @@ parameter should be `id`.
argument is passed. Otherwise, query current state if no argument is
provided. Most other methods require active interface.
- .. method:: wlan.connect(ssid, password)
+ .. method:: wlan.connect(ssid=None, password=None, \*, bssid=None)
Connect to the specified wireless network, using the specified password.
+ If *bssid* is given then the connection will be restricted to the
+ access-point with that MAC address (the *ssid* must also be specified
+ in this case).
.. method:: wlan.disconnect()
@@ -413,16 +422,17 @@ parameter should be `id`.
Following are commonly supported parameters (availability of a specific parameter
depends on network technology type, driver, and `MicroPython port`).
- ========= ===========
- Parameter Description
- ========= ===========
- mac MAC address (bytes)
- essid WiFi access point name (string)
- channel WiFi channel (integer)
- hidden Whether ESSID is hidden (boolean)
- authmode Authentication mode supported (enumeration, see module constants)
- password Access password (string)
- ========= ===========
+ ============= ===========
+ Parameter Description
+ ============= ===========
+ mac MAC address (bytes)
+ essid WiFi access point name (string)
+ channel WiFi channel (integer)
+ hidden Whether ESSID is hidden (boolean)
+ authmode Authentication mode supported (enumeration, see module constants)
+ password Access password (string)
+ dhcp_hostname The DHCP hostname to use
+ ============= ===========
diff --git a/docs/library/pyb.Accel.rst b/docs/library/pyb.Accel.rst
index 061996485..9ade5c5c8 100644
--- a/docs/library/pyb.Accel.rst
+++ b/docs/library/pyb.Accel.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.Accel:
class Accel -- accelerometer control
====================================
diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst
index 9e71f12b0..232d04d96 100644
--- a/docs/library/pyb.CAN.rst
+++ b/docs/library/pyb.CAN.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.CAN:
class CAN -- controller area network communication bus
======================================================
diff --git a/docs/library/pyb.LCD.rst b/docs/library/pyb.LCD.rst
index 83cf890b6..5ab127edc 100644
--- a/docs/library/pyb.LCD.rst
+++ b/docs/library/pyb.LCD.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.LCD:
class LCD -- LCD control for the LCD touch-sensor pyskin
========================================================
diff --git a/docs/library/pyb.Switch.rst b/docs/library/pyb.Switch.rst
index 0d5dc63b7..e5ab6bd84 100644
--- a/docs/library/pyb.Switch.rst
+++ b/docs/library/pyb.Switch.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.Switch:
class Switch -- switch object
=============================
diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst
index 7d17c3099..702704435 100644
--- a/docs/library/pyb.USB_HID.rst
+++ b/docs/library/pyb.USB_HID.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.USB_HID:
class USB_HID -- USB Human Interface Device (HID)
=================================================
diff --git a/docs/library/pyb.USB_VCP.rst b/docs/library/pyb.USB_VCP.rst
index 4c4fe4516..80cc40cdd 100644
--- a/docs/library/pyb.USB_VCP.rst
+++ b/docs/library/pyb.USB_VCP.rst
@@ -1,4 +1,5 @@
.. currentmodule:: pyb
+.. _pyb.USB_VCP:
class USB_VCP -- USB virtual comm port
======================================
diff --git a/docs/library/ure.rst b/docs/library/ure.rst
index 67f4f54a1..ebae1db5f 100644
--- a/docs/library/ure.rst
+++ b/docs/library/ure.rst
@@ -34,6 +34,8 @@ Supported operators are:
``'+?'``
+``'|'``
+
``'()'``
Grouping. Each group is capturing (a substring it captures can be accessed
with `match.group()` method).
diff --git a/docs/library/uselect.rst b/docs/library/uselect.rst
index e330207db..beffce69a 100644
--- a/docs/library/uselect.rst
+++ b/docs/library/uselect.rst
@@ -66,12 +66,18 @@ Methods
Tuples returned may contain more than 2 elements as described above.
-.. method:: poll.ipoll([timeout])
+.. method:: poll.ipoll(timeout=-1, flags=0)
Like :meth:`poll.poll`, but instead returns an iterator which yields
- callee-owned tuples. This function provides efficient, allocation-free
+ `callee-owned tuples`. This function provides efficient, allocation-free
way to poll on streams.
+ If *flags* is 1, one-shot behavior for events is employed: streams for
+ which events happened, event mask will be automatically reset (equivalent
+ to ``poll.modify(obj, 0)``), so new events for such a stream won't be
+ processed until new mask is set with `poll.modify()`. This behavior is
+ useful for asynchronous I/O schedulers.
+
.. admonition:: Difference to CPython
:class: attention
diff --git a/docs/library/usocket.rst b/docs/library/usocket.rst
index dfdcd68bc..fab05b652 100644
--- a/docs/library/usocket.rst
+++ b/docs/library/usocket.rst
@@ -68,7 +68,16 @@ Functions
.. function:: socket(af=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP)
- Create a new socket using the given address family, socket type and protocol number.
+ Create a new socket using the given address family, socket type and
+ protocol number. Note that specifying *proto* in most cases is not
+ required (and not recommended, as some MicroPython ports may omit
+ ``IPPROTO_*`` constants). Instead, *type* argument will select needed
+ protocol automatically::
+
+ # Create STREAM TCP socket
+ socket(AF_INET, SOCK_STREAM)
+ # Create DGRAM UDP socket
+ socket(AF_INET, SOCK_DGRAM)
.. function:: getaddrinfo(host, port)
@@ -80,8 +89,8 @@ Functions
The following example shows how to connect to a given url::
- s = socket.socket()
- s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
+ s = usocket.socket()
+ s.connect(usocket.getaddrinfo('www.micropython.org', 80)[0][-1])
.. admonition:: Difference to CPython
:class: attention
@@ -96,13 +105,29 @@ Functions
from an exception object). The use of negative values is a provisional
detail which may change in the future.
+.. function:: inet_ntop(af, bin_addr)
+
+ Convert a binary network address *bin_addr* of the given address family *af*
+ to a textual representation::
+
+ >>> usocket.inet_ntop(usocket.AF_INET, b"\x7f\0\0\1")
+ '127.0.0.1'
+
+.. function:: inet_pton(af, txt_addr)
+
+ Convert a textual network address *txt_addr* of the given address family *af*
+ to a binary representation::
+
+ >>> usocket.inet_pton(usocket.AF_INET, "1.2.3.4")
+ b'\x01\x02\x03\x04'
+
Constants
---------
.. data:: AF_INET
AF_INET6
- Address family types. Availability depends on a particular board.
+ Address family types. Availability depends on a particular `MicroPython port`.
.. data:: SOCK_STREAM
SOCK_DGRAM
@@ -112,7 +137,11 @@ Constants
.. data:: IPPROTO_UDP
IPPROTO_TCP
- IP protocol numbers.
+ IP protocol numbers. Availability depends on a particular `MicroPython port`.
+ Note that you don't need to specify these in a call to `usocket.socket()`,
+ because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and
+ `SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants
+ is as an argument to `setsockopt()`.
.. data:: usocket.SOL_*
@@ -208,12 +237,30 @@ Methods
.. method:: socket.settimeout(value)
+ **Note**: Not every port supports this method, see below.
+
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
will raise an `OSError` exception if the timeout period value has elapsed before the operation has
completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket
is put in blocking mode.
+ Not every `MicroPython port` supports this method. A more portable and
+ generic solution is to use `uselect.poll` object. This allows to wait on
+ multiple objects at the same time (and not just on sockets, but on generic
+ stream objects which support polling). Example::
+
+ # Instead of:
+ s.settimeout(1.0) # time in seconds
+ s.read(10) # may timeout
+
+ # Use:
+ poller = uselect.poll()
+ poller.register(s, uselect.POLLIN)
+ res = poller.poll(1000) # time in milliseconds
+ if not res:
+ # s is still not ready for input, i.e. operation timed out
+
.. admonition:: Difference to CPython
:class: attention
@@ -281,7 +328,7 @@ Methods
Return value: number of bytes written.
-.. exception:: socket.error
+.. exception:: usocket.error
MicroPython does NOT have this exception.
diff --git a/docs/library/ussl.rst b/docs/library/ussl.rst
index c71b283cc..3ec609f67 100644
--- a/docs/library/ussl.rst
+++ b/docs/library/ussl.rst
@@ -13,7 +13,7 @@ facilities for network sockets, both client-side and server-side.
Functions
---------
-.. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)
+.. function:: ussl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, ca_certs=None)
Takes a stream *sock* (usually usocket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
@@ -23,12 +23,12 @@ Functions
server-side SSL socket should be created from a normal socket returned from
`accept()` on a non-SSL listening server socket.
- Depending on the underlying module implementation for a particular board,
- some or all keyword arguments above may be not supported.
+ Depending on the underlying module implementation in a particular
+ `MicroPython port`, some or all keyword arguments above may be not supported.
.. warning::
- Some implementations of ``ssl`` module do NOT validate server certificates,
+ Some implementations of ``ussl`` module do NOT validate server certificates,
which makes an SSL connection established prone to man-in-the-middle attacks.
Exceptions
@@ -41,8 +41,8 @@ Exceptions
Constants
---------
-.. data:: ssl.CERT_NONE
- ssl.CERT_OPTIONAL
- ssl.CERT_REQUIRED
+.. data:: ussl.CERT_NONE
+ ussl.CERT_OPTIONAL
+ ussl.CERT_REQUIRED
Supported values for *cert_reqs* parameter.
diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst
index 5690dddb0..48798aad3 100644
--- a/docs/pyboard/quickref.rst
+++ b/docs/pyboard/quickref.rst
@@ -39,17 +39,32 @@ Use the :mod:`time <utime>` module::
start = time.ticks_ms() # get value of millisecond counter
delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
-LEDs
-----
+Internal LEDs
+-------------
See :ref:`pyb.LED <pyb.LED>`. ::
from pyb import LED
- led = LED(1) # red led
+ led = LED(1) # 1=red, 2=green, 3=yellow, 4=blue
led.toggle()
led.on()
led.off()
+
+ # LEDs 3 and 4 support PWM intensity (0-255)
+ LED(4).intensity() # get intensity
+ LED(4).intensity(128) # set intensity to half
+
+Internal switch
+---------------
+
+See :ref:`pyb.Switch <pyb.Switch>`. ::
+
+ from pyb import Switch
+
+ sw = Switch()
+ sw.value() # returns True or False
+ sw.callback(lambda: pyb.LED(1).toggle())
Pins and GPIO
-------------
@@ -99,6 +114,17 @@ See :ref:`pyb.Timer <pyb.Timer>`. ::
tim.freq(0.5) # 0.5 Hz
tim.callback(lambda t: pyb.LED(1).toggle())
+RTC (real time clock)
+---------------------
+
+See :ref:`pyb.RTC <pyb.RTC>` ::
+
+ from pyb import RTC
+
+ rtc = RTC()
+ rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
+ rtc.datetime() # get date and time
+
PWM (pulse width modulation)
----------------------------
@@ -167,3 +193,25 @@ See :ref:`pyb.I2C <pyb.I2C>`. ::
i2c.recv(5, 0x42) # receive 5 bytes from slave
i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10
i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10
+
+CAN bus (controller area network)
+---------------------------------
+
+See :ref:`pyb.CAN <pyb.CAN>`. ::
+
+ from pyb import CAN
+
+ can = CAN(1, CAN.LOOPBACK)
+ can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))
+ can.send('message!', 123) # send a message with id 123
+ can.recv(0) # receive message on FIFO 0
+
+Internal accelerometer
+----------------------
+
+See :ref:`pyb.Accel <pyb.Accel>`. ::
+
+ from pyb import Accel
+
+ accel = Accel()
+ print(accel.x(), accel.y(), accel.z(), accel.tilt())
diff --git a/docs/pyboard/tutorial/leds.rst b/docs/pyboard/tutorial/leds.rst
index 763eedf01..6b05f5db0 100644
--- a/docs/pyboard/tutorial/leds.rst
+++ b/docs/pyboard/tutorial/leds.rst
@@ -60,10 +60,10 @@ One problem you might find is that if you stop the script and then start it agai
for l in leds:
l.off()
-The Fourth Special LED
-----------------------
+The Special LEDs
+----------------
-The blue LED is special. As well as turning it on and off, you can control the intensity using the intensity() method. This takes a number between 0 and 255 that determines how bright it is. The following script makes the blue LED gradually brighter then turns it off again. ::
+The yellow and blue LEDs are special. As well as turning them on and off, you can control their intensity using the intensity() method. This takes a number between 0 and 255 that determines how bright it is. The following script makes the blue LED gradually brighter then turns it off again. ::
led = pyb.LED(4)
intensity = 0
@@ -72,4 +72,4 @@ The blue LED is special. As well as turning it on and off, you can control the i
led.intensity(intensity)
pyb.delay(20)
-You can call intensity() on the other LEDs but they can only be off or on. 0 sets them off and any other number up to 255 turns them on.
+You can call intensity() on LEDs 1 and 2 but they can only be off or on. 0 sets them off and any other number up to 255 turns them on.
diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst
index 5009f30f7..2db261c09 100644
--- a/docs/reference/isr_rules.rst
+++ b/docs/reference/isr_rules.rst
@@ -80,7 +80,7 @@ example causes two LED's to flash at different rates.
self.led.toggle()
red = Foo(pyb.Timer(4, freq=1), pyb.LED(1))
- greeen = Foo(pyb.Timer(2, freq=0.8), pyb.LED(2))
+ green = Foo(pyb.Timer(2, freq=0.8), pyb.LED(2))
In this example the ``red`` instance associates timer 4 with LED 1: when a timer 4 interrupt occurs ``red.cb()``
is called causing LED 1 to change state. The ``green`` instance operates similarly: a timer 2 interrupt
diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py
index d65f2d350..cd358d00e 100644
--- a/drivers/display/ssd1306.py
+++ b/drivers/display/ssd1306.py
@@ -1,7 +1,6 @@
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
-import time
import framebuf
@@ -47,7 +46,6 @@ class SSD1306:
self.text = fb.text
self.scroll = fb.scroll
self.blit = fb.blit
- self.poweron()
self.init_display()
def init_display(self):
@@ -80,6 +78,9 @@ class SSD1306:
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
+ def poweron(self):
+ self.write_cmd(SET_DISP | 0x01)
+
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
@@ -123,9 +124,6 @@ class SSD1306_I2C(SSD1306):
self.i2c.write(buf)
self.i2c.stop()
- def poweron(self):
- pass
-
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
@@ -137,6 +135,12 @@ class SSD1306_SPI(SSD1306):
self.dc = dc
self.res = res
self.cs = cs
+ import time
+ self.res(1)
+ time.sleep_ms(1)
+ self.res(0)
+ time.sleep_ms(10)
+ self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
@@ -154,10 +158,3 @@ class SSD1306_SPI(SSD1306):
self.cs(0)
self.spi.write(buf)
self.cs(1)
-
- def poweron(self):
- self.res(1)
- time.sleep_ms(1)
- self.res(0)
- time.sleep_ms(10)
- self.res(1)
diff --git a/drivers/wiznet5k/ethernet/socket.c b/drivers/wiznet5k/ethernet/socket.c
index 129473ad4..ec25fcc79 100644
--- a/drivers/wiznet5k/ethernet/socket.c
+++ b/drivers/wiznet5k/ethernet/socket.c
@@ -52,10 +52,9 @@
#include <string.h>
+#include "py/mpthread.h"
#include "socket.h"
-extern void HAL_Delay(uint32_t);
-
#define SOCK_ANY_PORT_NUM 0xC000;
static uint16_t sock_any_port = SOCK_ANY_PORT_NUM;
@@ -242,7 +241,7 @@ int8_t WIZCHIP_EXPORT(connect)(uint8_t sn, uint8_t * addr, uint16_t port)
#endif
return SOCKERR_TIMEOUT;
}
- HAL_Delay(1);
+ MICROPY_THREAD_YIELD();
}
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
@@ -317,6 +316,7 @@ int32_t WIZCHIP_EXPORT(send)(uint8_t sn, uint8_t * buf, uint16_t len)
}
if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;
if(len <= freesize) break;
+ MICROPY_THREAD_YIELD();
}
wiz_send_data(sn, buf, len);
#if _WIZCHIP_ == 5200
@@ -368,7 +368,7 @@ int32_t WIZCHIP_EXPORT(recv)(uint8_t sn, uint8_t * buf, uint16_t len)
}
if((sock_io_mode & (1<<sn)) && (recvsize == 0)) return SOCK_BUSY;
if(recvsize != 0) break;
- HAL_Delay(1);
+ MICROPY_THREAD_YIELD();
};
if(recvsize < len) len = recvsize;
wiz_recv_data(sn, buf, len);
@@ -416,7 +416,7 @@ int32_t WIZCHIP_EXPORT(sendto)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t
if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
if( (sock_io_mode & (1<<sn)) && (len > freesize) ) return SOCK_BUSY;
if(len <= freesize) break;
- HAL_Delay(1);
+ MICROPY_THREAD_YIELD();
};
wiz_send_data(sn, buf, len);
@@ -446,7 +446,7 @@ int32_t WIZCHIP_EXPORT(sendto)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_t
return SOCKERR_TIMEOUT;
}
////////////
- HAL_Delay(1);
+ MICROPY_THREAD_YIELD();
}
#if _WIZCHIP_ == 5200 // for W5200 ARP errata
setSUBR((uint8_t*)"\x00\x00\x00\x00");
@@ -486,6 +486,7 @@ int32_t WIZCHIP_EXPORT(recvfrom)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_
if(getSn_SR(sn) == SOCK_CLOSED) return SOCKERR_SOCKCLOSED;
if( (sock_io_mode & (1<<sn)) && (pack_len == 0) ) return SOCK_BUSY;
if(pack_len != 0) break;
+ MICROPY_THREAD_YIELD();
};
}
sock_pack_info[sn] = PACK_COMPLETED;
diff --git a/drivers/wiznet5k/ethernet/w5500/w5500.c b/drivers/wiznet5k/ethernet/w5500/w5500.c
index 6b3111f99..3107b1b71 100644
--- a/drivers/wiznet5k/ethernet/w5500/w5500.c
+++ b/drivers/wiznet5k/ethernet/w5500/w5500.c
@@ -57,6 +57,16 @@
////////////////////////////////////////////////////
+#define LPC_SSP0 (0)
+
+static void Chip_SSP_ReadFrames_Blocking(int dummy, uint8_t *buf, uint32_t len) {
+ WIZCHIP.IF.SPI._read_bytes(buf, len);
+}
+
+static void Chip_SSP_WriteFrames_Blocking(int dummy, const uint8_t *buf, uint32_t len) {
+ WIZCHIP.IF.SPI._write_bytes(buf, len);
+}
+
uint8_t WIZCHIP_READ(uint32_t AddrSel)
{
uint8_t ret;
diff --git a/drivers/wiznet5k/ethernet/w5500/w5500.h b/drivers/wiznet5k/ethernet/w5500/w5500.h
index f0ffcb0c8..c2afb180e 100644
--- a/drivers/wiznet5k/ethernet/w5500/w5500.h
+++ b/drivers/wiznet5k/ethernet/w5500/w5500.h
@@ -44,7 +44,6 @@
#include <stdint.h>
#include "../wizchip_conf.h"
-#include "board.h"
#define _W5500_IO_BASE_ 0x00000000
diff --git a/drivers/wiznet5k/ethernet/wizchip_conf.h b/drivers/wiznet5k/ethernet/wizchip_conf.h
index 55c79ae0a..4a7a7bd69 100644
--- a/drivers/wiznet5k/ethernet/wizchip_conf.h
+++ b/drivers/wiznet5k/ethernet/wizchip_conf.h
@@ -56,7 +56,9 @@
* @todo You should select one, \b 5100, \b 5200 ,\b 5500 or etc. \n\n
* ex> <code> #define \_WIZCHIP_ 5500 </code>
*/
+#ifndef _WIZCHIP_
#define _WIZCHIP_ 5200 // 5100, 5200, 5500
+#endif
#define _WIZCHIP_IO_MODE_NONE_ 0x0000
#define _WIZCHIP_IO_MODE_BUS_ 0x0100 /**< Bus interface mode */
diff --git a/examples/hwapi/hwconfig_console.py b/examples/hwapi/hwconfig_console.py
index 4b0b0d79b..bbcc0e816 100644
--- a/examples/hwapi/hwconfig_console.py
+++ b/examples/hwapi/hwconfig_console.py
@@ -8,6 +8,12 @@ class LEDClass:
def value(self, v):
print(self.id, v)
+ def on(self):
+ self.value(1)
+
+ def off(self):
+ self.value(0)
+
LED = LEDClass(1)
LED2 = LEDClass(12)
diff --git a/extmod/misc.h b/extmod/misc.h
index 6c13592c7..d6f6d859c 100644
--- a/extmod/misc.h
+++ b/extmod/misc.h
@@ -35,8 +35,9 @@
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
#if MICROPY_PY_OS_DUPTERM
+int mp_uos_dupterm_rx_chr(void);
void mp_uos_dupterm_tx_strn(const char *str, size_t len);
-void mp_uos_deactivate(const char *msg, mp_obj_t exc);
+void mp_uos_deactivate(size_t dupterm_idx, 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 f7e776af9..bbb01b5d7 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -1032,7 +1032,7 @@ STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
break;
}
case MOD_NETWORK_SOCK_DGRAM:
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
break;
}
diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c
index 88a89a23d..3ad65ebf3 100644
--- a/extmod/modussl_axtls.c
+++ b/extmod/modussl_axtls.c
@@ -51,7 +51,11 @@ struct ssl_args {
STATIC const mp_obj_type_t ussl_socket_type;
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
+#if MICROPY_PY_USSL_FINALISER
+ mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
+#else
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
+#endif
o->base.type = &ussl_socket_type;
o->buf = NULL;
o->bytes_left = 0;
@@ -152,7 +156,7 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
// Currently supports only blocking mode
(void)self_in;
if (!mp_obj_is_true(flag_in)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
return mp_const_none;
}
@@ -178,6 +182,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+#if MICROPY_PY_USSL_FINALISER
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
+#endif
};
STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c
index d7316cb4a..69a64d2f7 100644
--- a/extmod/modussl_mbedtls.c
+++ b/extmod/modussl_mbedtls.c
@@ -65,23 +65,30 @@ struct ssl_args {
STATIC const mp_obj_type_t ussl_socket_type;
-void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
+#ifdef MBEDTLS_DEBUG_C
+STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
+ (void)ctx;
+ (void)level;
printf("DBG:%s:%04d: %s\n", file, line, str);
}
+#endif
// TODO: FIXME!
-int null_entropy_func(void *data, unsigned char *output, size_t len) {
+STATIC int null_entropy_func(void *data, unsigned char *output, size_t len) {
+ (void)data;
+ (void)output;
+ (void)len;
// enjoy random bytes
return 0;
}
-int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
+STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
int err;
- int out_sz = sock_stream->write(sock, buf, len, &err);
+ mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
if (out_sz == MP_STREAM_ERROR) {
if (mp_is_nonblocking_error(err)) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
@@ -92,13 +99,13 @@ int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
}
}
-int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
+STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
int err;
- int out_sz = sock_stream->read(sock, buf, len, &err);
+ mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
if (out_sz == MP_STREAM_ERROR) {
if (mp_is_nonblocking_error(err)) {
return MBEDTLS_ERR_SSL_WANT_READ;
@@ -111,7 +118,11 @@ int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
+#if MICROPY_PY_USSL_FINALISER
+ mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
+#else
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
+#endif
o->base.type = &ussl_socket_type;
int ret;
@@ -272,6 +283,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+#if MICROPY_PY_USSL_FINALISER
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
+#endif
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
};
diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c
index 0a836c7cc..28bbcc521 100644
--- a/extmod/modutimeq.c
+++ b/extmod/modutimeq.c
@@ -146,7 +146,7 @@ STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
}
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
if (!MP_OBJ_IS_TYPE(list_ref, &mp_type_list) || ret->len < 3) {
- mp_raise_TypeError("");
+ mp_raise_TypeError(NULL);
}
struct qentry *item = &heap->items[0];
diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c
index c5087ac29..38b88821b 100644
--- a/extmod/modwebrepl.c
+++ b/extmod/modwebrepl.c
@@ -308,7 +308,7 @@ STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) {
size_t len;
const char *passwd = mp_obj_str_get_data(passwd_in, &len);
if (len > sizeof(webrepl_passwd) - 1) {
- mp_raise_ValueError("");
+ mp_raise_ValueError(NULL);
}
strcpy(webrepl_passwd, passwd);
return mp_const_none;
diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c
index 54fb23a79..e5e6663b0 100644
--- a/extmod/uos_dupterm.c
+++ b/extmod/uos_dupterm.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2016 Paul Sokolovsky
+ * Copyright (c) 2017 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
@@ -31,61 +32,114 @@
#include "py/objtuple.h"
#include "py/objarray.h"
#include "py/stream.h"
+#include "lib/utils/interrupt_char.h"
#ifdef 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;
+void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
+ mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
+ MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_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);
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_stream_close(term);
+ nlr_pop();
+ } else {
+ // Ignore any errors during stream closing
+ }
+}
+
+int mp_uos_dupterm_rx_chr(void) {
+ for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
+ continue;
+ }
+
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_obj_t readinto_m[3];
+ mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m);
+ readinto_m[2] = MP_STATE_VM(dupterm_arr_obj);
+ mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
+ if (res == mp_const_none) {
+ nlr_pop();
+ } else if (res == MP_OBJ_NEW_SMALL_INT(0)) {
+ nlr_pop();
+ mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
+ nlr_pop();
+ if (*(byte*)bufinfo.buf == mp_interrupt_char) {
+ // Signal keyboard interrupt to be raised as soon as the VM resumes
+ mp_keyboard_interrupt();
+ return -2;
+ }
+ return *(byte*)bufinfo.buf;
+ }
+ } else {
+ mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
+ }
+ }
+
+ // No chars available
+ return -1;
}
void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
- if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) {
+ for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
+ continue;
+ }
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t write_m[3];
- mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_write, write_m);
+ mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m);
- mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj));
+ mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
void *org_items = arr->items;
arr->items = (void*)str;
arr->len = len;
- write_m[2] = MP_STATE_PORT(dupterm_arr_obj);
+ write_m[2] = MP_STATE_VM(dupterm_arr_obj);
mp_call_method_n_kw(1, 0, write_m);
- arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj));
+ arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
arr->items = org_items;
arr->len = 1;
nlr_pop();
} else {
- mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val);
+ mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val);
}
}
}
STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
- if (n_args == 0) {
- if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) {
- return mp_const_none;
- } else {
- return MP_STATE_PORT(term_obj);
- }
+ mp_int_t idx = 0;
+ if (n_args == 2) {
+ idx = mp_obj_get_int(args[1]);
+ }
+
+ if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) {
+ mp_raise_ValueError("invalid dupterm index");
+ }
+
+ mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]);
+ if (previous_obj == MP_OBJ_NULL) {
+ previous_obj = mp_const_none;
+ }
+ if (args[0] == mp_const_none) {
+ MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
} else {
- if (args[0] == mp_const_none) {
- MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
- } else {
- MP_STATE_PORT(term_obj) = args[0];
- if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) {
- MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
- }
+ MP_STATE_VM(dupterm_objs[idx]) = args[0];
+ if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) {
+ MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
}
- return mp_const_none;
}
+
+ return previous_obj;
}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 0, 1, mp_uos_dupterm);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm);
#endif
diff --git a/extmod/vfs.c b/extmod/vfs.c
index 586bb4b01..e83646d8d 100644
--- a/extmod/vfs.c
+++ b/extmod/vfs.c
@@ -38,6 +38,10 @@
#include "extmod/vfs_fat.h"
#endif
+// For mp_vfs_proxy_call, the maximum number of additional args that can be passed.
+// A fixed maximum size is used to avoid the need for a costly variable array.
+#define PROXY_MAX_ARGS (2)
+
// path is the path to lookup and *path_out holds the path within the VFS
// object (starts with / if an absolute path).
// Returns MP_VFS_ROOT for root dir (and then path_out is undefined) and
@@ -97,6 +101,7 @@ STATIC mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) {
}
STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) {
+ assert(n_args <= PROXY_MAX_ARGS);
if (vfs == MP_VFS_NONE) {
// mount point not found
mp_raise_OSError(MP_ENODEV);
@@ -105,7 +110,7 @@ STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_
// can't do operation on root dir
mp_raise_OSError(MP_EPERM);
}
- mp_obj_t meth[n_args + 2];
+ mp_obj_t meth[2 + PROXY_MAX_ARGS];
mp_load_method(vfs->obj, meth_name, meth);
if (args != NULL) {
memcpy(meth + 2, args, n_args * sizeof(*args));
diff --git a/lib/axtls b/lib/axtls
-Subproject 9b3092eb3b4b230a63c0c389bfbd3c55682c620
+Subproject dac9176cac58cc5e49669a9a4d404a6f6dd7cc1
diff --git a/lib/libm/math.c b/lib/libm/math.c
index 327a149b1..39c6a68a5 100644
--- a/lib/libm/math.c
+++ b/lib/libm/math.c
@@ -48,16 +48,6 @@ float copysignf(float x, float y) {
}
#endif
-// some compilers define log2f in terms of logf
-#ifdef log2f
-#undef log2f
-#endif
-// some compilers have _M_LN2 defined in math.h, some don't
-#ifndef _M_LN2
-#define _M_LN2 (0.69314718055994530942)
-#endif
-float log2f(float x) { return logf(x) / (float)_M_LN2; }
-
static const float _M_LN10 = 2.30258509299404; // 0x40135d8e
float log10f(float x) { return logf(x) / (float)_M_LN10; }
diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c
index 4f3ca5836..93ebc450a 100644
--- a/ports/esp8266/esp_mphal.c
+++ b/ports/esp8266/esp_mphal.c
@@ -159,41 +159,6 @@ void mp_hal_signal_input(void) {
#endif
}
-static int call_dupterm_read(void) {
- if (MP_STATE_PORT(term_obj) == NULL) {
- return -1;
- }
-
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_obj_t readinto_m[3];
- mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_readinto, readinto_m);
- readinto_m[2] = MP_STATE_PORT(dupterm_arr_obj);
- mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
- if (res == mp_const_none) {
- nlr_pop();
- return -2;
- }
- if (res == MP_OBJ_NEW_SMALL_INT(0)) {
- mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
- nlr_pop();
- return -1;
- }
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
- nlr_pop();
- if (*(byte*)bufinfo.buf == mp_interrupt_char) {
- mp_keyboard_interrupt();
- return -2;
- }
- return *(byte*)bufinfo.buf;
- } else {
- mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
- }
-
- return -1;
-}
-
STATIC void dupterm_task_handler(os_event_t *evt) {
static byte lock;
if (lock) {
@@ -201,7 +166,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
}
lock = 1;
while (1) {
- int c = call_dupterm_read();
+ int c = mp_uos_dupterm_rx_chr();
if (c < 0) {
break;
}
diff --git a/ports/esp8266/machine_hspi.c b/ports/esp8266/machine_hspi.c
index eaabbab7e..9fd0f4868 100644
--- a/ports/esp8266/machine_hspi.c
+++ b/ports/esp8266/machine_hspi.c
@@ -149,7 +149,7 @@ mp_obj_t machine_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// args[0] holds the id of the peripheral
if (args[0] != MP_OBJ_NEW_SMALL_INT(1)) {
// FlashROM is on SPI0, so far we don't support its usage
- mp_raise_ValueError("");
+ mp_raise_ValueError(NULL);
}
machine_hspi_obj_t *self = m_new_obj(machine_hspi_obj_t);
diff --git a/ports/esp8266/machine_wdt.c b/ports/esp8266/machine_wdt.c
index 04b42782e..4432297fa 100644
--- a/ports/esp8266/machine_wdt.c
+++ b/ports/esp8266/machine_wdt.c
@@ -51,7 +51,7 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args
case 0:
return &wdt_default;
default:
- mp_raise_ValueError("");
+ mp_raise_ValueError(NULL);
}
}
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index 04ea82761..c590ab59e 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -101,8 +101,7 @@ STATIC void mp_reset(void) {
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_FROZEN_FAKE_DIR_QSTR));
mp_obj_list_init(mp_sys_argv, 0);
- MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
- MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL;
+
reset_pins();
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
extern void esp_native_code_init(void);
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
index 2c61e5dcd..b41a11f59 100644
--- a/ports/esp8266/modnetwork.c
+++ b/ports/esp8266/modnetwork.c
@@ -93,29 +93,55 @@ STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
-STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *args) {
- require_if(args[0], STATION_IF);
+STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_ssid, ARG_password, ARG_bssid };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ require_if(pos_args[0], STATION_IF);
struct station_config config = {{0}};
size_t len;
const char *p;
+ bool set_config = false;
- if (n_args > 1) {
- p = mp_obj_str_get_data(args[1], &len);
+ // set parameters based on given args
+ if (args[ARG_ssid].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
len = MIN(len, sizeof(config.ssid));
memcpy(config.ssid, p, len);
- if (n_args > 2) {
- p = mp_obj_str_get_data(args[2], &len);
- len = MIN(len, sizeof(config.password));
- memcpy(config.password, p, len);
+ set_config = true;
+ }
+ if (args[ARG_password].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);
+ len = MIN(len, sizeof(config.password));
+ memcpy(config.password, p, len);
+ set_config = true;
+ }
+ if (args[ARG_bssid].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
+ if (len != sizeof(config.bssid)) {
+ mp_raise_ValueError(NULL);
}
+ config.bssid_set = 1;
+ memcpy(config.bssid, p, sizeof(config.bssid));
+ set_config = true;
+ }
+ if (set_config) {
error_check(wifi_station_set_config(&config), "Cannot set STA config");
}
error_check(wifi_station_connect(), "Cannot connect to AP");
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect);
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect);
STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
require_if(self_in, STATION_IF);
diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py
index 52c76863a..50d866b55 100644
--- a/ports/esp8266/modules/webrepl_setup.py
+++ b/ports/esp8266/modules/webrepl_setup.py
@@ -16,12 +16,9 @@ def getpass(prompt):
def input_pass():
while 1:
- passwd1 = getpass("New password: ")
- if len(passwd1) < 4:
- print("Password too short")
- continue
- elif len(passwd1) > 9:
- print("Password too long")
+ passwd1 = getpass("New password (4-9 chars): ")
+ if len(passwd1) < 4 or len(passwd1) > 9:
+ print("Invalid password length")
continue
passwd2 = getpass("Confirm password: ")
if passwd1 == passwd2:
diff --git a/ports/minimal/frozentest.mpy b/ports/minimal/frozentest.mpy
index 87f9581bf..7c6809bf6 100644
--- a/ports/minimal/frozentest.mpy
+++ b/ports/minimal/frozentest.mpy
Binary files differ
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index e3cb1b217..a6e82b24d 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -287,13 +287,13 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
class/src/usbd_msc_data.c \
)
-ifeq ($(MICROPY_PY_WIZNET5K),1)
+ifneq ($(MICROPY_PY_WIZNET5K),0)
WIZNET5K_DIR=drivers/wiznet5k
INC += -I$(TOP)/$(WIZNET5K_DIR)
-CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=1
+CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=$(MICROPY_PY_WIZNET5K) -D_WIZCHIP_=$(MICROPY_PY_WIZNET5K)
SRC_MOD += modnwwiznet5k.c
SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\
- ethernet/w5200/w5200.c \
+ ethernet/w$(MICROPY_PY_WIZNET5K)/w$(MICROPY_PY_WIZNET5K).c \
ethernet/wizchip_conf.c \
ethernet/socket.c \
internet/dns/dns.c \
diff --git a/ports/stm32/boards/stm32f767_af.csv b/ports/stm32/boards/stm32f767_af.csv
index db27818c6..1708dfcca 100644
--- a/ports/stm32/boards/stm32f767_af.csv
+++ b/ports/stm32/boards/stm32f767_af.csv
@@ -15,9 +15,9 @@ PortA,PA11,,TIM1_CH4,,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,,,LCD_R4,EVENTOUT
PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,SAI2_FS_B,CAN1_TX,OTG_FS_DP,,,,LCD_R5,EVENTOUT
PortA,PA13,JTMS,SWDIO,,,,,,,,,,,,,,EVENTOUT
PortA,PA14,JTCK,SWCLK,,,,,,,,,,,,,,EVENTOUT
-PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICE,CSPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT
-PortB,PB0,,TIM1_CH2N,TIM3_CH3T,IM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT
-PortB,PB1,,TIM1_CH3N,TIM3_CH4T,IM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT
+PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,HDMICEC,SPI1_NSS/I2S1_WS,SPI3_NSS/I2S3_WS,,UART4_RTS,,,,,,,EVENTOUT
+PortB,PB0,,TIM1_CH2N,TIM3_CH3T,TIM8_CH2N,,,,,UART4_CTS,LCD_R3,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT
+PortB,PB1,,TIM1_CH3N,TIM3_CH4T,TIM8_CH3N,,,,,,LCD_R6,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT
PortB,PB2,,,,,,,SAI1_SD_A,SPI3_MOSI/I2S3_SD,,QUADSPI_CLK,,,,,,EVENTOUT
PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK/I2S1_CK,SPI3_SCK/I2S3_CK,,,,SDMMC2_D2,,,,,EVENTOUT
PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,SPI2_NSS/I2S2_WS,,,SDMMC2_D3,,,,,EVENTOUT
@@ -41,7 +41,7 @@ PortC,PC5,,,,,,,,,SPDIFRX_IN3,,,ETH_MII_RXD1/ETH_RMII_RXD1,FMC_SDCKE0,,,EVENTOUT
PortC,PC6,,,TIM3_CH1,TIM8_CH1,,I2S2_MCK,,,USART6_TX,,SDMMC2_D6,,SDMMC1_D6,DCMI_D0,LCD_HSYNC,EVENTOUT
PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,I2S3_MCK,,USART6_RX,,SDMMC2_D7,,SDMMC1_D7,DCMI_D1,LCD_G6,EVENTOUT
PortC,PC8,TRACED1,,TIM3_CH3,TIM8_CH3,,,,UART5_RTS,USART6_CK,,,,SDMMC1_D0,DCMI_D2,,EVENTOUT
-PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT
+PortC,PC9,MCO2,,TIM3_CH4,TIM8_CH4,I2C3_SDA,I2S2_CKIN,,UART5_CTS,,QUADSPI_BK1_IO0,,,SDMMC1_D1,DCMI_D3,,EVENTOUT
PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,QUADSPI_BK1_IO1,,,SDMMC1_D2,DCMI_D8,LCD_R2,EVENTOUT
PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,QUADSPI_BK2_NCS,,,SDMMC1_D3,DCMI_D4,,EVENTOUT
PortC,PC12,TRACED3,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,SDMMC1_CK,DCMI_D9,,EVENTOUT
diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c
index 551206da8..8cc0a613d 100644
--- a/ports/stm32/modnwcc3k.c
+++ b/ports/stm32/modnwcc3k.c
@@ -125,7 +125,7 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin
if (ip == 0) {
// unknown host
- return MP_ENOENT;
+ return -2;
}
out_ip[0] = ip >> 24;
diff --git a/ports/stm32/modnwwiznet5k.c b/ports/stm32/modnwwiznet5k.c
index 21e4dbbbf..763137c70 100644
--- a/ports/stm32/modnwwiznet5k.c
+++ b/ports/stm32/modnwwiznet5k.c
@@ -30,6 +30,7 @@
#include "py/objlist.h"
#include "py/runtime.h"
+#include "py/stream.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "lib/netutils/netutils.h"
@@ -92,7 +93,7 @@ STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len,
return 0;
} else {
// failure
- return MP_ENOENT;
+ return -2;
}
}
@@ -173,11 +174,7 @@ STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_
int sr = getSn_SR((uint8_t)socket->u_param.fileno);
if (sr == SOCK_ESTABLISHED) {
socket2->u_param = socket->u_param;
- // TODO need to populate this with the correct values
- ip[0] = 0;
- ip[1] = 0;
- ip[2] = 0;
- ip[3] = 0;
+ getSn_DIPR((uint8_t)socket2->u_param.fileno, ip);
*port = getSn_PORT(socket2->u_param.fileno);
// WIZnet turns the listening socket into the client socket, so we
@@ -309,9 +306,19 @@ STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_
}
STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
- // TODO
- *_errno = MP_EINVAL;
- return -1;
+ if (request == MP_STREAM_POLL) {
+ int ret = 0;
+ if (arg & MP_STREAM_POLL_RD && getSn_RX_RSR(socket->u_param.fileno) != 0) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if (arg & MP_STREAM_POLL_WR && getSn_TX_FSR(socket->u_param.fileno) != 0) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ return ret;
+ } else {
+ *_errno = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
}
#if 0
@@ -350,7 +357,7 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, size_t n_args, size
wiznet5k_obj.spi->Init.CLKPolarity = SPI_POLARITY_LOW; // clock is low when idle
wiznet5k_obj.spi->Init.CLKPhase = SPI_PHASE_1EDGE; // data latched on first edge, which is rising edge for low-idle
wiznet5k_obj.spi->Init.NSS = SPI_NSS_SOFT;
- wiznet5k_obj.spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz
+ wiznet5k_obj.spi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // clock freq = f_PCLK / this_prescale_value; Wiz820i can do up to 80MHz
wiznet5k_obj.spi->Init.FirstBit = SPI_FIRSTBIT_MSB;
wiznet5k_obj.spi->Init.TIMode = SPI_TIMODE_DISABLED;
wiznet5k_obj.spi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
@@ -402,7 +409,12 @@ STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
if (i % 16 == 0) {
printf("\n %04x:", i);
}
- printf(" %02x", WIZCHIP_READ(i));
+ #if MICROPY_PY_WIZNET5K == 5200
+ uint32_t reg = i;
+ #else
+ uint32_t reg = _W5500_IO_BASE_ | i << 8;
+ #endif
+ printf(" %02x", WIZCHIP_READ(reg));
}
for (int sn = 0; sn < 4; ++sn) {
printf("\nWiz SREG[%d]:", sn);
@@ -410,7 +422,12 @@ STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
if (i % 16 == 0) {
printf("\n %04x:", i);
}
- printf(" %02x", WIZCHIP_READ(WIZCHIP_SREG_ADDR(sn, i)));
+ #if MICROPY_PY_WIZNET5K == 5200
+ uint32_t reg = WIZCHIP_SREG_ADDR(sn, i);
+ #else
+ uint32_t reg = _W5500_IO_BASE_ | i << 8 | WIZCHIP_SREG_BLOCK(sn) << 3;
+ #endif
+ printf(" %02x", WIZCHIP_READ(reg));
}
}
printf("\n");
@@ -418,6 +435,12 @@ STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs);
+STATIC mp_obj_t wiznet5k_isconnected(mp_obj_t self_in) {
+ (void)self_in;
+ return mp_obj_new_bool(wizphy_getphylink() == PHY_LINK_ON);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_isconnected_obj, wiznet5k_isconnected);
+
/// \method ifconfig([(ip, subnet, gateway, dns)])
/// Get/set IP address, subnet mask, gateway and DNS.
STATIC mp_obj_t wiznet5k_ifconfig(size_t n_args, const mp_obj_t *args) {
@@ -449,6 +472,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k
STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_regs), MP_ROM_PTR(&wiznet5k_regs_obj) },
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&wiznet5k_ifconfig_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&wiznet5k_isconnected_obj) },
};
STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c
index 176fc8466..81cbdcc19 100644
--- a/ports/stm32/modpyb.c
+++ b/ports/stm32/modpyb.c
@@ -27,7 +27,7 @@
#include <stdint.h>
#include <stdio.h>
-#include "py/obj.h"
+#include "py/runtime.h"
#include "py/gc.h"
#include "py/builtin.h"
#include "py/mphal.h"
@@ -104,6 +104,28 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros);
MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c
+// Get or set the UART object that the REPL is repeated on.
+// This is a legacy function, use of uos.dupterm is preferred.
+STATIC mp_obj_t pyb_repl_uart(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
+ return mp_const_none;
+ } else {
+ return MP_STATE_PORT(pyb_stdio_uart);
+ }
+ } else {
+ if (args[0] == mp_const_none) {
+ MP_STATE_PORT(pyb_stdio_uart) = NULL;
+ } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
+ MP_STATE_PORT(pyb_stdio_uart) = args[0];
+ } else {
+ mp_raise_ValueError("need a UART object");
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart);
+
STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyb) },
@@ -126,7 +148,7 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&machine_sleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_standby), MP_ROM_PTR(&machine_deepsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_main), MP_ROM_PTR(&pyb_main_obj) },
- { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&mod_os_dupterm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_repl_uart), MP_ROM_PTR(&pyb_repl_uart_obj) },
{ MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) },
diff --git a/ports/stm32/moduos.c b/ports/stm32/moduos.c
index f661b3b5e..f6e1483d3 100644
--- a/ports/stm32/moduos.c
+++ b/ports/stm32/moduos.c
@@ -33,6 +33,7 @@
#include "lib/timeutils/timeutils.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
+#include "extmod/misc.h"
#include "extmod/vfs.h"
#include "extmod/vfs_fat.h"
#include "genhdr/mpversion.h"
@@ -105,28 +106,6 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
#endif
-// Get or set the UART object that the REPL is repeated on.
-// TODO should accept any object with read/write methods.
-STATIC mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) {
- if (n_args == 0) {
- if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
- return mp_const_none;
- } else {
- return MP_STATE_PORT(pyb_stdio_uart);
- }
- } else {
- if (args[0] == mp_const_none) {
- MP_STATE_PORT(pyb_stdio_uart) = NULL;
- } else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
- MP_STATE_PORT(pyb_stdio_uart) = args[0];
- } else {
- mp_raise_ValueError("need a UART object");
- }
- return mp_const_none;
- }
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj, 0, 1, os_dupterm);
-
STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
@@ -154,7 +133,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
#endif
// these are MicroPython extensions
- { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mod_os_dupterm_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
{ MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
{ MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
{ MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
diff --git a/ports/stm32/modusocket.c b/ports/stm32/modusocket.c
index c5ab3b6d7..71a237b0d 100644
--- a/ports/stm32/modusocket.c
+++ b/ports/stm32/modusocket.c
@@ -390,29 +390,48 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
size_t hlen;
const char *host = mp_obj_str_get_data(host_in, &hlen);
mp_int_t port = mp_obj_get_int(port_in);
+ uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ bool have_ip = false;
+
+ if (hlen > 0) {
+ // check if host is already in IP form
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ netutils_parse_ipv4_addr(host_in, out_ip, NETUTILS_BIG);
+ have_ip = true;
+ nlr_pop();
+ } else {
+ // swallow exception: host was not in IP form so need to do DNS lookup
+ }
+ }
- // find a NIC that can do a name lookup
- for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
- mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
- mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
- if (nic_type->gethostbyname != NULL) {
- uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- int ret = nic_type->gethostbyname(nic, host, hlen, out_ip);
- if (ret != 0) {
- // TODO CPython raises: socket.gaierror: [Errno -2] Name or service not known
- mp_raise_OSError(ret);
+ if (!have_ip) {
+ // find a NIC that can do a name lookup
+ for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
+ mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
+ mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
+ if (nic_type->gethostbyname != NULL) {
+ int ret = nic_type->gethostbyname(nic, host, hlen, out_ip);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+ have_ip = true;
+ break;
}
- mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
- tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
- tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
- tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
- tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
- tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
- return mp_obj_new_list(1, (mp_obj_t*)&tuple);
}
}
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+ if (!have_ip) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+ }
+
+ mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
+ tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
+ tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
+ return mp_obj_new_list(1, (mp_obj_t*)&tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo);
diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h
index 7888b5355..51d442561 100644
--- a/ports/stm32/mpconfigport.h
+++ b/ports/stm32/mpconfigport.h
@@ -126,6 +126,7 @@
#define MICROPY_PY_USELECT (1)
#define MICROPY_PY_UTIMEQ (1)
#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_OS_DUPTERM (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
@@ -326,6 +327,8 @@ static inline mp_uint_t disable_irq(void) {
__WFI(); \
} \
} while (0);
+
+#define MICROPY_THREAD_YIELD() pyb_thread_yield()
#else
#define MICROPY_EVENT_POLL_HOOK \
do { \
@@ -333,8 +336,13 @@ static inline mp_uint_t disable_irq(void) {
mp_handle_pending(); \
__WFI(); \
} while (0);
+
+#define MICROPY_THREAD_YIELD()
#endif
+// We need an implementation of the log2 function which is not a macro
+#define MP_NEED_LOG2 (1)
+
// There is no classical C heap in bare-metal ports, only Python
// garbage-collected heap. For completeness, emulate C heap via
// GC heap. Note that MicroPython core never uses malloc() and friends,
diff --git a/ports/stm32/mpconfigport.mk b/ports/stm32/mpconfigport.mk
index 64145383e..e708de6c1 100644
--- a/ports/stm32/mpconfigport.mk
+++ b/ports/stm32/mpconfigport.mk
@@ -1,6 +1,9 @@
# Enable/disable extra modules
-# wiznet5k module for ethernet support
+# wiznet5k module for ethernet support; valid values are:
+# 0 : no Wiznet support
+# 5200 : support for W5200 module
+# 5500 : support for W5500 module
MICROPY_PY_WIZNET5K ?= 0
# cc3k module for wifi support
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
index ab3dc227a..e9c4f28f7 100644
--- a/ports/stm32/mphalport.c
+++ b/ports/stm32/mphalport.c
@@ -3,6 +3,7 @@
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
+#include "extmod/misc.h"
#include "usb.h"
#include "uart.h"
@@ -38,6 +39,10 @@ int mp_hal_stdin_rx_chr(void) {
} else if (MP_STATE_PORT(pyb_stdio_uart) != NULL && uart_rx_any(MP_STATE_PORT(pyb_stdio_uart))) {
return uart_rx_char(MP_STATE_PORT(pyb_stdio_uart));
}
+ int dupterm_c = mp_uos_dupterm_rx_chr();
+ if (dupterm_c >= 0) {
+ return dupterm_c;
+ }
MICROPY_EVENT_POLL_HOOK
}
}
@@ -56,15 +61,26 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (usb_vcp_is_enabled()) {
usb_vcp_send_strn(str, len);
}
+ mp_uos_dupterm_tx_strn(str, len);
}
+// Efficiently convert "\n" to "\r\n"
void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
- // send stdout to UART and USB CDC VCP
- if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
- uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len);
+ const char *last = str;
+ while (len--) {
+ if (*str == '\n') {
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
+ }
+ mp_hal_stdout_tx_strn("\r\n", 2);
+ ++str;
+ last = str;
+ } else {
+ ++str;
+ }
}
- if (usb_vcp_is_enabled()) {
- usb_vcp_send_strn_cooked(str, len);
+ if (str > last) {
+ mp_hal_stdout_tx_strn(last, str - last);
}
}
diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c
index a8913a055..8f0513e8c 100644
--- a/ports/stm32/uart.c
+++ b/ports/stm32/uart.c
@@ -454,26 +454,11 @@ STATIC size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_
return num_tx;
}
-STATIC void uart_tx_char(pyb_uart_obj_t *uart_obj, int c) {
- uint16_t ch = c;
- int errcode;
- uart_tx_data(uart_obj, &ch, 1, &errcode);
-}
-
void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
int errcode;
uart_tx_data(uart_obj, str, len, &errcode);
}
-void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len) {
- for (const char *top = str + len; str < top; str++) {
- if (*str == '\n') {
- uart_tx_char(uart_obj, '\r');
- }
- uart_tx_char(uart_obj, *str);
- }
-}
-
// this IRQ handler is set up to handle RXNE interrupts only
void uart_irq_handler(mp_uint_t uart_id) {
// get the uart object
diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h
index e96b25b5f..d176520a1 100644
--- a/ports/stm32/uart.h
+++ b/ports/stm32/uart.h
@@ -48,6 +48,5 @@ void uart_irq_handler(mp_uint_t uart_id);
mp_uint_t uart_rx_any(pyb_uart_obj_t *uart_obj);
int uart_rx_char(pyb_uart_obj_t *uart_obj);
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);
#endif // MICROPY_INCLUDED_STMHAL_UART_H
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 906eb1989..5017bb930 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -178,20 +178,6 @@ void usb_vcp_send_strn(const char *str, int len) {
#endif
}
-void usb_vcp_send_strn_cooked(const char *str, int len) {
-#ifdef USE_DEVICE_MODE
- if (usb_device.enabled) {
- for (const char *top = str + len; str < top; str++) {
- if (*str == '\n') {
- usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)"\r\n", 2);
- } else {
- usbd_cdc_tx_always(&usb_device.usbd_cdc_itf, (const uint8_t*)str, 1);
- }
- }
- }
-#endif
-}
-
/******************************************************************************/
// MicroPython bindings for USB
diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h
index f60ea8033..41c461fb2 100644
--- a/ports/stm32/usb.h
+++ b/ports/stm32/usb.h
@@ -63,7 +63,6 @@ void pyb_usb_dev_deinit(void);
bool usb_vcp_is_enabled(void);
int usb_vcp_recv_byte(uint8_t *c); // if a byte is available, return 1 and put the byte in *c, else return 0
void usb_vcp_send_strn(const char* str, int len);
-void usb_vcp_send_strn_cooked(const char *str, int len);
void pyb_usb_host_init(void);
void pyb_usb_host_process(void);
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index 4c49c9321..2e9fba917 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -57,10 +57,14 @@
#define CDC_SEND_BREAK 0x23
uint8_t *usbd_cdc_init(usbd_cdc_itf_t *cdc, usbd_cdc_msc_hid_state_t *usbd) {
+ // Link the parent state
cdc->usbd = usbd;
+
+ // Reset all the CDC state
+ // Note: we don't reset tx_buf_ptr_in in order to allow the output buffer to
+ // be filled (by usbd_cdc_tx_always) before the USB device is connected.
cdc->rx_buf_put = 0;
cdc->rx_buf_get = 0;
- cdc->tx_buf_ptr_in = 0;
cdc->tx_buf_ptr_out = 0;
cdc->tx_buf_ptr_out_shadow = 0;
cdc->tx_buf_ptr_wait_count = 0;
diff --git a/ports/stm32/usbd_cdc_interface.h b/ports/stm32/usbd_cdc_interface.h
index 6dcab7d47..98b8fc077 100644
--- a/ports/stm32/usbd_cdc_interface.h
+++ b/ports/stm32/usbd_cdc_interface.h
@@ -43,8 +43,8 @@ typedef struct _usbd_cdc_itf_t {
uint16_t rx_buf_get; // circular buffer index
uint8_t tx_buf[USBD_CDC_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
- uint16_t tx_buf_ptr_in; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available
- volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained
+ uint16_t tx_buf_ptr_in; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when new data is available
+ volatile uint16_t tx_buf_ptr_out; // increment this pointer modulo USBD_CDC_TX_DATA_SIZE when data is drained
uint16_t tx_buf_ptr_out_shadow; // shadow of above
uint8_t tx_buf_ptr_wait_count; // used to implement a timeout waiting for low-level USB driver
uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
diff --git a/ports/teensy/teensy_hal.c b/ports/teensy/teensy_hal.c
index 84d68cff8..7ce82f1d2 100644
--- a/ports/teensy/teensy_hal.c
+++ b/ports/teensy/teensy_hal.c
@@ -49,6 +49,7 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
// send stdout to UART and USB CDC VCP
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
+ void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
uart_tx_strn_cooked(MP_STATE_PORT(pyb_stdio_uart), str, len);
}
if (usb_vcp_is_enabled()) {
diff --git a/ports/teensy/uart.c b/ports/teensy/uart.c
index 3d5111217..a8cfd63ea 100644
--- a/ports/teensy/uart.c
+++ b/ports/teensy/uart.c
@@ -426,11 +426,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_send_obj, 1, pyb_uart_send);
///
/// Return value: if `recv` is an integer then a new buffer of the bytes received,
/// otherwise the same buffer that was passed in to `recv`.
+#if 0
STATIC const mp_arg_t pyb_uart_recv_args[] = {
{ MP_QSTR_recv, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
};
#define PYB_UART_RECV_NUM_ARGS MP_ARRAY_SIZE(pyb_uart_recv_args)
+#endif
STATIC mp_obj_t pyb_uart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
// TODO assumes transmission size is 8-bits wide
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index dbe3e592e..5bdcf4e1a 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -97,7 +97,7 @@ SRC_MOD += modtermios.c
endif
ifeq ($(MICROPY_PY_SOCKET),1)
CFLAGS_MOD += -DMICROPY_PY_SOCKET=1
-SRC_MOD += modsocket.c
+SRC_MOD += modusocket.c
endif
ifeq ($(MICROPY_PY_THREAD),1)
CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c
index 15b6d9cd7..f29c095cf 100644
--- a/ports/unix/modjni.c
+++ b/ports/unix/modjni.c
@@ -266,7 +266,7 @@ STATIC mp_obj_t jobject_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value)
return mp_const_none;
}
}
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
if (!JJ(IsInstanceOf, self->obj, List_class)) {
diff --git a/ports/unix/modsocket.c b/ports/unix/modusocket.c
index 7e82554c7..cfb6a9f5e 100644
--- a/ports/unix/modsocket.c
+++ b/ports/unix/modusocket.c
@@ -60,8 +60,6 @@
should be add to separate modules (C or Python level).
*/
-#define MICROPY_SOCKET_EXTRA (0)
-
// This type must "inherit" from mp_obj_fdfile_t, i.e. matching subset of
// fields should have the same layout.
typedef struct _mp_obj_socket_t {
@@ -382,26 +380,6 @@ const mp_obj_type_t mp_type_socket = {
.locals_dict = (mp_obj_dict_t*)&usocket_locals_dict,
};
-#if MICROPY_SOCKET_EXTRA
-STATIC mp_obj_t mod_socket_htons(mp_obj_t arg) {
- return MP_OBJ_NEW_SMALL_INT(htons(MP_OBJ_SMALL_INT_VALUE(arg)));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_htons_obj, mod_socket_htons);
-
-
-STATIC mp_obj_t mod_socket_gethostbyname(mp_obj_t arg) {
- const char *s = mp_obj_str_get_str(arg);
- struct hostent *h = gethostbyname(s);
- if (h == NULL) {
- // CPython: socket.herror
- mp_raise_OSError(h_errno);
- }
- assert(h->h_length == 4);
- return mp_obj_new_int(*(int*)*h->h_addr_list);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_gethostbyname_obj, mod_socket_gethostbyname);
-#endif // MICROPY_SOCKET_EXTRA
-
#define BINADDR_MAX_LEN sizeof(struct in6_addr)
STATIC mp_obj_t mod_socket_inet_pton(mp_obj_t family_in, mp_obj_t addr_in) {
int family = mp_obj_get_int(family_in);
@@ -549,10 +527,6 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_inet_pton), MP_ROM_PTR(&mod_socket_inet_pton_obj) },
{ MP_ROM_QSTR(MP_QSTR_inet_ntop), MP_ROM_PTR(&mod_socket_inet_ntop_obj) },
{ MP_ROM_QSTR(MP_QSTR_sockaddr), MP_ROM_PTR(&mod_socket_sockaddr_obj) },
-#if MICROPY_SOCKET_EXTRA
- { MP_ROM_QSTR(MP_QSTR_htons), MP_ROM_PTR(&mod_socket_htons_obj) },
- { MP_ROM_QSTR(MP_QSTR_gethostbyname), MP_ROM_PTR(&mod_socket_gethostbyname_obj) },
-#endif
#define C(name) { MP_ROM_QSTR(MP_QSTR_ ## name), MP_ROM_INT(name) }
C(AF_UNIX),
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index 50b979279..db382e0a7 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -85,6 +85,7 @@
#define MICROPY_PY_BUILTINS_POW3 (1)
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
+#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
#define MICROPY_PY_SYS_EXIT (1)
diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c
index 2b273d834..f27c62fd1 100644
--- a/ports/unix/unix_mphal.c
+++ b/ports/unix/unix_mphal.c
@@ -108,11 +108,11 @@ void mp_hal_stdio_mode_orig(void) {
#endif
#if MICROPY_PY_OS_DUPTERM
-static int call_dupterm_read(void) {
+static int call_dupterm_read(size_t idx) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t read_m[3];
- mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_read, read_m);
+ mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_read, read_m);
read_m[2] = MP_OBJ_NEW_SMALL_INT(1);
mp_obj_t res = mp_call_method_n_kw(1, 0, read_m);
if (res == mp_const_none) {
@@ -122,18 +122,18 @@ static int call_dupterm_read(void) {
mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len == 0) {
mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n");
- MP_STATE_PORT(term_obj) = NULL;
+ MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
return -1;
}
nlr_pop();
return *(byte*)bufinfo.buf;
} else {
// Temporarily disable dupterm to avoid infinite recursion
- mp_obj_t save_term = MP_STATE_PORT(term_obj);
- MP_STATE_PORT(term_obj) = NULL;
+ mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]);
+ MP_STATE_VM(dupterm_objs[idx]) = NULL;
mp_printf(&mp_plat_print, "dupterm: ");
mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
- MP_STATE_PORT(term_obj) = save_term;
+ MP_STATE_VM(dupterm_objs[idx]) = save_term;
}
return -1;
@@ -143,10 +143,11 @@ static int call_dupterm_read(void) {
int mp_hal_stdin_rx_chr(void) {
unsigned char c;
#if MICROPY_PY_OS_DUPTERM
- if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) {
+ // TODO only support dupterm one slot at the moment
+ if (MP_STATE_VM(dupterm_objs[0]) != MP_OBJ_NULL) {
int c;
do {
- c = call_dupterm_read();
+ c = call_dupterm_read(0);
} while (c == -2);
if (c == -1) {
goto main_term;
diff --git a/ports/zephyr/main.c b/ports/zephyr/main.c
index 7255d981f..7eb9da3e1 100644
--- a/ports/zephyr/main.c
+++ b/ports/zephyr/main.c
@@ -60,7 +60,9 @@ static char *stack_top;
static char heap[MICROPY_HEAP_SIZE];
void init_zephyr(void) {
- // TODO: Make addresses configurable
+ // We now rely on CONFIG_NET_APP_SETTINGS to set up bootstrap
+ // network addresses.
+#if 0
#ifdef CONFIG_NETWORKING
if (net_if_get_default() == NULL) {
// If there's no default networking interface,
@@ -81,6 +83,7 @@ void init_zephyr(void) {
static struct in6_addr in6addr_my = {{{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}};
net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, NET_ADDR_MANUAL, 0);
#endif
+#endif
}
int real_main(void) {
diff --git a/ports/zephyr/prj_base.conf b/ports/zephyr/prj_base.conf
index c3ba2812f..fbcedf260 100644
--- a/ports/zephyr/prj_base.conf
+++ b/ports/zephyr/prj_base.conf
@@ -4,6 +4,12 @@ CONFIG_REBOOT=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_CONSOLE_HANDLER=y
CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y
+
+CONFIG_CONSOLE_PULL=y
+CONFIG_CONSOLE_GETCHAR=y
+CONFIG_CONSOLE_GETCHAR_BUFSIZE=128
+CONFIG_CONSOLE_PUTCHAR_BUFSIZE=128
+
CONFIG_NEWLIB_LIBC=y
CONFIG_FLOAT=y
CONFIG_MAIN_STACK_SIZE=4096
@@ -18,6 +24,14 @@ CONFIG_NET_SOCKETS=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_NET_NBUF_RX_COUNT=5
+CONFIG_NET_APP_SETTINGS=y
+CONFIG_NET_APP_INIT_TIMEOUT=3
+CONFIG_NET_APP_NEED_IPV6=y
+CONFIG_NET_APP_NEED_IPV4=y
+CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1"
+CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
+CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2"
+
# DNS
CONFIG_DNS_RESOLVER=y
CONFIG_DNS_RESOLVER_ADDITIONAL_QUERIES=2
diff --git a/ports/zephyr/prj_qemu_cortex_m3.conf b/ports/zephyr/prj_qemu_cortex_m3.conf
index 09614c362..1ade981e2 100644
--- a/ports/zephyr/prj_qemu_cortex_m3.conf
+++ b/ports/zephyr/prj_qemu_cortex_m3.conf
@@ -1,3 +1,7 @@
+# Interrupt-driven UART console has emulation artifacts under QEMU,
+# disable it
+CONFIG_CONSOLE_PULL=n
+
# Networking drivers
# SLIP driver for QEMU
CONFIG_NET_SLIP_TAP=y
diff --git a/ports/zephyr/prj_qemu_x86.conf b/ports/zephyr/prj_qemu_x86.conf
index ef60cfec9..9bc81259a 100644
--- a/ports/zephyr/prj_qemu_x86.conf
+++ b/ports/zephyr/prj_qemu_x86.conf
@@ -1,3 +1,7 @@
+# Interrupt-driven UART console has emulation artifacts under QEMU,
+# disable it
+CONFIG_CONSOLE_PULL=n
+
# Networking drivers
# SLIP driver for QEMU
CONFIG_NET_SLIP_TAP=y
diff --git a/ports/zephyr/src/zephyr_start.c b/ports/zephyr/src/zephyr_start.c
index 9e8a90beb..452e304ca 100644
--- a/ports/zephyr/src/zephyr_start.c
+++ b/ports/zephyr/src/zephyr_start.c
@@ -24,11 +24,16 @@
* THE SOFTWARE.
*/
#include <zephyr.h>
+#include <console.h>
#include "zephyr_getchar.h"
int real_main(void);
void main(void) {
+#ifdef CONFIG_CONSOLE_PULL
+ console_init();
+#else
zephyr_getchar_init();
+#endif
real_main();
}
diff --git a/ports/zephyr/uart_core.c b/ports/zephyr/uart_core.c
index 1e85053cd..e41fb9acc 100644
--- a/ports/zephyr/uart_core.c
+++ b/ports/zephyr/uart_core.c
@@ -28,6 +28,7 @@
#include "src/zephyr_getchar.h"
// Zephyr headers
#include <uart.h>
+#include <console.h>
/*
* Core UART functions to implement for a port
@@ -35,11 +36,23 @@
// Receive single character
int mp_hal_stdin_rx_chr(void) {
+#ifdef CONFIG_CONSOLE_PULL
+ return console_getchar();
+#else
return zephyr_getchar();
+#endif
}
// Send string of given length
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
+#ifdef CONFIG_CONSOLE_PULL
+ while (len--) {
+ char c = *str++;
+ while (console_putchar(c) == -1) {
+ k_sleep(1);
+ }
+ }
+#else
static struct device *uart_console_dev;
if (uart_console_dev == NULL) {
uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
@@ -48,4 +61,5 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
while (len--) {
uart_poll_out(uart_console_dev, *str++);
}
+#endif
}
diff --git a/py/argcheck.c b/py/argcheck.c
index 46be126ac..2a606d613 100644
--- a/py/argcheck.c
+++ b/py/argcheck.c
@@ -136,11 +136,9 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args,
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);
}
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || defined(_MSC_VER)
NORETURN void mp_arg_error_terse_mismatch(void) {
mp_raise_TypeError("argument num/types mismatch");
}
-#endif
#if MICROPY_CPYTHON_COMPAT
NORETURN void mp_arg_error_unimpl_kw(void) {
diff --git a/py/bc.c b/py/bc.c
index 1f6819295..381daa24d 100644
--- a/py/bc.c
+++ b/py/bc.c
@@ -322,7 +322,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(O, O, U, U), // 0x38-0x3b
OC4(U, O, B, O), // 0x3c-0x3f
OC4(O, B, B, O), // 0x40-0x43
- OC4(B, B, O, U), // 0x44-0x47
+ OC4(B, B, O, B), // 0x44-0x47
OC4(U, U, U, U), // 0x48-0x4b
OC4(U, U, U, U), // 0x4c-0x4f
OC4(V, V, U, V), // 0x50-0x53
@@ -362,7 +362,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(B, B, B, B), // 0xcc-0xcf
OC4(B, B, B, B), // 0xd0-0xd3
- OC4(B, B, B, B), // 0xd4-0xd7
+ OC4(U, U, U, B), // 0xd4-0xd7
OC4(B, B, B, B), // 0xd8-0xdb
OC4(B, B, B, B), // 0xdc-0xdf
@@ -373,7 +373,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(B, B, B, B), // 0xf0-0xf3
OC4(B, B, B, B), // 0xf4-0xf7
- OC4(B, B, B, U), // 0xf8-0xfb
+ OC4(U, U, U, U), // 0xf8-0xfb
OC4(U, U, U, U), // 0xfc-0xff
};
#undef OC4
diff --git a/py/bc0.h b/py/bc0.h
index 38e23c0fd..70acfb0ca 100644
--- a/py/bc0.h
+++ b/py/bc0.h
@@ -113,7 +113,7 @@
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
-#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(<MP_UNARY_OP_NON_BYTECODE)
-#define MP_BC_BINARY_OP_MULTI (0xd7) // + op(36)
+#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(<MP_UNARY_OP_NUM_BYTECODE)
+#define MP_BC_BINARY_OP_MULTI (0xd7) // + op(<MP_BINARY_OP_NUM_BYTECODE)
#endif // MICROPY_INCLUDED_PY_BC0_H
diff --git a/py/emitnative.c b/py/emitnative.c
index b2c9a7366..8e97dda11 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -123,6 +123,8 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
[MP_F_NEW_CELL] = 1,
[MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
[MP_F_SETUP_CODE_STATE] = 5,
+ [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,
+ [MP_F_SMALL_INT_MODULO] = 2,
};
#include "py/asmx86.h"
@@ -1823,18 +1825,20 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
vtype_kind_t vtype_lhs = peek_vtype(emit, 1);
vtype_kind_t vtype_rhs = peek_vtype(emit, 0);
if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) {
+ // for integers, inplace and normal ops are equivalent, so use just normal ops
+ if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) {
+ op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;
+ }
+
#if N_X64 || N_X86
// special cases for x86 and shifting
- if (op == MP_BINARY_OP_LSHIFT
- || op == MP_BINARY_OP_INPLACE_LSHIFT
- || op == MP_BINARY_OP_RSHIFT
- || op == MP_BINARY_OP_INPLACE_RSHIFT) {
+ if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {
#if N_X64
emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET);
#else
emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET);
#endif
- if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
+ if (op == MP_BINARY_OP_LSHIFT) {
ASM_LSL_REG(emit->as, REG_RET);
} else {
ASM_ASR_REG(emit->as, REG_RET);
@@ -1843,35 +1847,48 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
return;
}
#endif
+
+ // special cases for floor-divide and module because we dispatch to helper functions
+ if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) {
+ emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
+ if (op == MP_BINARY_OP_FLOOR_DIVIDE) {
+ emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE);
+ } else {
+ emit_call(emit, MP_F_SMALL_INT_MODULO);
+ }
+ emit_post_push_reg(emit, VTYPE_INT, REG_RET);
+ return;
+ }
+
int reg_rhs = REG_ARG_3;
emit_pre_pop_reg_flexible(emit, &vtype_rhs, &reg_rhs, REG_RET, REG_ARG_2);
emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);
if (0) {
// dummy
#if !(N_X64 || N_X86)
- } else if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
+ } else if (op == MP_BINARY_OP_LSHIFT) {
ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_RSHIFT || op == MP_BINARY_OP_INPLACE_RSHIFT) {
+ } else if (op == MP_BINARY_OP_RSHIFT) {
ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
#endif
- } else if (op == MP_BINARY_OP_OR || op == MP_BINARY_OP_INPLACE_OR) {
+ } else if (op == MP_BINARY_OP_OR) {
ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_XOR || op == MP_BINARY_OP_INPLACE_XOR) {
+ } else if (op == MP_BINARY_OP_XOR) {
ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_AND || op == MP_BINARY_OP_INPLACE_AND) {
+ } else if (op == MP_BINARY_OP_AND) {
ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_ADD || op == MP_BINARY_OP_INPLACE_ADD) {
+ } else if (op == MP_BINARY_OP_ADD) {
ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_SUBTRACT || op == MP_BINARY_OP_INPLACE_SUBTRACT) {
+ } else if (op == MP_BINARY_OP_SUBTRACT) {
ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_MULTIPLY || op == MP_BINARY_OP_INPLACE_MULTIPLY) {
+ } else if (op == MP_BINARY_OP_MULTIPLY) {
ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
} else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
diff --git a/py/formatfloat.c b/py/formatfloat.c
index 35cd5d51a..4228f99ff 100644
--- a/py/formatfloat.c
+++ b/py/formatfloat.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
+#include <math.h>
#include "py/formatfloat.h"
/***********************************************************************
@@ -68,12 +69,10 @@ union floatbits {
uint32_t u;
};
static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; }
-static inline int fp_isspecial(float x) { union floatbits fb = {x}; return (fb.u & FLT_EXP_MASK) == FLT_EXP_MASK; }
-static inline int fp_isinf(float x) { union floatbits fb = {x}; return (fb.u & FLT_MAN_MASK) == 0; }
+#define fp_isnan(x) isnan(x)
+#define fp_isinf(x) isinf(x)
static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; }
static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; }
-// Assumes both fp_isspecial() and fp_isinf() were applied before
-#define fp_isnan(x) 1
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
@@ -82,9 +81,7 @@ static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u <
#define FPROUND_TO_ONE 0.999999999995
#define FPDECEXP 256
#define FPMIN_BUF_SIZE 7 // +9e+199
-#include <math.h>
#define fp_signbit(x) signbit(x)
-#define fp_isspecial(x) 1
#define fp_isnan(x) isnan(x)
#define fp_isinf(x) isinf(x)
#define fp_iszero(x) (x == 0)
@@ -122,7 +119,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
}
return buf_size >= 2;
}
- if (fp_signbit(f)) {
+ if (fp_signbit(f) && !fp_isnan(f)) {
*s++ = '-';
f = -f;
} else {
@@ -135,7 +132,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
// It is buf_size minus room for the sign and null byte.
int buf_remaining = buf_size - 1 - (s - buf);
- if (fp_isspecial(f)) {
+ {
char uc = fmt & 0x20;
if (fp_isinf(f)) {
*s++ = 'I' ^ uc;
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 7249769f4..38fde1a9c 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -108,7 +108,15 @@ def parse_input_headers(infiles):
continue
# add the qstr to the list, with order number to retain original order in file
- qstrs[ident] = (len(qstrs), ident, qstr)
+ order = len(qstrs)
+ # but put special method names like __add__ at the top of list, so
+ # that their id's fit into a byte
+ if ident == "":
+ # Sort empty qstr above all still
+ order = -200000
+ elif ident.startswith("__"):
+ order -= 100000
+ qstrs[ident] = (order, ident, qstr)
if not qcfgs:
sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n")
diff --git a/py/mkenv.mk b/py/mkenv.mk
index 507fa6eab..5a118854a 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -68,13 +68,7 @@ LD += -m32
endif
MAKE_FROZEN = $(TOP)/tools/make-frozen.py
-# allow mpy-cross (for WSL) and mpy-cross.exe (for cygwin) to coexist
-ifeq ($(OS),Windows_NT)
-MPY_CROSS = $(TOP)/mpy-cross/mpy-cross.exe
-PROG_EXT = .exe
-else
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
-endif
MPY_TOOL = $(TOP)/tools/mpy-tool.py
all:
diff --git a/py/mkrules.mk b/py/mkrules.mk
index e26b94939..1d6f11fc9 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -144,13 +144,13 @@ $(PROG): $(OBJ)
# we may want to compile using Thumb, but link with non-Thumb libc.
$(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS)
ifndef DEBUG
- $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)$(PROG_EXT)
+ $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
endif
- $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)$(PROG_EXT)
+ $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)
clean: clean-prog
clean-prog:
- $(RM) -f $(PROG)$(PROG_EXT)
+ $(RM) -f $(PROG)
$(RM) -f $(PROG).map
.PHONY: clean-prog
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index 991feda8c..728309292 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -348,31 +348,16 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
if (MP_OBJ_IS_STR(o_in)) {
len = unichar_charlen(str, len);
if (len == 1) {
- if (!UTF8_IS_NONASCII(*str)) {
- goto return_first_byte;
- }
- mp_int_t ord = *str++ & 0x7F;
- for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
- ord &= ~mask;
- }
- while (UTF8_IS_CONT(*str)) {
- ord = (ord << 6) | (*str++ & 0x3F);
- }
- return mp_obj_new_int(ord);
+ return mp_obj_new_int(utf8_get_char((const byte*)str));
}
- } else {
- // a bytes object
+ } else
+ #endif
+ {
+ // a bytes object, or a str without unicode support (don't sign extend the char)
if (len == 1) {
- return_first_byte:
return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]);
}
}
- #else
- if (len == 1) {
- // don't sign extend when converting to ord
- return mp_obj_new_int(((const byte*)str)[0]);
- }
- #endif
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_TypeError("ord expects a character");
diff --git a/py/modmath.c b/py/modmath.c
index 909780596..56ceb14bd 100644
--- a/py/modmath.c
+++ b/py/modmath.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2017 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
@@ -40,14 +40,31 @@ STATIC NORETURN void math_error(void) {
mp_raise_ValueError("math domain error");
}
+STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) {
+ mp_float_t x = mp_obj_get_float(x_obj);
+ mp_float_t ans = f(x);
+ if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) {
+ math_error();
+ }
+ return mp_obj_new_float(ans);
+}
+
+STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(mp_float_t, mp_float_t)) {
+ mp_float_t x = mp_obj_get_float(x_obj);
+ mp_float_t y = mp_obj_get_float(y_obj);
+ mp_float_t ans = f(x, y);
+ if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) {
+ math_error();
+ }
+ return mp_obj_new_float(ans);
+}
+
#define MATH_FUN_1(py_name, c_name) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \
+ return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
+ } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#define MATH_FUN_2(py_name, c_name) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_float(y_obj))); } \
- STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-
#define MATH_FUN_1_TO_BOOL(py_name, c_name) \
STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
@@ -56,23 +73,29 @@ STATIC NORETURN void math_error(void) {
STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#define MATH_FUN_1_ERRCOND(py_name, c_name, error_condition) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \
- mp_float_t x = mp_obj_get_float(x_obj); \
- if (error_condition) { \
- math_error(); \
- } \
- return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(x)); \
+#define MATH_FUN_2(py_name, c_name) \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+ return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \
} \
- STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#ifdef MP_NEED_LOG2
+#define MATH_FUN_2_FLT_INT(py_name, c_name) \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+ return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \
+ } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+
+#if MP_NEED_LOG2
+#undef log2
+#undef log2f
// 1.442695040888963407354163704 is 1/_M_LN2
-#define log2(x) (log(x) * 1.442695040888963407354163704)
+mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
+ return MICROPY_FLOAT_C_FUN(log)(x) * MICROPY_FLOAT_CONST(1.442695040888963407354163704);
+}
#endif
// sqrt(x): returns the square root of x
-MATH_FUN_1_ERRCOND(sqrt, sqrt, (x < (mp_float_t)0.0))
+MATH_FUN_1(sqrt, sqrt)
// pow(x, y): returns x to the power of y
MATH_FUN_2(pow, pow)
// exp(x)
@@ -81,9 +104,9 @@ MATH_FUN_1(exp, exp)
// expm1(x)
MATH_FUN_1(expm1, expm1)
// log2(x)
-MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0))
+MATH_FUN_1(log2, log2)
// log10(x)
-MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0))
+MATH_FUN_1(log10, log10)
// cosh(x)
MATH_FUN_1(cosh, cosh)
// sinh(x)
@@ -114,9 +137,15 @@ MATH_FUN_2(atan2, atan2)
// ceil(x)
MATH_FUN_1_TO_INT(ceil, ceil)
// copysign(x, y)
-MATH_FUN_2(copysign, copysign)
+STATIC mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) {
+ return MICROPY_FLOAT_C_FUN(copysign)(x, y);
+}
+MATH_FUN_2(copysign, copysign_func)
// fabs(x)
-MATH_FUN_1(fabs, fabs)
+STATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) {
+ return MICROPY_FLOAT_C_FUN(fabs)(x);
+}
+MATH_FUN_1(fabs, fabs_func)
// floor(x)
MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
// fmod(x, y)
@@ -130,7 +159,7 @@ MATH_FUN_1_TO_BOOL(isnan, isnan)
// trunc(x)
MATH_FUN_1_TO_INT(trunc, trunc)
// ldexp(x, exp)
-MATH_FUN_2(ldexp, ldexp)
+MATH_FUN_2_FLT_INT(ldexp, ldexp)
#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
// erf(x): return the error function of x
MATH_FUN_1(erf, erf)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index cec9fb748..252ab7f37 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -775,16 +775,24 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0)
#endif
-// Whether to support complete set of special methods
-// for user classes, or only the most used ones. "Reverse"
-// methods are controlled by MICROPY_PY_REVERSE_SPECIAL_METHODS
-// below.
+// Whether to support complete set of special methods for user
+// classes, or only the most used ones. "Inplace" methods are
+// controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below.
+// "Reverse" methods are controlled by
+// MICROPY_PY_REVERSE_SPECIAL_METHODS below.
#ifndef MICROPY_PY_ALL_SPECIAL_METHODS
#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
#endif
-// Whether to support reverse arithmetic operarions methods
-// (__radd__, etc.)
+// Whether to support all inplace arithmetic operarion methods
+// (__imul__, etc.)
+#ifndef MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
+#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (0)
+#endif
+
+// Whether to support reverse arithmetic operarion methods
+// (__radd__, etc.). Additionally gated by
+// MICROPY_PY_ALL_SPECIAL_METHODS.
#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
#endif
@@ -1111,6 +1119,8 @@ typedef double mp_float_t;
#ifndef MICROPY_PY_USSL
#define MICROPY_PY_USSL (0)
+// Whether to add finaliser code to ussl objects
+#define MICROPY_PY_USSL_FINALISER (0)
#endif
#ifndef MICROPY_PY_WEBSOCKET
diff --git a/py/mpstate.h b/py/mpstate.h
index 1ffb5213c..23133cb7e 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -168,7 +168,7 @@ typedef struct _mp_state_vm_t {
// root pointers for extmod
#ifdef MICROPY_PY_OS_DUPTERM
- mp_obj_t term_obj;
+ mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM];
mp_obj_t dupterm_arr_obj;
#endif
diff --git a/py/nativeglue.c b/py/nativeglue.c
index 61b624ec7..e63c2fcda 100644
--- a/py/nativeglue.c
+++ b/py/nativeglue.c
@@ -29,6 +29,7 @@
#include <assert.h>
#include "py/runtime.h"
+#include "py/smallint.h"
#include "py/emitglue.h"
#include "py/bc.h"
@@ -170,6 +171,8 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_obj_new_cell,
mp_make_closure_from_raw_code,
mp_setup_code_state,
+ mp_small_int_floor_divide,
+ mp_small_int_modulo,
};
/*
diff --git a/py/objarray.c b/py/objarray.c
index b8dca32f7..a1a979b56 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -286,7 +286,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
// Otherwise, can only look for a scalar numeric value in an array
if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
return mp_const_false;
diff --git a/py/objlist.c b/py/objlist.c
index c6e85f2c8..0cbf68c2f 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -158,7 +158,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
mp_int_t len_adj = slice.start - slice.stop;
@@ -198,7 +198,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_get_array(value, &value_len, &value_items);
mp_bound_slice_t slice_out;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start);
//printf("Len adj: %d\n", len_adj);
diff --git a/py/objtype.c b/py/objtype.c
index d57cec703..2fefc65ad 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -335,7 +335,9 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
return MP_OBJ_FROM_PTR(o);
}
-const uint16_t mp_unary_op_method_name[] = {
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
[MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
[MP_UNARY_OP_LEN] = MP_QSTR___len__,
[MP_UNARY_OP_HASH] = MP_QSTR___hash__,
@@ -343,11 +345,11 @@ const uint16_t mp_unary_op_method_name[] = {
[MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__,
[MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__,
[MP_UNARY_OP_INVERT] = MP_QSTR___invert__,
+ [MP_UNARY_OP_ABS] = MP_QSTR___abs__,
#endif
#if MICROPY_PY_SYS_GETSIZEOF
- [MP_UNARY_OP_SIZEOF] = MP_QSTR_getsizeof,
+ [MP_UNARY_OP_SIZEOF] = MP_QSTR___sizeof__,
#endif
- [MP_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this, used to make sure array has full size
};
STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
@@ -409,59 +411,69 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
-const uint16_t mp_binary_op_method_name[] = {
- /*
- MP_BINARY_OP_OR,
- MP_BINARY_OP_XOR,
- MP_BINARY_OP_AND,
- MP_BINARY_OP_LSHIFT,
- MP_BINARY_OP_RSHIFT,
- */
+// Binary-op enum values not listed here will have the default value of 0 in the
+// table, corresponding to MP_QSTR_NULL, and are therefore unsupported (a lookup will
+// fail). They can be added at the expense of code size for the qstr.
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
+ [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
+ [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
+ [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
+ [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
+ [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
+ // MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
+ [MP_BINARY_OP_IN] = MP_QSTR___contains__,
+
+ // All inplace methods are optional, and normal methods will be used
+ // as a fallback.
+ [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,
+ [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
+ #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
+ [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__,
+ [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__,
+ [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__,
+ [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__,
+ [MP_BINARY_OP_INPLACE_POWER] = MP_QSTR___ipow__,
+ [MP_BINARY_OP_INPLACE_OR] = MP_QSTR___ior__,
+ [MP_BINARY_OP_INPLACE_XOR] = MP_QSTR___ixor__,
+ [MP_BINARY_OP_INPLACE_AND] = MP_QSTR___iand__,
+ [MP_BINARY_OP_INPLACE_LSHIFT] = MP_QSTR___ilshift__,
+ [MP_BINARY_OP_INPLACE_RSHIFT] = MP_QSTR___irshift__,
+ #endif
+
[MP_BINARY_OP_ADD] = MP_QSTR___add__,
[MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
#if MICROPY_PY_ALL_SPECIAL_METHODS
[MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__,
[MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__,
[MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__,
+ [MP_BINARY_OP_MODULO] = MP_QSTR___mod__,
+ [MP_BINARY_OP_DIVMOD] = MP_QSTR___divmod__,
+ [MP_BINARY_OP_POWER] = MP_QSTR___pow__,
+ [MP_BINARY_OP_OR] = MP_QSTR___or__,
+ [MP_BINARY_OP_XOR] = MP_QSTR___xor__,
+ [MP_BINARY_OP_AND] = MP_QSTR___and__,
+ [MP_BINARY_OP_LSHIFT] = MP_QSTR___lshift__,
+ [MP_BINARY_OP_RSHIFT] = MP_QSTR___rshift__,
#endif
- /*
- MP_BINARY_OP_MODULO,
- MP_BINARY_OP_POWER,
- MP_BINARY_OP_DIVMOD,
- MP_BINARY_OP_INPLACE_OR,
- MP_BINARY_OP_INPLACE_XOR,
- MP_BINARY_OP_INPLACE_AND,
- MP_BINARY_OP_INPLACE_LSHIFT,
- MP_BINARY_OP_INPLACE_RSHIFT,*/
- #if MICROPY_PY_ALL_SPECIAL_METHODS
- [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,
- [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
- #endif
- /*MP_BINARY_OP_INPLACE_MULTIPLY,
- MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
- MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
- MP_BINARY_OP_INPLACE_MODULO,
- MP_BINARY_OP_INPLACE_POWER,*/
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
[MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__,
[MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__,
+ #if MICROPY_PY_ALL_SPECIAL_METHODS
[MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__,
+ [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__,
+ [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__,
+ [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__,
+ [MP_BINARY_OP_REVERSE_POWER] = MP_QSTR___rpow__,
+ [MP_BINARY_OP_REVERSE_OR] = MP_QSTR___ror__,
+ [MP_BINARY_OP_REVERSE_XOR] = MP_QSTR___rxor__,
+ [MP_BINARY_OP_REVERSE_AND] = MP_QSTR___rand__,
+ [MP_BINARY_OP_REVERSE_LSHIFT] = MP_QSTR___rlshift__,
+ [MP_BINARY_OP_REVERSE_RSHIFT] = MP_QSTR___rrshift__,
+ #endif
#endif
-
- [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
- [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
- [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
- [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
- [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
- /*
- MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
- */
- [MP_BINARY_OP_IN] = MP_QSTR___contains__,
- /*
- MP_BINARY_OP_IS,
- */
- [MP_BINARY_OP_LAST] = 0, // used to make sure array has full size, TODO: FIXME
};
STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
diff --git a/py/persistentcode.c b/py/persistentcode.c
index 42efcbfbb..477ba7501 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -39,7 +39,7 @@
#include "py/smallint.h"
// The current version of .mpy files
-#define MPY_VERSION (2)
+#define MPY_VERSION (3)
// The feature flags byte encodes the compile-time config options that
// affect the generate bytecode.
diff --git a/py/runtime.c b/py/runtime.c
index 4af17dd09..cbec82f17 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -108,6 +108,13 @@ void mp_init(void) {
MP_STATE_VM(mp_module_builtins_override_dict) = NULL;
#endif
+ #ifdef MICROPY_PY_OS_DUPTERM
+ for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) {
+ MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL;
+ }
+ MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL;
+ #endif
+
#ifdef MICROPY_FSUSERMOUNT
// zero out the pointers to the user-mounted devices
memset(MP_STATE_VM(fs_user_mount) + MICROPY_FATFS_NUM_PERSISTENT, 0,
diff --git a/py/runtime.h b/py/runtime.h
index 79f5cbc92..a8b6312ff 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -57,8 +57,8 @@ typedef struct _mp_arg_t {
} mp_arg_t;
// Tables mapping operator enums to qstrs, defined in objtype.c
-extern const uint16_t mp_unary_op_method_name[];
-extern const uint16_t mp_binary_op_method_name[];
+extern const byte mp_unary_op_method_name[];
+extern const byte mp_binary_op_method_name[];
void mp_init(void);
void mp_deinit(void);
diff --git a/py/runtime0.h b/py/runtime0.h
index 8e95b68cf..4709430fb 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -53,41 +53,38 @@ typedef enum {
MP_UNARY_OP_NOT,
// Following ops cannot appear in the bytecode
- MP_UNARY_OP_NON_BYTECODE,
+ MP_UNARY_OP_NUM_BYTECODE,
- MP_UNARY_OP_BOOL = MP_UNARY_OP_NON_BYTECODE, // __bool__
+ MP_UNARY_OP_BOOL = MP_UNARY_OP_NUM_BYTECODE, // __bool__
MP_UNARY_OP_LEN, // __len__
MP_UNARY_OP_HASH, // __hash__; must return a small int
MP_UNARY_OP_ABS, // __abs__
MP_UNARY_OP_SIZEOF, // for sys.getsizeof()
+
+ MP_UNARY_OP_NUM_RUNTIME,
} mp_unary_op_t;
-// Note: the first 35 of these are used in bytecode and changing
+// Note: the first 9+12+12 of these are used in bytecode and changing
// them requires changing the bytecode version.
typedef enum {
- // Relational operations, should return a bool
+ // 9 relational operations, should return a bool
MP_BINARY_OP_LESS,
MP_BINARY_OP_MORE,
MP_BINARY_OP_EQUAL,
MP_BINARY_OP_LESS_EQUAL,
MP_BINARY_OP_MORE_EQUAL,
MP_BINARY_OP_NOT_EQUAL,
-
MP_BINARY_OP_IN,
MP_BINARY_OP_IS,
MP_BINARY_OP_EXCEPTION_MATCH,
- // these are not supported by the runtime and must be synthesised by the emitter
- MP_BINARY_OP_NOT_IN,
- MP_BINARY_OP_IS_NOT,
- // Arithmetic operations
+ // 12 inplace arithmetic operations
MP_BINARY_OP_INPLACE_OR,
MP_BINARY_OP_INPLACE_XOR,
MP_BINARY_OP_INPLACE_AND,
MP_BINARY_OP_INPLACE_LSHIFT,
MP_BINARY_OP_INPLACE_RSHIFT,
MP_BINARY_OP_INPLACE_ADD,
-
MP_BINARY_OP_INPLACE_SUBTRACT,
MP_BINARY_OP_INPLACE_MULTIPLY,
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
@@ -95,13 +92,13 @@ typedef enum {
MP_BINARY_OP_INPLACE_MODULO,
MP_BINARY_OP_INPLACE_POWER,
+ // 12 normal arithmetic operations
MP_BINARY_OP_OR,
MP_BINARY_OP_XOR,
MP_BINARY_OP_AND,
MP_BINARY_OP_LSHIFT,
MP_BINARY_OP_RSHIFT,
MP_BINARY_OP_ADD,
-
MP_BINARY_OP_SUBTRACT,
MP_BINARY_OP_MULTIPLY,
MP_BINARY_OP_FLOOR_DIVIDE,
@@ -111,16 +108,16 @@ typedef enum {
// Operations below this line don't appear in bytecode, they
// just identify special methods.
+ MP_BINARY_OP_NUM_BYTECODE,
// MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_*
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
- MP_BINARY_OP_REVERSE_OR,
+ MP_BINARY_OP_REVERSE_OR = MP_BINARY_OP_NUM_BYTECODE,
MP_BINARY_OP_REVERSE_XOR,
MP_BINARY_OP_REVERSE_AND,
MP_BINARY_OP_REVERSE_LSHIFT,
MP_BINARY_OP_REVERSE_RSHIFT,
MP_BINARY_OP_REVERSE_ADD,
-
MP_BINARY_OP_REVERSE_SUBTRACT,
MP_BINARY_OP_REVERSE_MULTIPLY,
MP_BINARY_OP_REVERSE_FLOOR_DIVIDE,
@@ -129,9 +126,18 @@ typedef enum {
MP_BINARY_OP_REVERSE_POWER,
#endif
- MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime
+ // This is not emitted by the compiler but is supported by the runtime
+ MP_BINARY_OP_DIVMOD
+ #if !MICROPY_PY_REVERSE_SPECIAL_METHODS
+ = MP_BINARY_OP_NUM_BYTECODE
+ #endif
+ ,
+
+ MP_BINARY_OP_NUM_RUNTIME,
- MP_BINARY_OP_LAST,
+ // These 2 are not supported by the runtime and must be synthesised by the emitter
+ MP_BINARY_OP_NOT_IN,
+ MP_BINARY_OP_IS_NOT,
} mp_binary_op_t;
typedef enum {
@@ -181,6 +187,8 @@ typedef enum {
MP_F_NEW_CELL,
MP_F_MAKE_CLOSURE_FROM_RAW_CODE,
MP_F_SETUP_CODE_STATE,
+ MP_F_SMALL_INT_FLOOR_DIVIDE,
+ MP_F_SMALL_INT_MODULO,
MP_F_NUMBER_OF,
} mp_fun_kind_t;
diff --git a/py/showbc.c b/py/showbc.c
index 728d8d983..3deb18cd3 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -539,9 +539,9 @@ const byte *mp_bytecode_print_str(const byte *ip) {
printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
- } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NON_BYTECODE) {
+ } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
- } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) {
+ } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;
printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op]));
} else {
diff --git a/py/vmentrytable.h b/py/vmentrytable.h
index e634e2b41..615f4e2ce 100644
--- a/py/vmentrytable.h
+++ b/py/vmentrytable.h
@@ -109,8 +109,8 @@ static const void *const entry_table[256] = {
[MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI,
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
- [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NON_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI,
- [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 35] = &&entry_MP_BC_BINARY_OP_MULTI,
+ [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI,
+ [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI,
};
#if __clang__
diff --git a/shared-module/multiterminal/__init__.c b/shared-module/multiterminal/__init__.c
index 5f6e298f0..361a6dcc7 100644
--- a/shared-module/multiterminal/__init__.c
+++ b/shared-module/multiterminal/__init__.c
@@ -30,21 +30,21 @@
#include "shared-bindings/multiterminal/__init__.h"
mp_obj_t shared_module_multiterminal_get_secondary_terminal() {
- if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) {
+ if (MP_STATE_VM(dupterm_objs[0]) == MP_OBJ_NULL) {
return mp_const_none;
} else {
- return MP_STATE_PORT(term_obj);
+ return MP_STATE_VM(dupterm_objs[0]);
}
}
void shared_module_multiterminal_set_secondary_terminal(mp_obj_t secondary_terminal) {
- MP_STATE_PORT(term_obj) = secondary_terminal;
+ MP_STATE_VM(dupterm_objs[0]) = secondary_terminal;
if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) {
MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
}
}
void shared_module_multiterminal_clear_secondary_terminal() {
- MP_STATE_PORT(term_obj) = MP_OBJ_NULL;
+ MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_NULL;
MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL;
}
diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp
index 09fbff6fa..1274cda00 100644
--- a/tests/cmdline/cmd_showbc.py.exp
+++ b/tests/cmdline/cmd_showbc.py.exp
@@ -43,9 +43,9 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
bc=\\d\+ line=126
00 LOAD_CONST_NONE
01 LOAD_CONST_FALSE
-02 BINARY_OP 28 __add__
+02 BINARY_OP 26 __add__
03 LOAD_CONST_TRUE
-04 BINARY_OP 28 __add__
+04 BINARY_OP 26 __add__
05 STORE_FAST 0
06 LOAD_CONST_SMALL_INT 0
07 STORE_FAST 0
@@ -84,7 +84,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ STORE_FAST 7
\\d\+ LOAD_FAST 0
\\d\+ LOAD_DEREF 14
-\\d\+ BINARY_OP 28 __add__
+\\d\+ BINARY_OP 26 __add__
\\d\+ STORE_FAST 8
\\d\+ LOAD_FAST 0
\\d\+ UNARY_OP 1
@@ -132,7 +132,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
\\d\+ DUP_TOP_TWO
\\d\+ LOAD_SUBSCR
\\d\+ LOAD_FAST 12
-\\d\+ BINARY_OP 16 __iadd__
+\\d\+ BINARY_OP 14 __iadd__
\\d\+ ROT_THREE
\\d\+ STORE_SUBSCR
\\d\+ LOAD_DEREF 14
@@ -369,7 +369,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+):
42 STORE_FAST_N 19
44 LOAD_FAST 9
45 LOAD_FAST_N 19
-47 BINARY_OP 28 __add__
+47 BINARY_OP 26 __add__
48 POP_TOP
49 LOAD_CONST_NONE
50 RETURN_VALUE
@@ -521,7 +521,7 @@ arg names: *
bc=\\d\+ line=113
00 LOAD_DEREF 0
02 LOAD_CONST_SMALL_INT 1
-03 BINARY_OP 28 __add__
+03 BINARY_OP 26 __add__
04 STORE_FAST 1
05 LOAD_CONST_SMALL_INT 1
06 STORE_DEREF 0
@@ -540,7 +540,7 @@ arg names: * b
bc=\\d\+ line=139
00 LOAD_FAST 1
01 LOAD_DEREF 0
-03 BINARY_OP 28 __add__
+03 BINARY_OP 26 __add__
04 RETURN_VALUE
mem: total=\\d\+, current=\\d\+, peak=\\d\+
stack: \\d\+ out of \\d\+
diff --git a/tests/extmod/ure1.py b/tests/extmod/ure1.py
index 6075990fc..54471ed4f 100644
--- a/tests/extmod/ure1.py
+++ b/tests/extmod/ure1.py
@@ -48,7 +48,12 @@ m = r.match("d")
print(m.group(0))
m = r.match("A")
print(m.group(0))
+print("===")
+# '-' character within character class block
+print(re.match("[-a]+", "-a]d").group(0))
+print(re.match("[a-]+", "-a]d").group(0))
+print("===")
r = re.compile("o+")
m = r.search("foobar")
diff --git a/tests/float/complex1.py b/tests/float/complex1.py
index 854410545..479b4b348 100644
--- a/tests/float/complex1.py
+++ b/tests/float/complex1.py
@@ -59,6 +59,7 @@ ans = (-1.2) ** -3.4; print("%.5g %.5g" % (ans.real, ans.imag))
# check printing of inf/nan
print(float('nan') * 1j)
+print(float('-nan') * 1j)
print(float('inf') * (1 + 1j))
print(float('-inf') * (1 + 1j))
diff --git a/tests/float/float1.py b/tests/float/float1.py
index 137dacc23..c64f965a7 100644
--- a/tests/float/float1.py
+++ b/tests/float/float1.py
@@ -21,6 +21,7 @@ print(float("INF"))
print(float("infinity"))
print(float("INFINITY"))
print(float("nan"))
+print(float("-nan"))
print(float("NaN"))
try:
float("")
diff --git a/tests/float/math_domain.py b/tests/float/math_domain.py
new file mode 100644
index 000000000..0cf10fb2a
--- /dev/null
+++ b/tests/float/math_domain.py
@@ -0,0 +1,51 @@
+# Tests domain errors in math functions
+
+try:
+ import math
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+inf = float('inf')
+nan = float('nan')
+
+# single argument functions
+for name, f, args in (
+ ('fabs', math.fabs, ()),
+ ('ceil', math.ceil, ()),
+ ('floor', math.floor, ()),
+ ('trunc', math.trunc, ()),
+ ('sqrt', math.sqrt, (-1, 0)),
+ ('exp', math.exp, ()),
+ ('sin', math.sin, ()),
+ ('cos', math.cos, ()),
+ ('tan', math.tan, ()),
+ ('asin', math.asin, (-1.1, 1, 1.1)),
+ ('acos', math.acos, (-1.1, 1, 1.1)),
+ ('atan', math.atan, ()),
+ ('ldexp', lambda x: math.ldexp(x, 0), ()),
+ ('radians', math.radians, ()),
+ ('degrees', math.degrees, ()),
+ ):
+ for x in args + (inf, nan):
+ try:
+ ans = f(x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
+ except OverflowError:
+ print(name, 'OverflowError')
+
+# double argument functions
+for name, f, args in (
+ ('pow', math.pow, ((0, 2), (-1, 2), (0, -1), (-1, 2.3))),
+ ('fmod', math.fmod, ((1.2, inf), (1.2, 0), (inf, 1.2))),
+ ('atan2', math.atan2, ((0, 0),)),
+ ('copysign', math.copysign, ()),
+ ):
+ for x in args + ((0, inf), (inf, 0), (inf, inf), (inf, nan), (nan, inf), (nan, nan)):
+ try:
+ ans = f(*x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
diff --git a/tests/float/math_domain_special.py b/tests/float/math_domain_special.py
new file mode 100644
index 000000000..388920350
--- /dev/null
+++ b/tests/float/math_domain_special.py
@@ -0,0 +1,36 @@
+# Tests domain errors in special math functions
+
+try:
+ import math
+ math.erf
+except (ImportError, AttributeError):
+ print("SKIP")
+ raise SystemExit
+
+inf = float('inf')
+nan = float('nan')
+
+# single argument functions
+for name, f, args in (
+ ('expm1', math.exp, ()),
+ ('log2', math.log2, (-1, 0)),
+ ('log10', math.log10, (-1, 0)),
+ ('sinh', math.sinh, ()),
+ ('cosh', math.cosh, ()),
+ ('tanh', math.tanh, ()),
+ ('asinh', math.asinh, ()),
+ ('acosh', math.acosh, (-1, 0.9, 1)),
+ ('atanh', math.atanh, (-1, 1)),
+ ('erf', math.erf, ()),
+ ('erfc', math.erfc, ()),
+ ('gamma', math.gamma, (-2, -1, 0, 1)),
+ ('lgamma', math.lgamma, (-2, -1, 0, 1)),
+ ):
+ for x in args + (inf, nan):
+ try:
+ ans = f(x)
+ print('%.4f' % ans)
+ except ValueError:
+ print(name, 'ValueError')
+ except OverflowError:
+ print(name, 'OverflowError')
diff --git a/tests/micropython/viper_binop_divmod.py b/tests/micropython/viper_binop_divmod.py
new file mode 100644
index 000000000..822424982
--- /dev/null
+++ b/tests/micropython/viper_binop_divmod.py
@@ -0,0 +1,18 @@
+# test floor-division and modulo operators
+
+@micropython.viper
+def div(x:int, y:int) -> int:
+ return x // y
+
+@micropython.viper
+def mod(x:int, y:int) -> int:
+ return x % y
+
+def dm(x, y):
+ print(div(x, y), mod(x, y))
+
+for x in (-6, 6):
+ for y in range(-7, 8):
+ if y == 0:
+ continue
+ dm(x, y)
diff --git a/tests/micropython/viper_binop_divmod.py.exp b/tests/micropython/viper_binop_divmod.py.exp
new file mode 100644
index 000000000..4fc971d46
--- /dev/null
+++ b/tests/micropython/viper_binop_divmod.py.exp
@@ -0,0 +1,28 @@
+0 -6
+1 0
+1 -1
+1 -2
+2 0
+3 0
+6 0
+-6 0
+-3 0
+-2 0
+-2 2
+-2 4
+-1 0
+-1 1
+-1 -1
+-1 0
+-2 -4
+-2 -2
+-2 0
+-3 0
+-6 0
+6 0
+3 0
+2 0
+1 2
+1 1
+1 0
+0 6
diff --git a/tests/net_inet/test_tls_sites.py b/tests/net_inet/test_tls_sites.py
index 67345fd0b..bf8071d08 100644
--- a/tests/net_inet/test_tls_sites.py
+++ b/tests/net_inet/test_tls_sites.py
@@ -6,6 +6,8 @@ try:
import ussl as ssl
except:
import ssl
+ # CPython only supports server_hostname with SSLContext
+ ssl = ssl.SSLContext()
def test_one(site, opts):
@@ -22,7 +24,7 @@ def test_one(site, opts):
else:
s = ssl.wrap_socket(s)
- s.write(b"GET / HTTP/1.0\r\n\r\n")
+ s.write(b"GET / HTTP/1.0\r\nHost: %s\r\n\r\n" % bytes(site, 'latin'))
resp = s.read(4096)
# print(resp)
@@ -34,6 +36,7 @@ SITES = [
"google.com",
"www.google.com",
"api.telegram.org",
+ {"host": "api.pushbullet.com", "sni": True},
# "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com",
{"host": "w9rybpfril.execute-api.ap-southeast-2.amazonaws.com", "sni": True},
]
diff --git a/tests/net_inet/test_tls_sites.py.exp b/tests/net_inet/test_tls_sites.py.exp
index 12732d1fa..2f3c113d2 100644
--- a/tests/net_inet/test_tls_sites.py.exp
+++ b/tests/net_inet/test_tls_sites.py.exp
@@ -1,4 +1,5 @@
google.com ok
www.google.com ok
api.telegram.org ok
+api.pushbullet.com ok
w9rybpfril.execute-api.ap-southeast-2.amazonaws.com ok
diff --git a/tests/run-tests b/tests/run-tests
index 4024d61df..f1035c435 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -506,9 +506,12 @@ def main():
# we need to access feature_check's from the same directory as the
# run-tests script itself.
base_path = os.path.dirname(sys.argv[0]) or "."
- res = run_tests(pyb, tests, args, base_path)
- if pyb:
- pyb.close()
+ try:
+ res = run_tests(pyb, tests, args, base_path)
+ finally:
+ if pyb:
+ pyb.close()
+
if not res:
sys.exit(1)
diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp
index 4c4f66663..1db46ab8f 100644
--- a/tests/unix/extra_coverage.py.exp
+++ b/tests/unix/extra_coverage.py.exp
@@ -39,8 +39,8 @@ ementation
0
0
# runtime utils
-TypeError: unsupported type for : 'str'
-TypeError: unsupported types for : 'str', 'str'
+TypeError: unsupported type for __abs__: 'str'
+TypeError: unsupported types for __divmod__: 'str', 'str'
Warning: test
# format float
?
diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py
index ded962487..ac7b2c1cc 100755
--- a/tools/mpy-tool.py
+++ b/tools/mpy-tool.py
@@ -57,7 +57,7 @@ class FreezeError(Exception):
return 'error while freezing %s: %s' % (self.rawcode.source_file, self.msg)
class Config:
- MPY_VERSION = 2
+ MPY_VERSION = 3
MICROPY_LONGINT_IMPL_NONE = 0
MICROPY_LONGINT_IMPL_LONGLONG = 1
MICROPY_LONGINT_IMPL_MPZ = 2
@@ -105,7 +105,7 @@ def make_opcode_format():
OC4(O, O, U, U), # 0x38-0x3b
OC4(U, O, B, O), # 0x3c-0x3f
OC4(O, B, B, O), # 0x40-0x43
- OC4(B, B, O, U), # 0x44-0x47
+ OC4(B, B, O, B), # 0x44-0x47
OC4(U, U, U, U), # 0x48-0x4b
OC4(U, U, U, U), # 0x4c-0x4f
OC4(V, V, U, V), # 0x50-0x53
@@ -145,7 +145,7 @@ def make_opcode_format():
OC4(B, B, B, B), # 0xcc-0xcf
OC4(B, B, B, B), # 0xd0-0xd3
- OC4(B, B, B, B), # 0xd4-0xd7
+ OC4(U, U, U, B), # 0xd4-0xd7
OC4(B, B, B, B), # 0xd8-0xdb
OC4(B, B, B, B), # 0xdc-0xdf
@@ -156,7 +156,7 @@ def make_opcode_format():
OC4(B, B, B, B), # 0xf0-0xf3
OC4(B, B, B, B), # 0xf4-0xf7
- OC4(B, B, B, U), # 0xf8-0xfb
+ OC4(U, U, U, U), # 0xf8-0xfb
OC4(U, U, U, U), # 0xfc-0xff
))
diff --git a/tools/pyboard.py b/tools/pyboard.py
index d15f520ac..16ee41f70 100755
--- a/tools/pyboard.py
+++ b/tools/pyboard.py
@@ -5,6 +5,7 @@
# The MIT License (MIT)
#
# Copyright (c) 2014-2016 Damien P. George
+# Copyright (c) 2017 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
@@ -28,7 +29,11 @@
pyboard interface
This module provides the Pyboard class, used to communicate with and
-control the pyboard over a serial USB connection.
+control a MicroPython device over a communication channel. Both real
+boards and emulated devices (e.g. running in QEMU) are supported.
+Various communication channels are supported, including a serial
+connection, telnet-style network connection, external process
+connection.
Example usage:
@@ -343,7 +348,7 @@ class Pyboard:
# check if we could exec command
data = self.serial.read(2)
if data != b'OK':
- raise PyboardError('could not exec command (response: %s)' % data)
+ raise PyboardError('could not exec command (response: %r)' % data)
def exec_raw(self, command, timeout=10, data_consumer=None):
self.exec_raw_no_follow(command);