Merge MicroPython 1.13 into CircuitPython

This commit is contained in:
Scott Shawcroft 2021-05-04 11:40:55 -07:00
commit f0bb26d70f
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
484 changed files with 13086 additions and 5242 deletions

View File

@ -71,27 +71,18 @@ jobs:
run: make -C mpy-cross -j2 run: make -C mpy-cross -j2
- name: Build unix port - name: Build unix port
run: | run: |
make -C ports/unix deplibs -j2 make -C ports/unix VARIANT=coverage -j2
make -C ports/unix -j2
make -C ports/unix coverage -j2
- name: Test all - name: Test all
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1
working-directory: tests working-directory: tests
- name: Print failure info
run: |
shopt -s nullglob;
for exp in *.exp;
do testbase=$(basename $exp .exp);
echo -e "\nFAILURE $testbase";
diff -u $testbase.exp $testbase.out;
done
working-directory: tests
if: failure()
- name: Native Tests - name: Native Tests
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 --emit native run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --emit native
working-directory: tests working-directory: tests
- name: mpy Tests - name: mpy Tests
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 --via-mpy -d basics float run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy -d basics float micropython
working-directory: tests
- name: Native mpy Tests
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
working-directory: tests working-directory: tests
- name: Build mpy-cross.static-raspbian - name: Build mpy-cross.static-raspbian
run: make -C mpy-cross -j2 -f Makefile.static-raspbian run: make -C mpy-cross -j2 -f Makefile.static-raspbian

3
.gitignore vendored
View File

@ -37,8 +37,7 @@ build-*/
# Test failure outputs # Test failure outputs
###################### ######################
tests/*.exp tests/results/*
tests/*.out
# Python cache files # Python cache files
###################### ######################

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2013-2019 Damien P. George Copyright (c) 2013-2020 Damien P. George
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -7,7 +7,7 @@
# You can set these variables from the command line. # You can set these variables from the command line.
PYTHON = python3 PYTHON = python3
SPHINXOPTS = SPHINXOPTS = -W --keep-going
SPHINXBUILD = sphinx-build SPHINXBUILD = sphinx-build
PAPER = PAPER =
# path to build the generated docs # path to build the generated docs
@ -223,7 +223,7 @@ pseudoxml:
all-source: all-source:
locale/circuitpython.pot: all-source locale/circuitpython.pot: all-source
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o - | sed -e '/"POT-Creation-Date: /d' > $@ find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' > $@
# Historically, `make translate` updated the .pot file and ran msgmerge. # Historically, `make translate` updated the .pot file and ran msgmerge.
# However, this was a frequent source of merge conflicts. Weblate can perform # However, this was a frequent source of merge conflicts. Weblate can perform
@ -248,7 +248,7 @@ merge-translate:
.PHONY: check-translate .PHONY: check-translate
check-translate: check-translate:
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot.tmp -p locale find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o circuitpython.pot.tmp -p locale
$(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status $(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status
stubs: stubs:

View File

@ -541,10 +541,10 @@ object instead of the pins themselves. This allows the calling code to provide
any object with the appropriate methods such as an I2C expansion board. any object with the appropriate methods such as an I2C expansion board.
Another example is to expect a :py:class:`~digitalio.DigitalInOut` for a pin to Another example is to expect a :py:class:`~digitalio.DigitalInOut` for a pin to
toggle instead of a :py:class:`~microcontroller.Pin` from `board`. Taking in the toggle instead of a :py:class:`~microcontroller.Pin` from :py:mod:`board`.
:py:class:`~microcontroller.Pin` object alone would limit the driver to pins on Taking in the :py:class:`~microcontroller.Pin` object alone would limit the
the actual microcontroller instead of pins provided by another driver such as an driver to pins on the actual microcontroller instead of pins provided by another
IO expander. driver such as an IO expander.
Lots of small modules Lots of small modules
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -36,6 +36,7 @@ Full Table of Contents
:caption: MicroPython specific :caption: MicroPython specific
library/index.rst library/index.rst
reference/glossary.rst
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1

View File

@ -78,7 +78,7 @@ Example::
Functions Functions
--------- ---------
.. function:: open(stream, \*, flags=0, pagesize=0, cachesize=0, minkeypage=0) .. function:: open(stream, *, flags=0, pagesize=0, cachesize=0, minkeypage=0)
Open a database from a random-access ``stream`` (like an open file). All Open a database from a random-access ``stream`` (like an open file). All
other parameters are optional and keyword-only, and allow to tweak advanced other parameters are optional and keyword-only, and allow to tweak advanced
@ -118,7 +118,7 @@ Methods
Flush any data in cache to the underlying stream. Flush any data in cache to the underlying stream.
.. method:: btree.__getitem__(key) .. method:: btree.__getitem__(key)
btree.get(key, default=None) btree.get(key, default=None, /)
btree.__setitem__(key, val) btree.__setitem__(key, val)
btree.__detitem__(key) btree.__detitem__(key)
btree.__contains__(key) btree.__contains__(key)

View File

@ -1,12 +1,13 @@
:mod:`errno` -- system error codes :mod:`uerrno` -- system error codes
=================================== ===================================
.. module:: errno .. module:: uerrno
:synopsis: system error codes :synopsis: system error codes
|see_cpython_module| :mod:`cpython:errno`. |see_cpython_module| :mod:`python:errno`.
This module provides access to symbolic error codes for `OSError` exception. This module provides access to symbolic error codes for `OSError` exception.
A particular inventory of codes depends on :term:`MicroPython port`.
Constants Constants
--------- ---------
@ -14,13 +15,14 @@ Constants
.. data:: EEXIST, EAGAIN, etc. .. data:: EEXIST, EAGAIN, etc.
Error codes, based on ANSI C/POSIX standard. All error codes start with Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". Errors are usually accessible as ``exc.args[0]`` "E". As mentioned above, inventory of the codes depends on
:term:`MicroPython port`. Errors are usually accessible as ``exc.args[0]``
where ``exc`` is an instance of `OSError`. Usage example:: where ``exc`` is an instance of `OSError`. Usage example::
try: try:
os.mkdir("my_dir") uos.mkdir("my_dir")
except OSError as exc: except OSError as exc:
if exc.args[0] == errno.EEXIST: if exc.args[0] == uerrno.EEXIST:
print("Directory already exists") print("Directory already exists")
.. data:: errorcode .. data:: errorcode
@ -28,5 +30,5 @@ Constants
Dictionary mapping numeric error codes to strings with symbolic error Dictionary mapping numeric error codes to strings with symbolic error
code (see above):: code (see above)::
>>> print(errno.errorcode[uerrno.EEXIST]) >>> print(uerrno.errorcode[uerrno.EEXIST])
EEXIST EEXIST

View File

@ -1,4 +1,4 @@
:mod:`framebuf` --- Frame buffer manipulation :mod:`framebuf` --- frame buffer manipulation
============================================= =============================================
.. include:: ../templates/unsupported_in_circuitpython.inc .. include:: ../templates/unsupported_in_circuitpython.inc
@ -30,7 +30,7 @@ For example::
Constructors Constructors
------------ ------------
.. class:: FrameBuffer(buffer, width, height, format, stride=width) .. class:: FrameBuffer(buffer, width, height, format, stride=width, /)
Construct a FrameBuffer object. The parameters are: Construct a FrameBuffer object. The parameters are:
@ -132,7 +132,7 @@ Constants
Monochrome (1-bit) color format Monochrome (1-bit) color format
This defines a mapping where the bits in a byte are horizontally mapped. This defines a mapping where the bits in a byte are horizontally mapped.
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost. Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
Subsequent bytes appear at successive horizontal locations until the Subsequent bytes appear at successive horizontal locations until the
rightmost edge is reached. Further bytes are rendered on the next row, one rightmost edge is reached. Further bytes are rendered on the next row, one
pixel lower. pixel lower.
@ -141,7 +141,7 @@ Constants
Monochrome (1-bit) color format Monochrome (1-bit) color format
This defines a mapping where the bits in a byte are horizontally mapped. This defines a mapping where the bits in a byte are horizontally mapped.
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost. Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
Subsequent bytes appear at successive horizontal locations until the Subsequent bytes appear at successive horizontal locations until the
rightmost edge is reached. Further bytes are rendered on the next row, one rightmost edge is reached. Further bytes are rendered on the next row, one
pixel lower. pixel lower.

View File

@ -37,6 +37,7 @@ with the ``u`` prefix dropped:
json.rst json.rst
re.rst re.rst
sys.rst sys.rst
uasyncio.rst
uctypes.rst uctypes.rst
uselect.rst uselect.rst
uzlib.rst uzlib.rst

View File

@ -73,17 +73,26 @@ Functions
.. function:: heap_lock() .. function:: heap_lock()
.. function:: heap_unlock() .. function:: heap_unlock()
.. function:: heap_locked()
Lock or unlock the heap. When locked no memory allocation can occur and a Lock or unlock the heap. When locked no memory allocation can occur and a
`MemoryError` will be raised if any heap allocation is attempted. `MemoryError` will be raised if any heap allocation is attempted.
`heap_locked()` returns a true value if the heap is currently locked.
These functions can be nested, ie `heap_lock()` can be called multiple times These functions can be nested, ie `heap_lock()` can be called multiple times
in a row and the lock-depth will increase, and then `heap_unlock()` must be in a row and the lock-depth will increase, and then `heap_unlock()` must be
called the same number of times to make the heap available again. called the same number of times to make the heap available again.
Both `heap_unlock()` and `heap_locked()` return the current lock depth
(after unlocking for the former) as a non-negative integer, with 0 meaning
the heap is not locked.
If the REPL becomes active with the heap locked then it will be forcefully If the REPL becomes active with the heap locked then it will be forcefully
unlocked. unlocked.
Note: `heap_locked()` is not enabled on most ports by default,
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
.. function:: kbd_intr(chr) .. function:: kbd_intr(chr)
Set the character that will raise a `KeyboardInterrupt` exception. By Set the character that will raise a `KeyboardInterrupt` exception. By

View File

@ -124,7 +124,7 @@ Functions
string for first position which matches regex (which still may be string for first position which matches regex (which still may be
0 if regex is anchored). 0 if regex is anchored).
.. function:: sub(regex_str, replace, string, count=0, flags=0) .. function:: sub(regex_str, replace, string, count=0, flags=0, /)
Compile *regex_str* and search for it in *string*, replacing all matches Compile *regex_str* and search for it in *string*, replacing all matches
with *replace*, and returning the new string. with *replace*, and returning the new string.
@ -138,11 +138,12 @@ Functions
If *count* is specified and non-zero then substitution will stop after If *count* is specified and non-zero then substitution will stop after
this many substitutions are made. The *flags* argument is ignored. this many substitutions are made. The *flags* argument is ignored.
Note: availability of this function depends on MicroPython port. Note: availability of this function depends on :term:`MicroPython port`.
.. data:: DEBUG .. data:: DEBUG
Flag value, display debug information about compiled expression. Flag value, display debug information about compiled expression.
(Availability depends on :term:`MicroPython port`.)
.. _regex: .. _regex:
@ -155,14 +156,14 @@ Compiled regular expression. Instances of this class are created using
.. method:: regex.match(string) .. method:: regex.match(string)
regex.search(string) regex.search(string)
regex.sub(replace, string, count=0, flags=0) regex.sub(replace, string, count=0, flags=0, /)
Similar to the module-level functions :meth:`match`, :meth:`search` Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`. and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to Using methods is (much) more efficient if the same regex is applied to
multiple strings. multiple strings.
.. method:: regex.split(string, max_split=-1) .. method:: regex.split(string, max_split=-1, /)
Split a *string* using regex. If *max_split* is given, it specifies Split a *string* using regex. If *max_split* is given, it specifies
maximum number of splits to perform. Returns list of strings (there maximum number of splits to perform. Returns list of strings (there
@ -183,7 +184,7 @@ to the replacement function in `sub()`.
Return a tuple containing all the substrings of the groups of the match. Return a tuple containing all the substrings of the groups of the match.
Note: availability of this method depends on MicroPython port. Note: availability of this method depends on :term:`MicroPython port`.
.. method:: match.start([index]) .. method:: match.start([index])
match.end([index]) match.end([index])
@ -192,10 +193,10 @@ to the replacement function in `sub()`.
substring group that was matched. *index* defaults to the entire substring group that was matched. *index* defaults to the entire
group, otherwise it will select a group. group, otherwise it will select a group.
Note: availability of these methods depends on MicroPython port. Note: availability of these methods depends on :term:`MicroPython port`.
.. method:: match.span([index]) .. method:: match.span([index])
Returns the 2-tuple ``(match.start(index), match.end(index))``. Returns the 2-tuple ``(match.start(index), match.end(index))``.
Note: availability of this method depends on MicroPython port. Note: availability of this method depends on :term:`MicroPython port`.

View File

@ -11,7 +11,7 @@
Functions Functions
--------- ---------
.. function:: exit(retval=0) .. function:: exit(retval=0, /)
Terminate current program with a given exit code. Underlyingly, this Terminate current program with a given exit code. Underlyingly, this
function raise as `SystemExit` exception. If an argument is given, its function raise as `SystemExit` exception. If an argument is given, its

303
docs/library/uasyncio.rst Normal file
View File

@ -0,0 +1,303 @@
:mod:`uasyncio` --- asynchronous I/O scheduler
==============================================
.. module:: uasyncio
:synopsis: asynchronous I/O scheduler for writing concurrent code
|see_cpython_module|
`asyncio <https://docs.python.org/3.8/library/asyncio.html>`_
Example::
import uasyncio
async def blink(led, period_ms):
while True:
led.on()
await uasyncio.sleep_ms(5)
led.off()
await uasyncio.sleep_ms(period_ms)
async def main(led1, led2):
uasyncio.create_task(blink(led1, 700))
uasyncio.create_task(blink(led2, 400))
await uasyncio.sleep_ms(10_000)
# Running on a pyboard
from pyb import LED
uasyncio.run(main(LED(1), LED(2)))
# Running on a generic board
from machine import Pin
uasyncio.run(main(Pin(1), Pin(2)))
Core functions
--------------
.. function:: create_task(coro)
Create a new task from the given coroutine and schedule it to run.
Returns the corresponding `Task` object.
.. function:: run(coro)
Create a new task from the given coroutine and run it until it completes.
Returns the value returned by *coro*.
.. function:: sleep(t)
Sleep for *t* seconds (can be a float).
This is a coroutine.
.. function:: sleep_ms(t)
Sleep for *t* milliseconds.
This is a coroutine, and a MicroPython extension.
Additional functions
--------------------
.. function:: wait_for(awaitable, timeout)
Wait for the *awaitable* to complete, but cancel it if it takes longer
that *timeout* seconds. If *awaitable* is not a task then a task will be
created from it.
If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``:
this should be trapped by the caller.
Returns the return value of *awaitable*.
This is a coroutine.
.. function:: wait_for_ms(awaitable, timeout)
Similar to `wait_for` but *timeout* is an integer in milliseconds.
This is a coroutine, and a MicroPython extension.
.. function:: gather(*awaitables, return_exceptions=False)
Run all *awaitables* concurrently. Any *awaitables* that are not tasks are
promoted to tasks.
Returns a list of return values of all *awaitables*.
This is a coroutine.
class Task
----------
.. class:: Task()
This object wraps a coroutine into a running task. Tasks can be waited on
using ``await task``, which will wait for the task to complete and return
the return value of the task.
Tasks should not be created directly, rather use `create_task` to create them.
.. method:: Task.cancel()
Cancel the task by injecting a ``CancelledError`` into it. The task may
or may not ignore this exception.
class Event
-----------
.. class:: Event()
Create a new event which can be used to synchronise tasks. Events start
in the cleared state.
.. method:: Event.is_set()
Returns ``True`` if the event is set, ``False`` otherwise.
.. method:: Event.set()
Set the event. Any tasks waiting on the event will be scheduled to run.
.. method:: Event.clear()
Clear the event.
.. method:: Event.wait()
Wait for the event to be set. If the event is already set then it returns
immediately.
This is a coroutine.
class Lock
----------
.. class:: Lock()
Create a new lock which can be used to coordinate tasks. Locks start in
the unlocked state.
In addition to the methods below, locks can be used in an ``async with`` statement.
.. method:: Lock.locked()
Returns ``True`` if the lock is locked, otherwise ``False``.
.. method:: Lock.acquire()
Wait for the lock to be in the unlocked state and then lock it in an atomic
way. Only one task can acquire the lock at any one time.
This is a coroutine.
.. method:: Lock.release()
Release the lock. If any tasks are waiting on the lock then the next one in the
queue is scheduled to run and the lock remains locked. Otherwise, no tasks are
waiting an the lock becomes unlocked.
TCP stream connections
----------------------
.. function:: open_connection(host, port)
Open a TCP connection to the given *host* and *port*. The *host* address will be
resolved using `socket.getaddrinfo`, which is currently a blocking call.
Returns a pair of streams: a reader and a writer stream.
Will raise a socket-specific ``OSError`` if the host could not be resolved or if
the connection could not be made.
This is a coroutine.
.. function:: start_server(callback, host, port, backlog=5)
Start a TCP server on the given *host* and *port*. The *callback* will be
called with incoming, accepted connections, and be passed 2 arguments: reader
and writer streams for the connection.
Returns a `Server` object.
This is a coroutine.
.. class:: Stream()
This represents a TCP stream connection. To minimise code this class implements
both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to
this class.
.. method:: Stream.get_extra_info(v)
Get extra information about the stream, given by *v*. The valid values for *v* are:
``peername``.
.. method:: Stream.close()
Close the stream.
.. method:: Stream.wait_closed()
Wait for the stream to close.
This is a coroutine.
.. method:: Stream.read(n)
Read up to *n* bytes and return them.
This is a coroutine.
.. method:: Stream.readline()
Read a line and return it.
This is a coroutine.
.. method:: Stream.write(buf)
Accumulated *buf* to the output buffer. The data is only flushed when
`Stream.drain` is called. It is recommended to call `Stream.drain` immediately
after calling this function.
.. method:: Stream.drain()
Drain (write) all buffered output data out to the stream.
This is a coroutine.
.. class:: Server()
This represents the server class returned from `start_server`. It can be used
in an ``async with`` statement to close the server upon exit.
.. method:: Server.close()
Close the server.
.. method:: Server.wait_closed()
Wait for the server to close.
This is a coroutine.
Event Loop
----------
.. function:: get_event_loop()
Return the event loop used to schedule and run tasks. See `Loop`.
.. function:: new_event_loop()
Reset the event loop and return it.
Note: since MicroPython only has a single event loop this function just
resets the loop's state, it does not create a new one.
.. class:: Loop()
This represents the object which schedules and runs tasks. It cannot be
created, use `get_event_loop` instead.
.. method:: Loop.create_task(coro)
Create a task from the given *coro* and return the new `Task` object.
.. method:: Loop.run_forever()
Run the event loop until `stop()` is called.
.. method:: Loop.run_until_complete(awaitable)
Run the given *awaitable* until it completes. If *awaitable* is not a task
then it will be promoted to one.
.. method:: Loop.stop()
Stop the event loop.
.. method:: Loop.close()
Close the event loop.
.. method:: Loop.set_exception_handler(handler)
Set the exception handler to call when a Task raises an exception that is not
caught. The *handler* should accept two arguments: ``(loop, context)``.
.. method:: Loop.get_exception_handler()
Get the current exception handler. Returns the handler, or ``None`` if no
custom handler is set.
.. method:: Loop.default_exception_handler(context)
The default exception handler that is called.
.. method:: Loop.call_exception_handler(context)
Call the current exception handler. The argument *context* is passed through and
is a dictionary containing keys: ``'message'``, ``'exception'``, ``'future'``.

View File

@ -182,7 +182,7 @@ Following are encoding examples for various field types:
Module contents Module contents
--------------- ---------------
.. class:: struct(addr, descriptor, layout_type=NATIVE) .. class:: struct(addr, descriptor, layout_type=NATIVE, /)
Instantiate a "foreign data structure" object based on structure address in Instantiate a "foreign data structure" object based on structure address in
memory, descriptor (encoded as a dictionary), and layout type (see below). memory, descriptor (encoded as a dictionary), and layout type (see below).
@ -202,7 +202,7 @@ Module contents
Layout type for a native structure - with data endianness and alignment Layout type for a native structure - with data endianness and alignment
conforming to the ABI of the system on which MicroPython runs. conforming to the ABI of the system on which MicroPython runs.
.. function:: sizeof(struct, layout_type=NATIVE) .. function:: sizeof(struct, layout_type=NATIVE, /)
Return size of data structure in bytes. The *struct* argument can be Return size of data structure in bytes. The *struct* argument can be
either a structure class or a specific instantiated structure object either a structure class or a specific instantiated structure object

View File

@ -60,7 +60,7 @@ Methods
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError` Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
is raised with error of ENOENT. is raised with error of ENOENT.
.. method:: poll.poll(timeout=-1) .. method:: poll.poll(timeout=-1, /)
Wait for at least one of the registered objects to become ready or have an Wait for at least one of the registered objects to become ready or have an
exceptional condition, with optional timeout in milliseconds (if *timeout* exceptional condition, with optional timeout in milliseconds (if *timeout*
@ -83,7 +83,7 @@ Methods
Tuples returned may contain more than 2 elements as described above. Tuples returned may contain more than 2 elements as described above.
.. method:: poll.ipoll(timeout=-1, flags=0) .. method:: poll.ipoll(timeout=-1, flags=0, /)
Like :meth:`poll.poll`, but instead returns an iterator which yields a Like :meth:`poll.poll`, but instead returns an iterator which yields a
``callee-owned tuples``. This function provides efficient, allocation-free ``callee-owned tuples``. This function provides efficient, allocation-free

View File

@ -16,7 +16,7 @@ is not yet implemented.
Functions Functions
--------- ---------
.. function:: decompress(data, wbits=0, bufsize=0) .. function:: decompress(data, wbits=0, bufsize=0, /)
Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
size used during compression (8-15, the dictionary size is power of 2 of size used during compression (8-15, the dictionary size is power of 2 of
@ -25,7 +25,7 @@ Functions
to be raw DEFLATE stream. *bufsize* parameter is for compatibility with to be raw DEFLATE stream. *bufsize* parameter is for compatibility with
CPython and is ignored. CPython and is ignored.
.. class:: DecompIO(stream, wbits=0) .. class:: DecompIO(stream, wbits=0, /)
Create a ``stream`` wrapper which allows transparent decompression of Create a ``stream`` wrapper which allows transparent decompression of
compressed data in another *stream*. This allows to process compressed compressed data in another *stream*. This allows to process compressed

175
docs/reference/glossary.rst Normal file
View File

@ -0,0 +1,175 @@
Glossary
========
.. glossary::
baremetal
A system without a (full-fledged) operating system, for example an
:term:`MCU`-based system. When running on a baremetal system,
MicroPython effectively functions like a small operating system,
running user programs and providing a command interpreter
(:term:`REPL`).
buffer protocol
Any Python object that can be automatically converted into bytes, such
as ``bytes``, ``bytearray``, ``memoryview`` and ``str`` objects, which
all implement the "buffer protocol".
board
Typically this refers to a printed circuit board (PCB) containing a
:term:`microcontroller <MCU>` and supporting components.
MicroPython firmware is typically provided per-board, as the firmware
contains both MCU-specific functionality but also board-level
functionality such as drivers or pin names.
bytecode
A compact representation of a Python program that generated by
compiling the Python source code. This is what the VM actually
executes. Bytecode is typically generated automatically at runtime and
is invisible to the user. Note that while :term:`CPython` and
MicroPython both use bytecode, the format is different. You can also
pre-compile source code offline using the :term:`cross-compiler`.
callee-owned tuple
This is a MicroPython-specific construct where, for efficiency
reasons, some built-in functions or methods may re-use the same
underlying tuple object to return data. This avoids having to allocate
a new tuple for every call, and reduces heap fragmentation. Programs
should not hold references to callee-owned tuples and instead only
extract data from them (or make a copy).
CircuitPython
A variant of MicroPython developed by `Adafruit Industries
<https://circuitpython.org>`_.
CPython
CPython is the reference implementation of the Python programming
language, and the most well-known one. It is, however, one of many
implementations (including Jython, IronPython, PyPy, and MicroPython).
While MicroPython's implementation differs substantially from CPython,
it aims to maintain as much compatibility as possible.
cross-compiler
Also known as ``mpy-cross``. This tool runs on your PC and converts a
:term:`.py file` containing MicroPython code into a :term:`.mpy file`
containing MicroPython bytecode. This means it loads faster (the board
doesn't have to compile the code), and uses less space on flash (the
bytecode is more space efficient).
driver
A MicroPython library that implements support for a particular
component, such as a sensor or display.
FFI
Acronym for Foreign Function Interface. A mechanism used by the
:term:`MicroPython Unix port` to access operating system functionality.
This is not available on :term:`baremetal` ports.
filesystem
Most MicroPython ports and boards provide a filesystem stored in flash
that is available to user code via the standard Python file APIs such
as ``open()``. Some boards also make this internal filesystem
accessible to the host via USB mass-storage.
frozen module
A Python module that has been cross compiled and bundled into the
firmware image. This reduces RAM requirements as the code is executed
directly from flash.
Garbage Collector
A background process that runs in Python (and MicroPython) to reclaim
unused memory in the :term:`heap`.
GPIO
General-purpose input/output. The simplest means to control electrical
signals (commonly referred to as "pins") on a microcontroller. GPIO
typically allows pins to be either input or output, and to set or get
their digital value (logical "0" or "1"). MicroPython abstracts GPIO
access using the :class:`machine.Pin` and :class:`machine.Signal`
classes.
GPIO port
A group of :term:`GPIO` pins, usually based on hardware properties of
these pins (e.g. controllable by the same register).
heap
A region of RAM where MicroPython stores dynamic data. It is managed
automatically by the :term:`Garbage Collector`. Different MCUs and
boards have vastly different amounts of RAM available for the heap, so
this will affect how complex your program can be.
interned string
An optimisation used by MicroPython to improve the efficiency of
working with strings. An interned string is referenced by its (unique)
identity rather than its address and can therefore be quickly compared
just by its identifier. It also means that identical strings can be
de-duplicated in memory. String interning is almost always invisible to
the user.
MCU
Microcontroller. Microcontrollers usually have much less resources
than a desktop, laptop, or phone, but are smaller, cheaper and
require much less power. MicroPython is designed to be small and
optimized enough to run on an average modern microcontroller.
MicroPython port
MicroPython supports different :term:`boards <board>`, RTOSes, and
OSes, and can be relatively easily adapted to new systems. MicroPython
with support for a particular system is called a "port" to that
system. Different ports may have widely different functionality. This
documentation is intended to be a reference of the generic APIs
available across different ports ("MicroPython core"). Note that some
ports may still omit some APIs described here (e.g. due to resource
constraints). Any such differences, and port-specific extensions
beyond the MicroPython core functionality, would be described in the
separate port-specific documentation.
MicroPython Unix port
The unix port is one of the major :term:`MicroPython ports
<MicroPython port>`. It is intended to run on POSIX-compatible
operating systems, like Linux, MacOS, FreeBSD, Solaris, etc. It also
serves as the basis of Windows port. The Unix port is very useful for
quick development and testing of the MicroPython language and
machine-independent features. It can also function in a similar way to
:term:`CPython`'s ``python`` executable.
.mpy file
The output of the :term:`cross-compiler`. A compiled form of a
:term:`.py file` that contains MicroPython bytecode instead of Python
source code.
native
Usually refers to "native code", i.e. machine code for the target
microcontroller (such as ARM Thumb, Xtensa, x86/x64). The ``@native``
decorator can be applied to a MicroPython function to generate native
code instead of bytecode for that function, which will likely be
faster but use more RAM.
port
Usually short for :term:`MicroPython port`, but could also refer to
:term:`GPIO port`.
.py file
A file containing Python source code.
REPL
An acronym for "Read, Eval, Print, Loop". This is the interactive
Python prompt, useful for debugging or testing short snippets of code.
Most MicroPython boards make a REPL available over a UART, and this is
typically accessible on a host PC via USB.
stream
Also known as a "file-like object". An Python object which provides
sequential read-write access to the underlying data. A stream object
implements a corresponding interface, which consists of methods like
``read()``, ``write()``, ``readinto()``, ``seek()``, ``flush()``,
``close()``, etc. A stream is an important concept in MicroPython;
many I/O objects implement the stream interface, and thus can be used
consistently and interchangeably in different contexts. For more
information on streams in MicroPython, see the `io` module.
UART
Acronym for "Universal Asynchronous Receiver/Transmitter". This is a
peripheral that sends data over a pair of pins (TX & RX). Many boards
include a way to make at least one of the UARTs available to a host PC
as a serial port over USB.

View File

@ -224,7 +224,7 @@ def support_matrix_by_board(use_branded_name=True):
# flatmap with comprehensions # flatmap with comprehensions
boards = dict(sorted([board for matrix in mapped_exec for board in matrix])) boards = dict(sorted([board for matrix in mapped_exec for board in matrix]))
#print(json.dumps(boards, indent=2)) # print(json.dumps(boards, indent=2))
return boards return boards
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -4,6 +4,6 @@
.. |see_cpython_module| replace:: .. |see_cpython_module| replace::
*This module implements a subset of the corresponding* ``CPython`` *module, *This module implements a subset of the corresponding* :term:`CPython` *module,
as described below. For more information, refer to the original* as described below. For more information, refer to the original
``CPython`` *documentation:* CPython documentation:*

57
extmod/btstack/btstack.mk Normal file
View File

@ -0,0 +1,57 @@
# Makefile directives for BlueKitchen BTstack
ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
MICROPY_BLUETOOTH_BTSTACK_USB ?= 0
BTSTACK_EXTMOD_DIR = extmod/btstack
EXTMOD_SRC_C += extmod/btstack/modbluetooth_btstack.c
INC += -I$(TOP)/$(BTSTACK_EXTMOD_DIR)
CFLAGS_MOD += -DMICROPY_BLUETOOTH_BTSTACK=1
BTSTACK_DIR = $(TOP)/lib/btstack
ifneq ($(wildcard $(BTSTACK_DIR)/src),)
include $(BTSTACK_DIR)/src/Makefile.inc
include $(BTSTACK_DIR)/src/ble/Makefile.inc
INC += -I$(BTSTACK_DIR)/src
INC += -I$(BTSTACK_DIR)/3rd-party/bluedroid/decoder/include
INC += -I$(BTSTACK_DIR)/3rd-party/bluedroid/encoder/include
INC += -I$(BTSTACK_DIR)/3rd-party/md5
INC += -I$(BTSTACK_DIR)/3rd-party/yxml
SRC_BTSTACK = \
$(addprefix lib/btstack/src/, $(SRC_FILES)) \
$(addprefix lib/btstack/src/ble/, $(filter-out %_tlv.c, $(SRC_BLE_FILES))) \
lib/btstack/platform/embedded/btstack_run_loop_embedded.c
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_USB),1)
SRC_BTSTACK += \
lib/btstack/platform/libusb/hci_transport_h2_libusb.c
CFLAGS += $(shell pkg-config libusb-1.0 --cflags)
LDFLAGS += $(shell pkg-config libusb-1.0 --libs)
endif
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_ENABLE_CLASSIC),1)
include $(BTSTACK_DIR)/src/classic/Makefile.inc
SRC_BTSTACK += \
$(addprefix lib/btstack/src/classic/, $(SRC_CLASSIC_FILES))
endif
LIB_SRC_C += $(SRC_BTSTACK)
# Suppress some warnings.
BTSTACK_WARNING_CFLAGS = -Wno-old-style-definition -Wno-unused-variable -Wno-unused-parameter
ifneq ($(CC),clang)
BTSTACK_WARNING_CFLAGS += -Wno-format
endif
$(BUILD)/lib/btstack/src/%.o: CFLAGS += $(BTSTACK_WARNING_CFLAGS)
endif
endif

View File

@ -0,0 +1,47 @@
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
// BTstack features that can be enabled
#define ENABLE_BLE
#define ENABLE_LE_PERIPHERAL
#define ENABLE_LE_CENTRAL
// #define ENABLE_CLASSIC
#define ENABLE_LE_DATA_CHANNELS
// #define ENABLE_LOG_INFO
#define ENABLE_LOG_ERROR
// BTstack configuration. buffers, sizes, ...
#define HCI_ACL_PAYLOAD_SIZE 1021
#define MAX_NR_GATT_CLIENTS 1
#define MAX_NR_HCI_CONNECTIONS 1
#define MAX_NR_L2CAP_SERVICES 3
#define MAX_NR_L2CAP_CHANNELS 3
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
#define MAX_NR_RFCOMM_SERVICES 1
#define MAX_NR_RFCOMM_CHANNELS 1
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
#define MAX_NR_BNEP_SERVICES 1
#define MAX_NR_BNEP_CHANNELS 1
#define MAX_NR_HFP_CONNECTIONS 1
#define MAX_NR_WHITELIST_ENTRIES 1
#define MAX_NR_SM_LOOKUP_ENTRIES 3
#define MAX_NR_SERVICE_RECORD_ITEMS 1
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
#define MAX_NR_AVDTP_CONNECTIONS 1
#define MAX_NR_AVRCP_CONNECTIONS 1
#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
// #define NVM_NUM_DEVICE_DB_ENTRIES 16
// We don't give btstack a malloc, so use a fixed-size ATT DB.
#define MAX_ATT_DB_SIZE 512
// BTstack HAL configuration
#define HAVE_EMBEDDED_TIME_MS
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H
#if MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
#include "extmod/modbluetooth.h"
#include "lib/btstack/src/btstack.h"
typedef struct _mp_btstack_pending_op_t mp_btstack_pending_op_t;
typedef struct _mp_bluetooth_btstack_root_pointers_t {
// This stores both the advertising data and the scan response data, concatenated together.
uint8_t *adv_data;
// Total length of both.
size_t adv_data_alloc;
// Characteristic (and descriptor) value storage.
mp_gatts_db_t gatts_db;
btstack_linked_list_t pending_ops;
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
// Registration for notify/indicate events.
gatt_client_notification_t notification;
#endif
} mp_bluetooth_btstack_root_pointers_t;
enum {
MP_BLUETOOTH_BTSTACK_STATE_OFF,
MP_BLUETOOTH_BTSTACK_STATE_STARTING,
MP_BLUETOOTH_BTSTACK_STATE_ACTIVE,
MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT,
};
extern volatile int mp_bluetooth_btstack_state;
void mp_bluetooth_btstack_port_init(void);
void mp_bluetooth_btstack_port_deinit(void);
void mp_bluetooth_btstack_port_start(void);
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_MODBLUETOOTH_BTSTACK_H

View File

@ -51,7 +51,7 @@ CFLAGS_MOD += -DMICROPY_PY_USSL=1
ifeq ($(MICROPY_SSL_AXTLS),1) ifeq ($(MICROPY_SSL_AXTLS),1)
CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include
AXTLS_DIR = lib/axtls AXTLS_DIR = lib/axtls
$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA) $(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition -Dmp_stream_errno=errno $(AXTLS_DEFS_EXTRA)
SRC_MOD += $(addprefix $(AXTLS_DIR)/,\ SRC_MOD += $(addprefix $(AXTLS_DIR)/,\
ssl/asn1.c \ ssl/asn1.c \
ssl/loader.c \ ssl/loader.c \

View File

@ -18,6 +18,7 @@
typedef struct _mp_obj_btree_t { typedef struct _mp_obj_btree_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_obj_t stream; // retain a reference to prevent GC from reclaiming it
DB *db; DB *db;
mp_obj_t start_key; mp_obj_t start_key;
mp_obj_t end_key; mp_obj_t end_key;
@ -44,9 +45,10 @@ void __dbpanic(DB *db) {
mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db); mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
} }
STATIC mp_obj_btree_t *btree_new(DB *db) { STATIC mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) {
mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t); mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);
o->base.type = &btree_type; o->base.type = &btree_type;
o->stream = stream;
o->db = db; o->db = db;
o->start_key = mp_const_none; o->start_key = mp_const_none;
o->end_key = mp_const_none; o->end_key = mp_const_none;
@ -228,14 +230,14 @@ STATIC mp_obj_t btree_iternext(mp_obj_t self_in) {
} }
STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_btree_t *self = mp_instance_cast_to_native_base(self_in, &btree_type); mp_obj_btree_t *self = mp_obj_cast_to_native_base(self_in, &btree_type);
if (value == MP_OBJ_NULL) { if (value == MP_OBJ_NULL) {
// delete // delete
DBT key; DBT key;
key.data = (void *)mp_obj_str_get_data(index, &key.size); key.data = (void *)mp_obj_str_get_data(index, &key.size);
int res = __bt_delete(self->db, &key, 0); int res = __bt_delete(self->db, &key, 0);
if (res == RET_SPECIAL) { if (res == RET_SPECIAL) {
nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); mp_raise_type(&mp_type_KeyError);
} }
CHECK_ERROR(res); CHECK_ERROR(res);
return mp_const_none; return mp_const_none;
@ -245,7 +247,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
key.data = (void *)mp_obj_str_get_data(index, &key.size); key.data = (void *)mp_obj_str_get_data(index, &key.size);
int res = __bt_get(self->db, &key, &val, 0); int res = __bt_get(self->db, &key, &val, 0);
if (res == RET_SPECIAL) { if (res == RET_SPECIAL) {
nlr_raise(mp_obj_new_exception(&mp_type_KeyError)); mp_raise_type(&mp_type_KeyError);
} }
CHECK_ERROR(res); CHECK_ERROR(res);
return mp_obj_new_bytes(val.data, val.size); return mp_obj_new_bytes(val.data, val.size);
@ -340,7 +342,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t
if (db == NULL) { if (db == NULL) {
mp_raise_OSError(errno); mp_raise_OSError(errno);
} }
return MP_OBJ_FROM_PTR(btree_new(db)); return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0]));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);

View File

@ -22,6 +22,10 @@ typedef struct _mp_obj_framebuf_t {
uint8_t format; uint8_t format;
} mp_obj_framebuf_t; } mp_obj_framebuf_t;
#if !MICROPY_ENABLE_DYNRUNTIME
STATIC const mp_obj_type_t mp_type_framebuf;
#endif
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t); typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t);
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int); typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int);
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t); typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
@ -278,7 +282,7 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, cons
case FRAMEBUF_GS8: case FRAMEBUF_GS8:
break; break;
default: default:
mp_raise_ValueError(translate("invalid format")); mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
} }
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
@ -288,7 +292,7 @@ STATIC const mp_obj_type_t mp_type_framebuf;
// Helper to ensure we have the native super class instead of a subclass. // Helper to ensure we have the native super class instead of a subclass.
static mp_obj_framebuf_t *native_framebuf(mp_obj_t framebuf_obj) { static mp_obj_framebuf_t *native_framebuf(mp_obj_t framebuf_obj) {
mp_obj_t native_framebuf = mp_instance_cast_to_native_base(framebuf_obj, &mp_type_framebuf); mp_obj_t native_framebuf = mp_obj_cast_to_native_base(framebuf_obj, &mp_type_framebuf);
mp_obj_assert_native_inited(native_framebuf); mp_obj_assert_native_inited(native_framebuf);
return MP_OBJ_TO_PTR(native_framebuf); return MP_OBJ_TO_PTR(native_framebuf);
} }

294
extmod/moduasyncio.c Normal file
View File

@ -0,0 +1,294 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/runtime.h"
#include "py/smallint.h"
#include "py/pairheap.h"
#include "py/mphal.h"
#if MICROPY_PY_UASYNCIO
typedef struct _mp_obj_task_t {
mp_pairheap_t pairheap;
mp_obj_t coro;
mp_obj_t data;
mp_obj_t waiting;
mp_obj_t ph_key;
} mp_obj_task_t;
typedef struct _mp_obj_task_queue_t {
mp_obj_base_t base;
mp_obj_task_t *heap;
} mp_obj_task_queue_t;
STATIC const mp_obj_type_t task_queue_type;
STATIC const mp_obj_type_t task_type;
STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
/******************************************************************************/
// Ticks for task ordering in pairing heap
STATIC mp_obj_t ticks(void) {
return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
}
STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
mp_int_t diff = ((t1 - t0 + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))
- MICROPY_PY_UTIME_TICKS_PERIOD / 2;
return diff;
}
STATIC int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
mp_obj_task_t *t1 = (mp_obj_task_t *)n1;
mp_obj_task_t *t2 = (mp_obj_task_t *)n2;
return MP_OBJ_SMALL_INT_VALUE(ticks_diff(t1->ph_key, t2->ph_key)) < 0;
}
/******************************************************************************/
// TaskQueue class
STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void)args;
mp_arg_check_num(n_args, kw_args, 0, 0, false);
mp_obj_task_queue_t *self = m_new_obj(mp_obj_task_queue_t);
self->base.type = type;
self->heap = (mp_obj_task_t *)mp_pairheap_new(task_lt);
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t task_queue_peek(mp_obj_t self_in) {
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
if (self->heap == NULL) {
return mp_const_none;
} else {
return MP_OBJ_FROM_PTR(self->heap);
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_peek_obj, task_queue_peek);
STATIC mp_obj_t task_queue_push_sorted(size_t n_args, const mp_obj_t *args) {
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(args[0]);
mp_obj_task_t *task = MP_OBJ_TO_PTR(args[1]);
task->data = mp_const_none;
if (n_args == 2) {
task->ph_key = ticks();
} else {
assert(mp_obj_is_small_int(args[2]));
task->ph_key = args[2];
}
self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, &self->heap->pairheap, &task->pairheap);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_sorted_obj, 2, 3, task_queue_push_sorted);
STATIC mp_obj_t task_queue_pop_head(mp_obj_t self_in) {
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_task_t *head = (mp_obj_task_t *)mp_pairheap_peek(task_lt, &self->heap->pairheap);
if (head == NULL) {
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
}
self->heap = (mp_obj_task_t *)mp_pairheap_pop(task_lt, &self->heap->pairheap);
return MP_OBJ_FROM_PTR(head);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_pop_head_obj, task_queue_pop_head);
STATIC mp_obj_t task_queue_remove(mp_obj_t self_in, mp_obj_t task_in) {
mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_task_t *task = MP_OBJ_TO_PTR(task_in);
self->heap = (mp_obj_task_t *)mp_pairheap_delete(task_lt, &self->heap->pairheap, &task->pairheap);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_queue_remove_obj, task_queue_remove);
STATIC const mp_rom_map_elem_t task_queue_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_peek), MP_ROM_PTR(&task_queue_peek_obj) },
{ MP_ROM_QSTR(MP_QSTR_push_sorted), MP_ROM_PTR(&task_queue_push_sorted_obj) },
{ MP_ROM_QSTR(MP_QSTR_push_head), MP_ROM_PTR(&task_queue_push_sorted_obj) },
{ MP_ROM_QSTR(MP_QSTR_pop_head), MP_ROM_PTR(&task_queue_pop_head_obj) },
{ MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&task_queue_remove_obj) },
};
STATIC MP_DEFINE_CONST_DICT(task_queue_locals_dict, task_queue_locals_dict_table);
STATIC const mp_obj_type_t task_queue_type = {
{ &mp_type_type },
.name = MP_QSTR_TaskQueue,
.make_new = task_queue_make_new,
.locals_dict = (mp_obj_dict_t *)&task_queue_locals_dict,
};
/******************************************************************************/
// Task class
// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_arg_check_num(n_args, kw_args, 1, 2, false);
mp_obj_task_t *self = m_new_obj(mp_obj_task_t);
self->pairheap.base.type = type;
mp_pairheap_init_node(task_lt, &self->pairheap);
self->coro = args[0];
self->data = mp_const_none;
self->waiting = mp_const_none;
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
if (n_args == 2) {
uasyncio_context = args[1];
}
return MP_OBJ_FROM_PTR(self);
}
STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
// Check if task is already finished.
if (self->coro == mp_const_none) {
return mp_const_false;
}
// Can't cancel self (not supported yet).
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
if (self_in == cur_task) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
}
// If Task waits on another task then forward the cancel to the one it's waiting on.
while (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(self->data)), MP_OBJ_FROM_PTR(&task_type))) {
self = MP_OBJ_TO_PTR(self->data);
}
mp_obj_t _task_queue = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
// Reschedule Task as a cancelled task.
mp_obj_t dest[3];
mp_load_method_maybe(self->data, MP_QSTR_remove, dest);
if (dest[0] != MP_OBJ_NULL) {
// Not on the main running queue, remove the task from the queue it's on.
dest[2] = MP_OBJ_FROM_PTR(self);
mp_call_method_n_kw(1, 0, dest);
// _task_queue.push_head(self)
dest[0] = _task_queue;
dest[1] = MP_OBJ_FROM_PTR(self);
task_queue_push_sorted(2, dest);
} else if (ticks_diff(self->ph_key, ticks()) > 0) {
// On the main running queue but scheduled in the future, so bring it forward to now.
// _task_queue.remove(self)
task_queue_remove(_task_queue, MP_OBJ_FROM_PTR(self));
// _task_queue.push_head(self)
dest[0] = _task_queue;
dest[1] = MP_OBJ_FROM_PTR(self);
task_queue_push_sorted(2, dest);
}
self->data = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
return mp_const_true;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) {
// Load
if (attr == MP_QSTR_coro) {
dest[0] = self->coro;
} else if (attr == MP_QSTR_data) {
dest[0] = self->data;
} else if (attr == MP_QSTR_waiting) {
if (self->waiting != mp_const_none) {
dest[0] = self->waiting;
}
} else if (attr == MP_QSTR_cancel) {
dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
dest[1] = self_in;
} else if (attr == MP_QSTR_ph_key) {
dest[0] = self->ph_key;
}
} else if (dest[1] != MP_OBJ_NULL) {
// Store
if (attr == MP_QSTR_coro) {
self->coro = dest[1];
dest[0] = MP_OBJ_NULL;
} else if (attr == MP_QSTR_data) {
self->data = dest[1];
dest[0] = MP_OBJ_NULL;
} else if (attr == MP_QSTR_waiting) {
self->waiting = dest[1];
dest[0] = MP_OBJ_NULL;
}
}
}
STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
(void)iter_buf;
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (self->waiting == mp_const_none) {
self->waiting = task_queue_make_new(&task_queue_type, 0, NULL, NULL);
}
return self_in;
}
STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
if (self->coro == mp_const_none) {
// Task finished, raise return value to caller so it can continue.
nlr_raise(self->data);
} else {
// Put calling task on waiting queue.
mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t args[2] = { self->waiting, cur_task };
task_queue_push_sorted(2, args);
// Set calling task's data to this task that it waits on, to double-link it.
((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
}
return mp_const_none;
}
STATIC const mp_obj_type_t task_type = {
{ &mp_type_type },
.name = MP_QSTR_Task,
.make_new = task_make_new,
.attr = task_attr,
.getiter = task_getiter,
.iternext = task_iternext,
};
/******************************************************************************/
// C-level uasyncio module
STATIC const mp_rom_map_elem_t mp_module_uasyncio_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__uasyncio) },
{ MP_ROM_QSTR(MP_QSTR_TaskQueue), MP_ROM_PTR(&task_queue_type) },
{ MP_ROM_QSTR(MP_QSTR_Task), MP_ROM_PTR(&task_type) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_uasyncio_globals, mp_module_uasyncio_globals_table);
const mp_obj_module_t mp_module_uasyncio = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_uasyncio_globals,
};
#endif // MICROPY_PY_UASYNCIO

View File

@ -9,7 +9,6 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/binary.h" #include "py/binary.h"
#include "extmod/modubinascii.h"
static void check_not_unicode(const mp_obj_t arg) { static void check_not_unicode(const mp_obj_t arg) {
#if MICROPY_CPYTHON_COMPAT #if MICROPY_CPYTHON_COMPAT
@ -19,7 +18,7 @@ static void check_not_unicode(const mp_obj_t arg) {
#endif #endif
} }
mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
// Second argument is for an extension to allow a separator to be used // Second argument is for an extension to allow a separator to be used
// between values. // between values.
const char *sep = NULL; const char *sep = NULL;
@ -59,14 +58,14 @@ mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
} }
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);
mp_obj_t mod_binascii_unhexlify(mp_obj_t data) { STATIC mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
if ((bufinfo.len & 1) != 0) { if ((bufinfo.len & 1) != 0) {
mp_raise_ValueError(translate("odd-length string")); mp_raise_ValueError(MP_ERROR_TEXT("odd-length string"));
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, bufinfo.len / 2); vstr_init_len(&vstr, bufinfo.len / 2);
@ -77,7 +76,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
if (unichar_isxdigit(hex_ch)) { if (unichar_isxdigit(hex_ch)) {
hex_byte += unichar_xdigit_value(hex_ch); hex_byte += unichar_xdigit_value(hex_ch);
} else { } else {
mp_raise_ValueError(translate("non-hex digit found")); mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit found"));
} }
if (i & 1) { if (i & 1) {
hex_byte <<= 4; hex_byte <<= 4;
@ -88,7 +87,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
} }
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
// If ch is a character in the base64 alphabet, and is not a pad character, then // If ch is a character in the base64 alphabet, and is not a pad character, then
// the corresponding integer between 0 and 63, inclusively, is returned. // the corresponding integer between 0 and 63, inclusively, is returned.
@ -109,7 +108,7 @@ static int mod_binascii_sextet(byte ch) {
} }
} }
mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) { STATIC mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
byte *in = bufinfo.buf; byte *in = bufinfo.buf;
@ -145,14 +144,14 @@ mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
} }
if (nbits) { if (nbits) {
mp_raise_ValueError(translate("incorrect padding")); mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
} }
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) { STATIC mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
check_not_unicode(data); check_not_unicode(data);
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
@ -203,12 +202,12 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
*out = '\n'; *out = '\n';
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
} }
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);
#if MICROPY_PY_UBINASCII_CRC32 #if MICROPY_PY_UBINASCII_CRC32
#include "../../lib/uzlib/src/tinf.h" #include "../../lib/uzlib/src/tinf.h"
mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo; mp_buffer_info_t bufinfo;
check_not_unicode(args[0]); check_not_unicode(args[0]);
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
@ -216,11 +215,9 @@ mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
return mp_obj_new_int_from_uint(crc ^ 0xffffffff); return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
#endif #endif
#if MICROPY_PY_UBINASCII
STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
{ MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) }, { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) },
@ -238,5 +235,3 @@ const mp_obj_module_t mp_module_ubinascii = {
.base = { &mp_type_module }, .base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_binascii_globals, .globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
}; };
#endif // MICROPY_PY_UBINASCII

View File

@ -1,21 +0,0 @@
// Copyright (c) 2014 Paul Sokolovsky
// SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors)
//
// SPDX-License-Identifier: MIT
#ifndef MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H
#define MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H
extern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args);
extern mp_obj_t mod_binascii_unhexlify(mp_obj_t data);
extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data);
extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data);
extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj);
#endif // MICROPY_INCLUDED_EXTMOD_MODUBINASCII_H

View File

@ -98,7 +98,7 @@ typedef struct _mp_obj_uctypes_struct_t {
} mp_obj_uctypes_struct_t; } mp_obj_uctypes_struct_t;
STATIC NORETURN void syntax_error(void) { STATIC NORETURN void syntax_error(void) {
mp_raise_TypeError(translate("syntax error in uctypes descriptor")); mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor"));
} }
STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
@ -118,11 +118,7 @@ STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_p
(void)kind; (void)kind;
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
const char *typen = "unk"; const char *typen = "unk";
if (mp_obj_is_type(self->desc, &mp_type_dict) if (mp_obj_is_dict_or_ordereddict(self->desc)) {
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|| mp_obj_is_type(self->desc, &mp_type_ordereddict)
#endif
) {
typen = "STRUCT"; typen = "STRUCT";
} else if (mp_obj_is_type(self->desc, &mp_type_tuple)) { } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
@ -195,11 +191,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
} }
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) { STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {
if (!mp_obj_is_type(desc_in, &mp_type_dict) if (!mp_obj_is_dict_or_ordereddict(desc_in)) {
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
&& !mp_obj_is_type(desc_in, &mp_type_ordereddict)
#endif
) {
if (mp_obj_is_type(desc_in, &mp_type_tuple)) { if (mp_obj_is_type(desc_in, &mp_type_tuple)) {
return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size); return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);
} else if (mp_obj_is_small_int(desc_in)) { } else if (mp_obj_is_small_int(desc_in)) {
@ -207,7 +199,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_
// but scalar structure field is lowered into native Python int, so all // but scalar structure field is lowered into native Python int, so all
// type info is lost. So, we cannot say if it's scalar type description, // type info is lost. So, we cannot say if it's scalar type description,
// or such lowered scalar. // or such lowered scalar.
mp_raise_TypeError(translate("Cannot unambiguously get sizeof scalar")); mp_raise_TypeError(MP_ERROR_TEXT("cannot unambiguously get sizeof scalar"));
} }
syntax_error(); syntax_error();
} }
@ -341,9 +333,9 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
return mp_obj_new_int_from_ll(((int64_t *)p)[index]); return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
case FLOAT32: case FLOAT32:
return mp_obj_new_float(((float *)p)[index]); return mp_obj_new_float_from_f(((float *)p)[index]);
case FLOAT64: case FLOAT64:
return mp_obj_new_float(((double *)p)[index]); return mp_obj_new_float_from_d(((double *)p)[index]);
#endif #endif
default: default:
assert(0); assert(0);
@ -354,11 +346,10 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
if (val_type == FLOAT32 || val_type == FLOAT64) { if (val_type == FLOAT32 || val_type == FLOAT64) {
mp_float_t v = mp_obj_get_float(val);
if (val_type == FLOAT32) { if (val_type == FLOAT32) {
((float *)p)[index] = v; ((float *)p)[index] = mp_obj_get_float_to_f(val);
} else { } else {
((double *)p)[index] = v; ((double *)p)[index] = mp_obj_get_float_to_d(val);
} }
return; return;
} }
@ -400,12 +391,8 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) { STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
if (!mp_obj_is_type(self->desc, &mp_type_dict) if (!mp_obj_is_dict_or_ordereddict(self->desc)) {
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
&& !mp_obj_is_type(self->desc, &mp_type_ordereddict)
#endif
) {
mp_raise_TypeError(translate("struct: no fields"));
} }
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
@ -530,7 +517,7 @@ STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
} }
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_obj_t value) { STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_obj_t value) {
mp_obj_uctypes_struct_t *self = mp_instance_cast_to_native_base(base_in, &uctypes_struct_type); mp_obj_uctypes_struct_t *self = mp_obj_cast_to_native_base(base_in, &uctypes_struct_type);
if (value == MP_OBJ_NULL) { if (value == MP_OBJ_NULL) {
// delete // delete
@ -538,7 +525,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
} else { } else {
// load / store // load / store
if (!mp_obj_is_type(self->desc, &mp_type_tuple)) { if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {
mp_raise_TypeError(translate("struct: cannot index")); mp_raise_TypeError(MP_ERROR_TEXT("struct: can't index"));
} }
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
@ -552,7 +539,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
arr_sz &= VALUE_MASK(VAL_TYPE_BITS); arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
if (index >= arr_sz) { if (index >= arr_sz) {
mp_raise_IndexError_varg(translate("%q index out of range"), MP_QSTR_struct); mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("struct: index out of range"));
} }
if (t->len == 2) { if (t->len == 2) {

View File

@ -14,7 +14,7 @@
STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) { STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
if (!mp_obj_is_type(heap_in, &mp_type_list)) { if (!mp_obj_is_type(heap_in, &mp_type_list)) {
mp_raise_TypeError(translate("heap must be a list")); mp_raise_TypeError(MP_ERROR_TEXT("heap must be a list"));
} }
return MP_OBJ_TO_PTR(heap_in); return MP_OBJ_TO_PTR(heap_in);
} }
@ -62,7 +62,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) { STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
mp_obj_list_t *heap = uheapq_get_heap(heap_in); mp_obj_list_t *heap = uheapq_get_heap(heap_in);
if (heap->len == 0) { if (heap->len == 0) {
mp_raise_IndexError(translate("empty heap")); mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
} }
mp_obj_t item = heap->items[0]; mp_obj_t item = heap->items[0];
heap->len -= 1; heap->len -= 1;

View File

@ -135,7 +135,7 @@ STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
stack.len = 0; stack.len = 0;
stack.items = NULL; stack.items = NULL;
mp_obj_t stack_top = MP_OBJ_NULL; mp_obj_t stack_top = MP_OBJ_NULL;
mp_obj_type_t *stack_top_type = NULL; const mp_obj_type_t *stack_top_type = NULL;
mp_obj_t stack_key = MP_OBJ_NULL; mp_obj_t stack_key = MP_OBJ_NULL;
S_NEXT(s); S_NEXT(s);
for (;;) { for (;;) {
@ -339,7 +339,7 @@ success:
return stack_top; return stack_top;
fail: fail:
mp_raise_ValueError(translate("syntax error in JSON")); mp_raise_ValueError(MP_ERROR_TEXT("syntax error in JSON"));
} }
STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {

View File

@ -132,7 +132,7 @@ STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {
if (len > 0) { if (len > 0) {
return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL); return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
} else { } else {
nlr_raise(mp_obj_new_exception(&mp_type_IndexError)); mp_raise_type(&mp_type_IndexError);
} }
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
@ -141,21 +141,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits // returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
STATIC mp_float_t yasmarang_float(void) { STATIC mp_float_t yasmarang_float(void) {
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE mp_float_union_t u;
typedef uint64_t mp_float_int_t;
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
typedef uint32_t mp_float_int_t;
#endif
union {
mp_float_t f;
#if MP_ENDIANNESS_LITTLE
struct { mp_float_int_t frc : MP_FLOAT_FRAC_BITS, exp : MP_FLOAT_EXP_BITS, sgn : 1;
} p;
#else
struct { mp_float_int_t sgn : 1, exp : MP_FLOAT_EXP_BITS, frc : MP_FLOAT_FRAC_BITS;
} p;
#endif
} u;
u.p.sgn = 0; u.p.sgn = 0;
u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1; u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
if (MP_FLOAT_FRAC_BITS <= 32) { if (MP_FLOAT_FRAC_BITS <= 32) {

View File

@ -18,7 +18,7 @@
#include "re1.5/re1.5.h" #include "re1.5/re1.5.h"
#if CIRCUITPY_RE_DEBUG #if MICROPY_PY_URE_DEBUG
#define FLAG_DEBUG 0x1000 #define FLAG_DEBUG 0x1000
#endif #endif
@ -34,6 +34,10 @@ typedef struct _mp_obj_match_t {
const char *caps[0]; const char *caps[0];
} mp_obj_match_t; } mp_obj_match_t;
STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args);
#if !MICROPY_ENABLE_DYNRUNTIME
STATIC const mp_obj_type_t re_type;
#endif
STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind; (void)kind;
@ -156,7 +160,12 @@ STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
(void)n_args; (void)n_args;
mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_re_t *self;
if (mp_obj_is_type(args[0], &re_type)) {
self = MP_OBJ_TO_PTR(args[0]);
} else {
self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
}
Subject subj; Subject subj;
size_t len; size_t len;
subj.begin = mp_obj_str_get_data(args[1], &len); subj.begin = mp_obj_str_get_data(args[1], &len);
@ -245,7 +254,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin); mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
mp_obj_list_append(retval, s); mp_obj_list_append(retval, s);
if (self->re.sub > 0) { if (self->re.sub > 0) {
mp_raise_NotImplementedError(translate("Splitting with sub-captures")); mp_raise_NotImplementedError(MP_ERROR_TEXT("Splitting with sub-captures"));
} }
subj.begin = caps[1]; subj.begin = caps[1];
if (maxsplit > 0 && --maxsplit == 0) { if (maxsplit > 0 && --maxsplit == 0) {
@ -408,7 +417,7 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
} }
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size); mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
o->base.type = &re_type; o->base.type = &re_type;
#if CIRCUITPY_RE_DEBUG #if MICROPY_PY_URE_DEBUG
int flags = 0; int flags = 0;
if (n_args > 1) { if (n_args > 1) {
flags = mp_obj_get_int(args[1]); flags = mp_obj_get_int(args[1]);
@ -419,9 +428,9 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
int error = re1_5_compilecode(&o->re, re_str); int error = re1_5_compilecode(&o->re, re_str);
if (error != 0) { if (error != 0) {
error: error:
mp_raise_ValueError(translate("Error in regex")); mp_raise_ValueError(MP_ERROR_TEXT("Error in regex"));
} }
#if CIRCUITPY_RE_DEBUG #if MICROPY_PY_URE_DEBUG
if (flags & FLAG_DEBUG) { if (flags & FLAG_DEBUG) {
re1_5_dumpcode(&o->re); re1_5_dumpcode(&o->re);
} }
@ -452,7 +461,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);
#if MICROPY_PY_URE_SUB #if MICROPY_PY_URE_SUB
STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) {
mp_obj_t self = mod_re_compile(1, args); mp_obj_t self = mod_re_compile(1, args);
return re_sub_helper(self, n_args, args); return re_sub_helper(MP_OBJ_TO_PTR(self), n_args, args);
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
#endif #endif
@ -470,7 +479,7 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
#if MICROPY_PY_URE_SUB #if MICROPY_PY_URE_SUB
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) }, { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
#endif #endif
#if CIRCUITPY_RE_DEBUG #if MICROPY_PY_URE_DEBUG
{ MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) }, { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
#endif #endif
}; };
@ -488,7 +497,7 @@ const mp_obj_module_t mp_module_ure = {
#define re1_5_fatal(x) assert(!x) #define re1_5_fatal(x) assert(!x)
#include "re1.5/compilecode.c" #include "re1.5/compilecode.c"
#if CIRCUITPY_RE_DEBUG #if MICROPY_PY_URE_DEBUG
#include "re1.5/dumpcode.c" #include "re1.5/dumpcode.c"
#endif #endif
#include "re1.5/recursiveloop.c" #include "re1.5/recursiveloop.c"

View File

@ -105,7 +105,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) { if (n_args == 4) {
if (args[3] != mp_const_none) { if (args[3] != mp_const_none) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
float timeout_f = mp_obj_get_float(args[3]); float timeout_f = mp_obj_get_float_to_f(args[3]);
if (timeout_f >= 0) { if (timeout_f >= 0) {
timeout = (mp_uint_t)(timeout_f * 1000); timeout = (mp_uint_t)(timeout_f * 1000);
} }

View File

@ -107,7 +107,7 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
mp_obj_t heap_in = args[0]; mp_obj_t heap_in = args[0];
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
if (heap->len == heap->alloc) { if (heap->len == heap->alloc) {
mp_raise_IndexError(translate("queue overflow")); mp_raise_IndexError(MP_ERROR_TEXT("queue overflow"));
} }
mp_uint_t l = heap->len; mp_uint_t l = heap->len;
heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]); heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);
@ -123,7 +123,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_ut
STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) { STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
if (heap->len == 0) { if (heap->len == 0) {
mp_raise_IndexError(translate("empty heap")); mp_raise_IndexError(MP_ERROR_TEXT("empty heap"));
} }
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref); mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) { if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
@ -148,7 +148,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) { STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in); mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
if (heap->len == 0) { if (heap->len == 0) {
mp_raise_IndexError(translate("empty heap")); mp_raise_IndexError(MP_ERROR_TEXT("empty heap"));
} }
struct qentry *item = &heap->items[0]; struct qentry *item = &heap->items[0];

View File

@ -43,7 +43,7 @@ STATIC int read_src_stream(TINF_DATA *data) {
mp_raise_OSError(err); mp_raise_OSError(err);
} }
if (out_sz == 0) { if (out_sz == 0) {
nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); mp_raise_type(&mp_type_EOFError);
} }
return c; return c;
} }
@ -74,7 +74,7 @@ STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, cons
dict_opt = uzlib_zlib_parse_header(&o->decomp); dict_opt = uzlib_zlib_parse_header(&o->decomp);
if (dict_opt < 0) { if (dict_opt < 0) {
header_error: header_error:
mp_raise_ValueError(translate("compression header")); mp_raise_ValueError(MP_ERROR_TEXT("compression header"));
} }
dict_sz = 1 << dict_opt; dict_sz = 1 << dict_opt;
} else { } else {

View File

@ -87,6 +87,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
PC++; // Skip # of pair byte PC++; // Skip # of pair byte
prog->len++; prog->len++;
for (cnt = 0; *re != ']'; re++, cnt++) { for (cnt = 0; *re != ']'; re++, cnt++) {
if (*re == '\\') {
++re;
}
if (!*re) return NULL; if (!*re) return NULL;
const char *b = re; const char *b = re;
if (*re == '\\') { if (*re == '\\') {

View File

@ -0,0 +1,29 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019 Damien P. George
from .core import *
__version__ = (3, 0, 0)
_attrs = {
"wait_for": "funcs",
"wait_for_ms": "funcs",
"gather": "funcs",
"Event": "event",
"Lock": "lock",
"open_connection": "stream",
"start_server": "stream",
"StreamReader": "stream",
"StreamWriter": "stream",
}
# Lazy loader, effectively does:
# global attr
# from .mod import attr
def __getattr__(attr):
mod = _attrs.get(attr, None)
if mod is None:
raise AttributeError(attr)
value = getattr(__import__(mod, None, None, True, 1), attr)
globals()[attr] = value
return value

277
extmod/uasyncio/core.py Normal file
View File

@ -0,0 +1,277 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019 Damien P. George
from time import ticks_ms as ticks, ticks_diff, ticks_add
import sys, select
# Import TaskQueue and Task, preferring built-in C code over Python code
try:
from _uasyncio import TaskQueue, Task
except:
from .task import TaskQueue, Task
################################################################################
# Exceptions
class CancelledError(BaseException):
pass
class TimeoutError(Exception):
pass
# Used when calling Loop.call_exception_handler
_exc_context = {"message": "Task exception wasn't retrieved", "exception": None, "future": None}
################################################################################
# Sleep functions
# "Yield" once, then raise StopIteration
class SingletonGenerator:
def __init__(self):
self.state = None
self.exc = StopIteration()
def __iter__(self):
return self
def __next__(self):
if self.state is not None:
_task_queue.push_sorted(cur_task, self.state)
self.state = None
return None
else:
self.exc.__traceback__ = None
raise self.exc
# Pause task execution for the given time (integer in milliseconds, uPy extension)
# Use a SingletonGenerator to do it without allocating on the heap
def sleep_ms(t, sgen=SingletonGenerator()):
assert sgen.state is None
sgen.state = ticks_add(ticks(), max(0, t))
return sgen
# Pause task execution for the given time (in seconds)
def sleep(t):
return sleep_ms(int(t * 1000))
################################################################################
# Queue and poller for stream IO
class IOQueue:
def __init__(self):
self.poller = select.poll()
self.map = {} # maps id(stream) to [task_waiting_read, task_waiting_write, stream]
def _enqueue(self, s, idx):
if id(s) not in self.map:
entry = [None, None, s]
entry[idx] = cur_task
self.map[id(s)] = entry
self.poller.register(s, select.POLLIN if idx == 0 else select.POLLOUT)
else:
sm = self.map[id(s)]
assert sm[idx] is None
assert sm[1 - idx] is not None
sm[idx] = cur_task
self.poller.modify(s, select.POLLIN | select.POLLOUT)
# Link task to this IOQueue so it can be removed if needed
cur_task.data = self
def _dequeue(self, s):
del self.map[id(s)]
self.poller.unregister(s)
def queue_read(self, s):
self._enqueue(s, 0)
def queue_write(self, s):
self._enqueue(s, 1)
def remove(self, task):
while True:
del_s = None
for k in self.map: # Iterate without allocating on the heap
q0, q1, s = self.map[k]
if q0 is task or q1 is task:
del_s = s
break
if del_s is not None:
self._dequeue(s)
else:
break
def wait_io_event(self, dt):
for s, ev in self.poller.ipoll(dt):
sm = self.map[id(s)]
# print('poll', s, sm, ev)
if ev & ~select.POLLOUT and sm[0] is not None:
# POLLIN or error
_task_queue.push_head(sm[0])
sm[0] = None
if ev & ~select.POLLIN and sm[1] is not None:
# POLLOUT or error
_task_queue.push_head(sm[1])
sm[1] = None
if sm[0] is None and sm[1] is None:
self._dequeue(s)
elif sm[0] is None:
self.poller.modify(s, select.POLLOUT)
else:
self.poller.modify(s, select.POLLIN)
################################################################################
# Main run loop
# Ensure the awaitable is a task
def _promote_to_task(aw):
return aw if isinstance(aw, Task) else create_task(aw)
# Create and schedule a new task from a coroutine
def create_task(coro):
if not hasattr(coro, "send"):
raise TypeError("coroutine expected")
t = Task(coro, globals())
_task_queue.push_head(t)
return t
# Keep scheduling tasks until there are none left to schedule
def run_until_complete(main_task=None):
global cur_task
excs_all = (CancelledError, Exception) # To prevent heap allocation in loop
excs_stop = (CancelledError, StopIteration) # To prevent heap allocation in loop
while True:
# Wait until the head of _task_queue is ready to run
dt = 1
while dt > 0:
dt = -1
t = _task_queue.peek()
if t:
# A task waiting on _task_queue; "ph_key" is time to schedule task at
dt = max(0, ticks_diff(t.ph_key, ticks()))
elif not _io_queue.map:
# No tasks can be woken so finished running
return
# print('(poll {})'.format(dt), len(_io_queue.map))
_io_queue.wait_io_event(dt)
# Get next task to run and continue it
t = _task_queue.pop_head()
cur_task = t
try:
# Continue running the coroutine, it's responsible for rescheduling itself
exc = t.data
if not exc:
t.coro.send(None)
else:
t.data = None
t.coro.throw(exc)
except excs_all as er:
# Check the task is not on any event queue
assert t.data is None
# This task is done, check if it's the main task and then loop should stop
if t is main_task:
if isinstance(er, StopIteration):
return er.value
raise er
# Save return value of coro to pass up to caller
t.data = er
# Schedule any other tasks waiting on the completion of this task
waiting = False
if hasattr(t, "waiting"):
while t.waiting.peek():
_task_queue.push_head(t.waiting.pop_head())
waiting = True
t.waiting = None # Free waiting queue head
# Print out exception for detached tasks
if not waiting and not isinstance(er, excs_stop):
_exc_context["exception"] = er
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# Indicate task is done
t.coro = None
# Create a new task from a coroutine and run it until it finishes
def run(coro):
return run_until_complete(create_task(coro))
################################################################################
# Event loop wrapper
async def _stopper():
pass
_stop_task = None
class Loop:
_exc_handler = None
def create_task(coro):
return create_task(coro)
def run_forever():
global _stop_task
_stop_task = Task(_stopper(), globals())
run_until_complete(_stop_task)
# TODO should keep running until .stop() is called, even if there're no tasks left
def run_until_complete(aw):
return run_until_complete(_promote_to_task(aw))
def stop():
global _stop_task
if _stop_task is not None:
_task_queue.push_head(_stop_task)
# If stop() is called again, do nothing
_stop_task = None
def close():
pass
def set_exception_handler(handler):
Loop._exc_handler = handler
def get_exception_handler():
return Loop._exc_handler
def default_exception_handler(loop, context):
print(context["message"])
print("future:", context["future"], "coro=", context["future"].coro)
sys.print_exception(context["exception"])
def call_exception_handler(context):
(Loop._exc_handler or Loop.default_exception_handler)(Loop, context)
# The runq_len and waitq_len arguments are for legacy uasyncio compatibility
def get_event_loop(runq_len=0, waitq_len=0):
return Loop
def new_event_loop():
global _task_queue, _io_queue
# TaskQueue of Task instances
_task_queue = TaskQueue()
# Task queue and poller for stream IO
_io_queue = IOQueue()
return Loop
# Initialise default event loop
new_event_loop()

31
extmod/uasyncio/event.py Normal file
View File

@ -0,0 +1,31 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
# Event class for primitive events that can be waited on, set, and cleared
class Event:
def __init__(self):
self.state = False # False=unset; True=set
self.waiting = core.TaskQueue() # Queue of Tasks waiting on completion of this event
def is_set(self):
return self.state
def set(self):
# Event becomes set, schedule any tasks waiting on it
while self.waiting.peek():
core._task_queue.push_head(self.waiting.pop_head())
self.state = True
def clear(self):
self.state = False
async def wait(self):
if not self.state:
# Event not set, put the calling task on the event's waiting queue
self.waiting.push_head(core.cur_task)
# Set calling task's data to the event's queue so it can be removed if needed
core.cur_task.data = self.waiting
yield
return True

54
extmod/uasyncio/funcs.py Normal file
View File

@ -0,0 +1,54 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
async def wait_for(aw, timeout, sleep=core.sleep):
aw = core._promote_to_task(aw)
if timeout is None:
return await aw
def cancel(aw, timeout, sleep):
await sleep(timeout)
aw.cancel()
cancel_task = core.create_task(cancel(aw, timeout, sleep))
try:
ret = await aw
except core.CancelledError:
# Ignore CancelledError from aw, it's probably due to timeout
pass
finally:
# Cancel the "cancel" task if it's still active (optimisation instead of cancel_task.cancel())
if cancel_task.coro is not None:
core._task_queue.remove(cancel_task)
if cancel_task.coro is None:
# Cancel task ran to completion, ie there was a timeout
raise core.TimeoutError
return ret
def wait_for_ms(aw, timeout):
return wait_for(aw, timeout, core.sleep_ms)
async def gather(*aws, return_exceptions=False):
ts = [core._promote_to_task(aw) for aw in aws]
for i in range(len(ts)):
try:
# TODO handle cancel of gather itself
# if ts[i].coro:
# iter(ts[i]).waiting.push_head(cur_task)
# try:
# yield
# except CancelledError as er:
# # cancel all waiting tasks
# raise er
ts[i] = await ts[i]
except Exception as er:
if return_exceptions:
ts[i] = er
else:
raise er
return ts

53
extmod/uasyncio/lock.py Normal file
View File

@ -0,0 +1,53 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
# Lock class for primitive mutex capability
class Lock:
def __init__(self):
# The state can take the following values:
# - 0: unlocked
# - 1: locked
# - <Task>: unlocked but this task has been scheduled to acquire the lock next
self.state = 0
# Queue of Tasks waiting to acquire this Lock
self.waiting = core.TaskQueue()
def locked(self):
return self.state == 1
def release(self):
if self.state != 1:
raise RuntimeError("Lock not acquired")
if self.waiting.peek():
# Task(s) waiting on lock, schedule next Task
self.state = self.waiting.pop_head()
core._task_queue.push_head(self.state)
else:
# No Task waiting so unlock
self.state = 0
async def acquire(self):
if self.state != 0:
# Lock unavailable, put the calling Task on the waiting queue
self.waiting.push_head(core.cur_task)
# Set calling task's data to the lock's queue so it can be removed if needed
core.cur_task.data = self.waiting
try:
yield
except core.CancelledError as er:
if self.state == core.cur_task:
# Cancelled while pending on resume, schedule next waiting Task
self.state = 1
self.release()
raise er
# Lock available, set it as locked
self.state = 1
return True
async def __aenter__(self):
return await self.acquire()
async def __aexit__(self, exc_type, exc, tb):
return self.release()

View File

@ -0,0 +1,13 @@
# This list of frozen files doesn't include task.py because that's provided by the C module.
freeze(
"..",
(
"uasyncio/__init__.py",
"uasyncio/core.py",
"uasyncio/event.py",
"uasyncio/funcs.py",
"uasyncio/lock.py",
"uasyncio/stream.py",
),
opt=3,
)

158
extmod/uasyncio/stream.py Normal file
View File

@ -0,0 +1,158 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
class Stream:
def __init__(self, s, e={}):
self.s = s
self.e = e
self.out_buf = b""
def get_extra_info(self, v):
return self.e[v]
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
await self.close()
def close(self):
pass
async def wait_closed(self):
# TODO yield?
self.s.close()
async def read(self, n):
yield core._io_queue.queue_read(self.s)
return self.s.read(n)
async def readexactly(self, n):
r = b""
while n:
yield core._io_queue.queue_read(self.s)
r2 = self.s.read(n)
if r2 is not None:
if not len(r2):
raise EOFError
r += r2
n -= len(r2)
return r
async def readline(self):
l = b""
while True:
yield core._io_queue.queue_read(self.s)
l2 = self.s.readline() # may do multiple reads but won't block
l += l2
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
return l
def write(self, buf):
self.out_buf += buf
async def drain(self):
mv = memoryview(self.out_buf)
off = 0
while off < len(mv):
yield core._io_queue.queue_write(self.s)
ret = self.s.write(mv[off:])
if ret is not None:
off += ret
self.out_buf = b""
# Stream can be used for both reading and writing to save code size
StreamReader = Stream
StreamWriter = Stream
# Create a TCP stream connection to a remote host
async def open_connection(host, port):
from uerrno import EINPROGRESS
import usocket as socket
ai = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
s = socket.socket()
s.setblocking(False)
ss = Stream(s)
try:
s.connect(ai[-1])
except OSError as er:
if er.args[0] != EINPROGRESS:
raise er
yield core._io_queue.queue_write(s)
return ss, ss
# Class representing a TCP stream server, can be closed and used in "async with"
class Server:
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
self.close()
await self.wait_closed()
def close(self):
self.task.cancel()
async def wait_closed(self):
await self.task
async def _serve(self, cb, host, port, backlog):
import usocket as socket
ai = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
s = socket.socket()
s.setblocking(False)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(ai[-1])
s.listen(backlog)
self.task = core.cur_task
# Accept incoming connections
while True:
try:
yield core._io_queue.queue_read(s)
except core.CancelledError:
# Shutdown server
s.close()
return
try:
s2, addr = s.accept()
except:
# Ignore a failed accept
continue
s2.setblocking(False)
s2s = Stream(s2, {"peername": addr})
core.create_task(cb(s2s, s2s))
# Helper function to start a TCP stream server, running as a new task
# TODO could use an accept-callback on socket read activity instead of creating a task
async def start_server(cb, host, port, backlog=5):
s = Server()
core.create_task(s._serve(cb, host, port, backlog))
return s
################################################################################
# Legacy uasyncio compatibility
async def stream_awrite(self, buf, off=0, sz=-1):
if off != 0 or sz != -1:
buf = memoryview(buf)
if sz == -1:
sz = len(buf)
buf = buf[off : off + sz]
self.write(buf)
await self.drain()
Stream.aclose = Stream.wait_closed
Stream.awrite = stream_awrite
Stream.awritestr = stream_awrite # TODO explicitly convert to bytes?

168
extmod/uasyncio/task.py Normal file
View File

@ -0,0 +1,168 @@
# MicroPython uasyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
# This file contains the core TaskQueue based on a pairing heap, and the core Task class.
# They can optionally be replaced by C implementations.
from . import core
# pairing-heap meld of 2 heaps; O(1)
def ph_meld(h1, h2):
if h1 is None:
return h2
if h2 is None:
return h1
lt = core.ticks_diff(h1.ph_key, h2.ph_key) < 0
if lt:
if h1.ph_child is None:
h1.ph_child = h2
else:
h1.ph_child_last.ph_next = h2
h1.ph_child_last = h2
h2.ph_next = None
h2.ph_rightmost_parent = h1
return h1
else:
h1.ph_next = h2.ph_child
h2.ph_child = h1
if h1.ph_next is None:
h2.ph_child_last = h1
h1.ph_rightmost_parent = h2
return h2
# pairing-heap pairing operation; amortised O(log N)
def ph_pairing(child):
heap = None
while child is not None:
n1 = child
child = child.ph_next
n1.ph_next = None
if child is not None:
n2 = child
child = child.ph_next
n2.ph_next = None
n1 = ph_meld(n1, n2)
heap = ph_meld(heap, n1)
return heap
# pairing-heap delete of a node; stable, amortised O(log N)
def ph_delete(heap, node):
if node is heap:
child = heap.ph_child
node.ph_child = None
return ph_pairing(child)
# Find parent of node
parent = node
while parent.ph_next is not None:
parent = parent.ph_next
parent = parent.ph_rightmost_parent
# Replace node with pairing of its children
if node is parent.ph_child and node.ph_child is None:
parent.ph_child = node.ph_next
node.ph_next = None
return heap
elif node is parent.ph_child:
child = node.ph_child
next = node.ph_next
node.ph_child = None
node.ph_next = None
node = ph_pairing(child)
parent.ph_child = node
else:
n = parent.ph_child
while node is not n.ph_next:
n = n.ph_next
child = node.ph_child
next = node.ph_next
node.ph_child = None
node.ph_next = None
node = ph_pairing(child)
if node is None:
node = n
else:
n.ph_next = node
node.ph_next = next
if next is None:
node.ph_rightmost_parent = parent
parent.ph_child_last = node
return heap
# TaskQueue class based on the above pairing-heap functions.
class TaskQueue:
def __init__(self):
self.heap = None
def peek(self):
return self.heap
def push_sorted(self, v, key):
v.data = None
v.ph_key = key
v.ph_child = None
v.ph_next = None
self.heap = ph_meld(v, self.heap)
def push_head(self, v):
self.push_sorted(v, core.ticks())
def pop_head(self):
v = self.heap
self.heap = ph_pairing(self.heap.ph_child)
return v
def remove(self, v):
self.heap = ph_delete(self.heap, v)
# Task class representing a coroutine, can be waited on and cancelled.
class Task:
def __init__(self, coro, globals=None):
self.coro = coro # Coroutine of this Task
self.data = None # General data for queue it is waiting on
self.ph_key = 0 # Pairing heap
self.ph_child = None # Paring heap
self.ph_child_last = None # Paring heap
self.ph_next = None # Paring heap
self.ph_rightmost_parent = None # Paring heap
def __iter__(self):
if not hasattr(self, "waiting"):
# Lazily allocated head of linked list of Tasks waiting on completion of this task.
self.waiting = TaskQueue()
return self
def __next__(self):
if not self.coro:
# Task finished, raise return value to caller so it can continue.
raise self.data
else:
# Put calling task on waiting queue.
self.waiting.push_head(core.cur_task)
# Set calling task's data to this task that it waits on, to double-link it.
core.cur_task.data = self
def cancel(self):
# Check if task is already finished.
if self.coro is None:
return False
# Can't cancel self (not supported yet).
if self is core.cur_task:
raise RuntimeError("can't cancel self")
# If Task waits on another task then forward the cancel to the one it's waiting on.
while isinstance(self.data, Task):
self = self.data
# Reschedule Task as a cancelled task.
if hasattr(self.data, "remove"):
# Not on the main running queue, remove the task from the queue it's on.
self.data.remove(self)
core._task_queue.push_head(self)
elif core.ticks_diff(self.ph_key, core.ticks()) > 0:
# On the main running queue but scheduled in the future, so bring it forward to now.
core._task_queue.remove(self)
core._task_queue.push_head(self)
self.data = core.CancelledError
return True

View File

@ -181,8 +181,8 @@ STATIC mp_obj_t mp_vfs_autodetect(mp_obj_t bdev_obj) {
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_readonly, ARG_mkfs }; enum { ARG_readonly, ARG_mkfs };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} },
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} }, { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} },
}; };
// parse args // parse args
@ -277,10 +277,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount);
mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_file, ARG_mode, ARG_encoding }; enum { ARG_file, ARG_mode, ARG_encoding };
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
{ MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
}; };
// parse args // parse args
@ -302,7 +302,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open);
mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
mp_obj_t path_out; mp_obj_t path_out;
mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);
MP_STATE_VM(vfs_cur) = vfs;
if (vfs == MP_VFS_ROOT) { if (vfs == MP_VFS_ROOT) {
// If we change to the root dir and a VFS is mounted at the root then // If we change to the root dir and a VFS is mounted at the root then
// we must change that VFS's current dir to the root dir so that any // we must change that VFS's current dir to the root dir so that any
@ -314,9 +313,11 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
break; break;
} }
} }
vfs = MP_VFS_ROOT;
} else { } else {
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out); mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out);
} }
MP_STATE_VM(vfs_cur) = vfs;
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir); MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir);
@ -493,4 +494,25 @@ mp_obj_t mp_vfs_statvfs(mp_obj_t path_in) {
} }
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs); MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs);
// This is a C-level helper function for ports to use if needed.
int mp_vfs_mount_and_chdir_protected(mp_obj_t bdev, mp_obj_t mount_point) {
nlr_buf_t nlr;
mp_int_t ret = -MP_EIO;
if (nlr_push(&nlr) == 0) {
mp_obj_t args[] = { bdev, mount_point };
mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map);
mp_vfs_chdir(mount_point);
ret = 0; // success
nlr_pop();
} else {
mp_obj_base_t *exc = nlr.ret_val;
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
mp_obj_get_int_maybe(v, &ret); // get errno value
ret = -ret;
}
}
return ret;
}
#endif // MICROPY_VFS #endif // MICROPY_VFS

View File

@ -101,6 +101,7 @@ mp_obj_t mp_vfs_rmdir(mp_obj_t path_in);
mp_obj_t mp_vfs_stat(mp_obj_t path_in); mp_obj_t mp_vfs_stat(mp_obj_t path_in);
mp_obj_t mp_vfs_statvfs(mp_obj_t path_in); mp_obj_t mp_vfs_statvfs(mp_obj_t path_in);
int mp_vfs_mount_and_chdir_protected(mp_obj_t bdev, mp_obj_t mount_point);
mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in); mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in);
MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj); MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj);

View File

@ -12,6 +12,7 @@
#endif #endif
#include <string.h> #include <string.h>
#include "py/obj.h"
#include "py/objproperty.h" #include "py/objproperty.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mperrno.h" #include "py/mperrno.h"
@ -340,9 +341,9 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size
t->items[7] = seconds; // st_atime t->items[7] = seconds; // st_atime
t->items[8] = seconds; // st_mtime t->items[8] = seconds; // st_mtime
t->items[9] = seconds; // st_ctime t->items[9] = seconds; // st_ctime
return MP_OBJ_FROM_PTR(t); return MP_OBJ_FROM_PTR(t);
} }
@ -440,7 +441,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
.base.type = &mp_type_property, .base.type = &mp_type_property,
.proxy = {(mp_obj_t)&fat_vfs_getlabel_obj, .proxy = {(mp_obj_t)&fat_vfs_getlabel_obj,
(mp_obj_t)&fat_vfs_setlabel_obj, (mp_obj_t)&fat_vfs_setlabel_obj,
(mp_obj_t)&mp_const_none_obj}, MP_ROM_NONE},
}; };
#endif #endif

View File

@ -130,9 +130,9 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO, // Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor // but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor
STATIC const mp_arg_t file_open_args[] = { STATIC const mp_arg_t file_open_args[] = {
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },
{ MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
}; };
#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) #define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2019 Damien P. George * Copyright (c) 2019-2020 Damien P. George
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,18 +25,20 @@
*/ */
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mphal.h"
#include "extmod/vfs.h" #include "extmod/vfs.h"
#include "extmod/vfs_lfs.h" #include "extmod/vfs_lfs.h"
#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2) #if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead }; enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime };
static const mp_arg_t lfs_make_allowed_args[] = { static const mp_arg_t lfs_make_allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} }, { MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
{ MP_QSTR_mtime, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
}; };
#if MICROPY_VFS_LFS1 #if MICROPY_VFS_LFS1
@ -98,9 +100,13 @@ mp_obj_t mp_vfs_lfs1_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode
#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2 #define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2
#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2##s #define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2##s
// Attribute ids for lfs2_attr.type.
#define LFS_ATTR_MTIME (1) // 64-bit little endian, nanoseconds since 1970/1/1
typedef struct _mp_obj_vfs_lfs2_t { typedef struct _mp_obj_vfs_lfs2_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_vfs_blockdev_t blockdev; mp_vfs_blockdev_t blockdev;
bool enable_mtime;
vstr_t cur_dir; vstr_t cur_dir;
struct lfs2_config config; struct lfs2_config config;
lfs2_t lfs; lfs2_t lfs;
@ -109,14 +115,25 @@ typedef struct _mp_obj_vfs_lfs2_t {
typedef struct _mp_obj_vfs_lfs2_file_t { typedef struct _mp_obj_vfs_lfs2_file_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_obj_vfs_lfs2_t *vfs; mp_obj_vfs_lfs2_t *vfs;
uint8_t mtime[8];
lfs2_file_t file; lfs2_file_t file;
struct lfs2_file_config cfg; struct lfs2_file_config cfg;
struct lfs2_attr attrs[1];
uint8_t file_buffer[0]; uint8_t file_buffer[0];
} mp_obj_vfs_lfs2_file_t; } mp_obj_vfs_lfs2_file_t;
const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in); const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in);
mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in); mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in);
STATIC void lfs_get_mtime(uint8_t buf[8]) {
uint64_t ns = mp_hal_time_ns();
// Store "ns" to "buf" in little-endian format (essentially htole64).
for (size_t i = 0; i < 8; ++i) {
buf[i] = ns;
ns >>= 8;
}
}
#include "extmod/vfs_lfsx.c" #include "extmod/vfs_lfsx.c"
#include "extmod/vfs_lfsx_file.c" #include "extmod/vfs_lfsx_file.c"

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2019 Damien P. George * Copyright (c) 2019-2020 Damien P. George
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -31,8 +31,10 @@
#include "py/stream.h" #include "py/stream.h"
#include "py/binary.h" #include "py/binary.h"
#include "py/objarray.h" #include "py/objarray.h"
#include "py/objstr.h"
#include "py/mperrno.h" #include "py/mperrno.h"
#include "extmod/vfs.h" #include "extmod/vfs.h"
#include "lib/timeutils/timeutils.h"
STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) { STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg); mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
@ -119,6 +121,9 @@ STATIC mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t * type, size_t n_args,
self->base.type = type; self->base.type = type;
vstr_init(&self->cur_dir, 16); vstr_init(&self->cur_dir, 16);
vstr_add_byte(&self->cur_dir, '/'); vstr_add_byte(&self->cur_dir, '/');
#if LFS_BUILD_VERSION == 2
self->enable_mtime = args[LFS_MAKE_ARG_mtime].u_bool;
#endif
MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj, MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int); args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
int ret = LFSx_API(mount)(&self->lfs, &self->config); int ret = LFSx_API(mount)(&self->lfs, &self->config);
@ -236,10 +241,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(rmdir_obj), MP_VFS_LFSx(rmdir));
STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) { STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) {
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in); const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in);
const char *path = mp_obj_str_get_str(path_new_in);
vstr_t path_new; vstr_t path_new;
vstr_init(&path_new, vstr_len(&self->cur_dir)); vstr_init(&path_new, vstr_len(&self->cur_dir));
vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir)); if (path[0] != '/') {
vstr_add_str(&path_new, mp_obj_str_get_str(path_new_in)); vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir));
}
vstr_add_str(&path_new, path);
int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new)); int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new));
vstr_clear(&path_new); vstr_clear(&path_new);
if (ret < 0) { if (ret < 0) {
@ -283,8 +291,45 @@ STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
} }
// If not at root add trailing / to make it easy to build paths // If not at root add trailing / to make it easy to build paths
// and then normalise the path
if (vstr_len(&self->cur_dir) != 1) { if (vstr_len(&self->cur_dir) != 1) {
vstr_add_byte(&self->cur_dir, '/'); vstr_add_byte(&self->cur_dir, '/');
#define CWD_LEN (vstr_len(&self->cur_dir))
size_t to = 1;
size_t from = 1;
char *cwd = vstr_str(&self->cur_dir);
while (from < CWD_LEN) {
for (; cwd[from] == '/' && from < CWD_LEN; ++from) {
// Scan for the start
}
if (from > to) {
// Found excessive slash chars, squeeze them out
vstr_cut_out_bytes(&self->cur_dir, to, from - to);
from = to;
}
for (; cwd[from] != '/' && from < CWD_LEN; ++from) {
// Scan for the next /
}
if ((from - to) == 1 && cwd[to] == '.') {
// './', ignore
vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
from = to;
} else if ((from - to) == 2 && cwd[to] == '.' && cwd[to + 1] == '.') {
// '../', skip back
if (to > 1) {
// Only skip back if not at the tip
for (--to; to > 1 && cwd[to - 1] != '/'; --to) {
// Skip back
}
}
vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
from = to;
} else {
// Normal element, keep it and just move the offset
to = ++from;
}
}
} }
return mp_const_none; return mp_const_none;
@ -304,13 +349,29 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(getcwd_obj), MP_VFS_LFSx(getcwd));
STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in); MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
const char *path = mp_obj_str_get_str(path_in); const char *path = MP_VFS_LFSx(make_path)(self, path_in);
struct LFSx_API (info) info; struct LFSx_API (info) info;
int ret = LFSx_API(stat)(&self->lfs, path, &info); int ret = LFSx_API(stat)(&self->lfs, path, &info);
if (ret < 0) { if (ret < 0) {
mp_raise_OSError(-ret); mp_raise_OSError(-ret);
} }
mp_uint_t mtime = 0;
#if LFS_BUILD_VERSION == 2
uint8_t mtime_buf[8];
lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
if (sz == sizeof(mtime_buf)) {
uint64_t ns = 0;
for (size_t i = sizeof(mtime_buf); i > 0; --i) {
ns = ns << 8 | mtime_buf[i - 1];
}
mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns);
#if MICROPY_EPOCH_IS_1970
mtime += TIMEUTILS_SECONDS_1970_TO_2000;
#endif
}
#endif
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
@ -319,9 +380,9 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
return MP_OBJ_FROM_PTR(t); return MP_OBJ_FROM_PTR(t);
} }
@ -400,6 +461,8 @@ STATIC MP_DEFINE_CONST_DICT(MP_VFS_LFSx(locals_dict), MP_VFS_LFSx(locals_dict_ta
STATIC mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) { STATIC mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) {
MP_OBJ_VFS_LFSx *self = self_in; MP_OBJ_VFS_LFSx *self = self_in;
struct LFSx_API (info) info; struct LFSx_API (info) info;
mp_obj_str_t path_obj = { { &mp_type_str }, 0, 0, (const byte *)path };
path = MP_VFS_LFSx(make_path)(self, MP_OBJ_FROM_PTR(&path_obj));
int ret = LFSx_API(stat)(&self->lfs, path, &info); int ret = LFSx_API(stat)(&self->lfs, path, &info);
if (ret == 0) { if (ret == 0) {
if (info.type == LFSx_MACRO(_TYPE_REG)) { if (info.type == LFSx_MACRO(_TYPE_REG)) {

View File

@ -3,7 +3,7 @@
* *
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2019 Damien P. George * Copyright (c) 2019-2020 Damien P. George
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -101,6 +101,17 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod
#endif #endif
o->cfg.buffer = &o->file_buffer[0]; o->cfg.buffer = &o->file_buffer[0];
#if LFS_BUILD_VERSION == 2
if (self->enable_mtime) {
lfs_get_mtime(&o->mtime[0]);
o->attrs[0].type = LFS_ATTR_MTIME;
o->attrs[0].buffer = &o->mtime[0];
o->attrs[0].size = sizeof(o->mtime);
o->cfg.attrs = &o->attrs[0];
o->cfg.attr_count = MP_ARRAY_SIZE(o->attrs);
}
#endif
const char *path = MP_VFS_LFSx(make_path)(self, path_in); const char *path = MP_VFS_LFSx(make_path)(self, path_in);
int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg); int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg);
if (ret < 0) { if (ret < 0) {
@ -131,6 +142,11 @@ STATIC mp_uint_t MP_VFS_LFSx(file_read)(mp_obj_t self_in, void *buf, mp_uint_t s
STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in); MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
MP_VFS_LFSx(check_open)(self); MP_VFS_LFSx(check_open)(self);
#if LFS_BUILD_VERSION == 2
if (self->vfs->enable_mtime) {
lfs_get_mtime(&self->mtime[0]);
}
#endif
LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size); LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size);
if (sz < 0) { if (sz < 0) {
*errcode = -sz; *errcode = -sz;

View File

@ -5,6 +5,8 @@
#include "py/runtime.h" #include "py/runtime.h"
#include "py/mperrno.h" #include "py/mperrno.h"
#include "py/mphal.h"
#include "py/mpthread.h"
#include "extmod/vfs.h" #include "extmod/vfs.h"
#include "extmod/vfs_posix.h" #include "extmod/vfs_posix.h"
@ -149,12 +151,15 @@ STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {
} }
for (;;) { for (;;) {
MP_THREAD_GIL_EXIT();
struct dirent *dirent = readdir(self->dir); struct dirent *dirent = readdir(self->dir);
if (dirent == NULL) { if (dirent == NULL) {
closedir(self->dir); closedir(self->dir);
MP_THREAD_GIL_ENTER();
self->dir = NULL; self->dir = NULL;
return MP_OBJ_STOP_ITERATION; return MP_OBJ_STOP_ITERATION;
} }
MP_THREAD_GIL_ENTER();
const char *fn = dirent->d_name; const char *fn = dirent->d_name;
if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) { if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
@ -208,7 +213,9 @@ STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
if (path[0] == '\0') { if (path[0] == '\0') {
path = "."; path = ".";
} }
MP_THREAD_GIL_EXIT();
iter->dir = opendir(path); iter->dir = opendir(path);
MP_THREAD_GIL_ENTER();
if (iter->dir == NULL) { if (iter->dir == NULL) {
mp_raise_OSError(errno); mp_raise_OSError(errno);
} }
@ -224,7 +231,10 @@ typedef struct _mp_obj_listdir_t {
STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777); const char *path = vfs_posix_get_path_str(self, path_in);
MP_THREAD_GIL_EXIT();
int ret = mkdir(path, 0777);
MP_THREAD_GIL_ENTER();
if (ret != 0) { if (ret != 0) {
mp_raise_OSError(errno); mp_raise_OSError(errno);
} }
@ -241,7 +251,9 @@ STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
const char *old_path = vfs_posix_get_path_str(self, old_path_in); const char *old_path = vfs_posix_get_path_str(self, old_path_in);
const char *new_path = vfs_posix_get_path_str(self, new_path_in); const char *new_path = vfs_posix_get_path_str(self, new_path_in);
MP_THREAD_GIL_EXIT();
int ret = rename(old_path, new_path); int ret = rename(old_path, new_path);
MP_THREAD_GIL_ENTER();
if (ret != 0) { if (ret != 0) {
mp_raise_OSError(errno); mp_raise_OSError(errno);
} }
@ -257,21 +269,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);
STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) { STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
struct stat sb; struct stat sb;
int ret = stat(vfs_posix_get_path_str(self, path_in), &sb); const char *path = vfs_posix_get_path_str(self, path_in);
if (ret != 0) { int ret;
mp_raise_OSError(errno); MP_HAL_RETRY_SYSCALL(ret, stat(path, &sb), mp_raise_OSError(err));
}
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino); t->items[1] = mp_obj_new_int_from_uint(sb.st_ino);
t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev); t->items[2] = mp_obj_new_int_from_uint(sb.st_dev);
t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink); t->items[3] = mp_obj_new_int_from_uint(sb.st_nlink);
t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid); t->items[4] = mp_obj_new_int_from_uint(sb.st_uid);
t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid); t->items[5] = mp_obj_new_int_from_uint(sb.st_gid);
t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size); t->items[6] = mp_obj_new_int_from_uint(sb.st_size);
t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime); t->items[7] = mp_obj_new_int_from_uint(sb.st_atime);
t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime); t->items[8] = mp_obj_new_int_from_uint(sb.st_mtime);
t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime); t->items[9] = mp_obj_new_int_from_uint(sb.st_ctime);
return MP_OBJ_FROM_PTR(t); return MP_OBJ_FROM_PTR(t);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat); STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
@ -300,10 +311,8 @@ STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
STRUCT_STATVFS sb; STRUCT_STATVFS sb;
const char *path = vfs_posix_get_path_str(self, path_in); const char *path = vfs_posix_get_path_str(self, path_in);
int ret = STATVFS(path, &sb); int ret;
if (ret != 0) { MP_HAL_RETRY_SYSCALL(ret, STATVFS(path, &sb), mp_raise_OSError(err));
mp_raise_OSError(errno);
}
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize); t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize); t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);

View File

@ -3,14 +3,17 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "py/mphal.h"
#include "py/mpthread.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/stream.h" #include "py/stream.h"
#include "extmod/vfs_posix.h" #include "extmod/vfs_posix.h"
#include "supervisor/shared/translate.h" #include "supervisor/shared/translate.h"
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX #if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#ifdef _WIN32 #ifdef _WIN32
#define fsync _commit #define fsync _commit
@ -24,7 +27,7 @@ typedef struct _mp_obj_vfs_posix_file_t {
#ifdef MICROPY_CPYTHON_COMPAT #ifdef MICROPY_CPYTHON_COMPAT
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
if (o->fd < 0) { if (o->fd < 0) {
mp_raise_ValueError(translate("I/O operation on closed file")); mp_raise_ValueError(MP_ERROR_TEXT("I/O operation on closed file"));
} }
} }
#else #else
@ -80,17 +83,15 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_
} }
const char *fname = mp_obj_str_get_str(fid); const char *fname = mp_obj_str_get_str(fid);
int fd = open(fname, mode_x | mode_rw, 0644); int fd;
if (fd == -1) { MP_HAL_RETRY_SYSCALL(fd, open(fname, mode_x | mode_rw, 0644), mp_raise_OSError(err));
mp_raise_OSError(errno);
}
o->fd = fd; o->fd = fd;
return MP_OBJ_FROM_PTR(o); return MP_OBJ_FROM_PTR(o);
} }
STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
}; };
@ -115,46 +116,49 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vf
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o); check_fd_is_open(o);
mp_int_t r = read(o->fd, buf, size); ssize_t r;
if (r == -1) { MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
*errcode = errno; *errcode = err;
return MP_STREAM_ERROR; return MP_STREAM_ERROR;
} });
return r; return (mp_uint_t)r;
} }
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o); check_fd_is_open(o);
mp_int_t r = write(o->fd, buf, size); ssize_t r;
while (r == -1 && errno == EINTR) { MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { *errcode = err;
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
}
r = write(o->fd, buf, size);
}
if (r == -1) {
*errcode = errno;
return MP_STREAM_ERROR; return MP_STREAM_ERROR;
} });
return r; return (mp_uint_t)r;
} }
STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) { STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o); check_fd_is_open(o);
switch (request) { switch (request) {
case MP_STREAM_FLUSH: case MP_STREAM_FLUSH: {
if (fsync(o->fd) < 0) { int ret;
*errcode = errno; MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), {
if (err == EINVAL
&& (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) {
// fsync(stdin/stdout/stderr) may fail with EINVAL, but don't propagate that
// error out. Because data is not buffered by us, and stdin/out/err.flush()
// should just be a no-op.
return 0;
}
*errcode = err;
return MP_STREAM_ERROR; return MP_STREAM_ERROR;
} });
return 0; return 0;
}
case MP_STREAM_SEEK: { case MP_STREAM_SEEK: {
struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg; struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
MP_THREAD_GIL_EXIT();
off_t off = lseek(o->fd, s->offset, s->whence); off_t off = lseek(o->fd, s->offset, s->whence);
MP_THREAD_GIL_ENTER();
if (off == (off_t)-1) { if (off == (off_t)-1) {
*errcode = errno; *errcode = errno;
return MP_STREAM_ERROR; return MP_STREAM_ERROR;
@ -163,11 +167,15 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
return 0; return 0;
} }
case MP_STREAM_CLOSE: case MP_STREAM_CLOSE:
MP_THREAD_GIL_EXIT();
close(o->fd); close(o->fd);
MP_THREAD_GIL_ENTER();
#ifdef MICROPY_CPYTHON_COMPAT #ifdef MICROPY_CPYTHON_COMPAT
o->fd = -1; o->fd = -1;
#endif #endif
return 0; return 0;
case MP_STREAM_GET_FILENO:
return o->fd;
default: default:
*errcode = EINVAL; *errcode = EINVAL;
return MP_STREAM_ERROR; return MP_STREAM_ERROR;
@ -234,4 +242,4 @@ const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILEN
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO}; const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO}; const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
#endif // MICROPY_VFS_POSIX #endif // MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE

View File

@ -50,8 +50,11 @@ STATIC void mp_reader_vfs_close(void *data) {
void mp_reader_new_file(mp_reader_t *reader, const char *filename) { void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); mp_obj_t args[2] = {
rf->file = mp_vfs_open(1, &arg, (mp_map_t *)&mp_const_empty_map); mp_obj_new_str(filename, strlen(filename)),
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
};
rf->file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
int errcode; int errcode;
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
if (errcode != 0) { if (errcode != 0) {

13
lib/embed/__errno.c Normal file
View File

@ -0,0 +1,13 @@
// This file provides a version of __errno() for embedded systems that do not have one.
// This function is needed for expressions of the form: &errno
static int embed_errno;
#if defined(__linux__)
int *__errno_location(void)
#else
int *__errno(void)
#endif
{
return &embed_errno;
}

View File

@ -5,5 +5,5 @@
NORETURN void abort_(void); NORETURN void abort_(void);
NORETURN void abort_(void) { NORETURN void abort_(void) {
mp_raise_msg(&mp_type_RuntimeError, translate("abort() called")); mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("abort() called"));
} }

View File

@ -173,6 +173,25 @@ char *strcpy(char *dest, const char *src) {
return dest; return dest;
} }
// Public Domain implementation of strncpy from:
// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strncpy_function
char *strncpy(char *s1, const char *s2, size_t n) {
char *dst = s1;
const char *src = s2;
/* Copy bytes, one at a time. */
while (n > 0) {
n--;
if ((*dst++ = *src++) == '\0') {
/* If we get here, we found a null character at the end
of s2, so use memset to put null bytes at the end of
s1. */
memset(dst, '\0', n);
break;
}
}
return s1;
}
// needed because gcc optimises strcpy + strcat to this // needed because gcc optimises strcpy + strcat to this
char *stpcpy(char *dest, const char *src) { char *stpcpy(char *dest, const char *src) {
while (*src) { while (*src) {

View File

@ -23,15 +23,15 @@
// dpgeorge: pio2 was double in original implementation of asinf // dpgeorge: pio2 was double in original implementation of asinf
static const float static const float
pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ pio2_hi = 1.5707962513e+00f, /* 0x3fc90fda */
pio2_lo = 7.5497894159e-08; /* 0x33a22168 */ pio2_lo = 7.5497894159e-08f; /* 0x33a22168 */
static const float static const float
/* coefficients for R(x^2) */ /* coefficients for R(x^2) */
pS0 = 1.6666586697e-01, pS0 = 1.6666586697e-01f,
pS1 = -4.2743422091e-02, pS1 = -4.2743422091e-02f,
pS2 = -8.6563630030e-03, pS2 = -8.6563630030e-03f,
qS1 = -7.0662963390e-01; qS1 = -7.0662963390e-01f;
static float R(float z) static float R(float z)
{ {

View File

@ -22,8 +22,8 @@
#include "libm.h" #include "libm.h"
static const float static const float
pi = 3.1415927410e+00, /* 0x40490fdb */ pi = 3.1415927410e+00f, /* 0x40490fdb */
pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */ pi_lo = -8.7422776573e-08f; /* 0xb3bbbd2e */
float atan2f(float y, float x) float atan2f(float y, float x)
{ {

View File

@ -23,25 +23,25 @@
#include "libm.h" #include "libm.h"
static const float atanhi[] = { static const float atanhi[] = {
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */ 4.6364760399e-01f, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */ 7.8539812565e-01f, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */ 9.8279368877e-01f, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */ 1.5707962513e+00f, /* atan(inf)hi 0x3fc90fda */
}; };
static const float atanlo[] = { static const float atanlo[] = {
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */ 5.0121582440e-09f, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */ 3.7748947079e-08f, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */ 3.4473217170e-08f, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */ 7.5497894159e-08f, /* atan(inf)lo 0x33a22168 */
}; };
static const float aT[] = { static const float aT[] = {
3.3333328366e-01, 3.3333328366e-01f,
-1.9999158382e-01, -1.9999158382e-01f,
1.4253635705e-01, 1.4253635705e-01f,
-1.0648017377e-01, -1.0648017377e-01f,
6.1687607318e-02, 6.1687607318e-02f,
}; };
float atanf(float x) float atanf(float x)

View File

@ -93,16 +93,16 @@ static const float
#else #else
static float static float
#endif #endif
zero = 0.0000000000e+00, /* 0x00000000 */ zero = 0.0000000000e+00f, /* 0x00000000 */
half = 5.0000000000e-01, /* 0x3f000000 */ half = 5.0000000000e-01f, /* 0x3f000000 */
two8 = 2.5600000000e+02, /* 0x43800000 */ two8 = 2.5600000000e+02f, /* 0x43800000 */
invpio2 = 6.3661980629e-01, /* 0x3f22f984 */ invpio2 = 6.3661980629e-01f, /* 0x3f22f984 */
pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */ pio2_1 = 1.5707855225e+00f, /* 0x3fc90f80 */
pio2_1t = 1.0804334124e-05, /* 0x37354443 */ pio2_1t = 1.0804334124e-05f, /* 0x37354443 */
pio2_2 = 1.0804273188e-05, /* 0x37354400 */ pio2_2 = 1.0804273188e-05f, /* 0x37354400 */
pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */ pio2_2t = 6.0770999344e-11f, /* 0x2e85a308 */
pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */ pio2_3 = 6.0770943833e-11f, /* 0x2e85a300 */
pio2_3t = 6.1232342629e-17; /* 0x248d3132 */ pio2_3t = 6.1232342629e-17f; /* 0x248d3132 */
#ifdef __STDC__ #ifdef __STDC__
__int32_t __ieee754_rem_pio2f(float x, float *y) __int32_t __ieee754_rem_pio2f(float x, float *y)

View File

@ -25,9 +25,9 @@
#include "fdlibm.h" #include "fdlibm.h"
#ifdef __STDC__ #ifdef __STDC__
static const float one = 1.0, tiny=1.0e-30; static const float one = 1.0f, tiny=1.0e-30f;
#else #else
static float one = 1.0, tiny=1.0e-30; static float one = 1.0f, tiny=1.0e-30f;
#endif #endif
// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined // sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined

View File

@ -33,77 +33,77 @@ static const float
#else #else
static float static float
#endif #endif
two23= 8.3886080000e+06, /* 0x4b000000 */ two23= 8.3886080000e+06f, /* 0x4b000000 */
half= 5.0000000000e-01, /* 0x3f000000 */ half= 5.0000000000e-01f, /* 0x3f000000 */
one = 1.0000000000e+00, /* 0x3f800000 */ one = 1.0000000000e+00f, /* 0x3f800000 */
pi = 3.1415927410e+00, /* 0x40490fdb */ pi = 3.1415927410e+00f, /* 0x40490fdb */
a0 = 7.7215664089e-02, /* 0x3d9e233f */ a0 = 7.7215664089e-02f, /* 0x3d9e233f */
a1 = 3.2246702909e-01, /* 0x3ea51a66 */ a1 = 3.2246702909e-01f, /* 0x3ea51a66 */
a2 = 6.7352302372e-02, /* 0x3d89f001 */ a2 = 6.7352302372e-02f, /* 0x3d89f001 */
a3 = 2.0580807701e-02, /* 0x3ca89915 */ a3 = 2.0580807701e-02f, /* 0x3ca89915 */
a4 = 7.3855509982e-03, /* 0x3bf2027e */ a4 = 7.3855509982e-03f, /* 0x3bf2027e */
a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ a5 = 2.8905137442e-03f, /* 0x3b3d6ec6 */
a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ a6 = 1.1927076848e-03f, /* 0x3a9c54a1 */
a7 = 5.1006977446e-04, /* 0x3a05b634 */ a7 = 5.1006977446e-04f, /* 0x3a05b634 */
a8 = 2.2086278477e-04, /* 0x39679767 */ a8 = 2.2086278477e-04f, /* 0x39679767 */
a9 = 1.0801156895e-04, /* 0x38e28445 */ a9 = 1.0801156895e-04f, /* 0x38e28445 */
a10 = 2.5214456400e-05, /* 0x37d383a2 */ a10 = 2.5214456400e-05f, /* 0x37d383a2 */
a11 = 4.4864096708e-05, /* 0x383c2c75 */ a11 = 4.4864096708e-05f, /* 0x383c2c75 */
tc = 1.4616321325e+00, /* 0x3fbb16c3 */ tc = 1.4616321325e+00f, /* 0x3fbb16c3 */
tf = -1.2148628384e-01, /* 0xbdf8cdcd */ tf = -1.2148628384e-01f, /* 0xbdf8cdcd */
/* tt = -(tail of tf) */ /* tt = -(tail of tf) */
tt = 6.6971006518e-09, /* 0x31e61c52 */ tt = 6.6971006518e-09f, /* 0x31e61c52 */
t0 = 4.8383611441e-01, /* 0x3ef7b95e */ t0 = 4.8383611441e-01f, /* 0x3ef7b95e */
t1 = -1.4758771658e-01, /* 0xbe17213c */ t1 = -1.4758771658e-01f, /* 0xbe17213c */
t2 = 6.4624942839e-02, /* 0x3d845a15 */ t2 = 6.4624942839e-02f, /* 0x3d845a15 */
t3 = -3.2788541168e-02, /* 0xbd064d47 */ t3 = -3.2788541168e-02f, /* 0xbd064d47 */
t4 = 1.7970675603e-02, /* 0x3c93373d */ t4 = 1.7970675603e-02f, /* 0x3c93373d */
t5 = -1.0314224288e-02, /* 0xbc28fcfe */ t5 = -1.0314224288e-02f, /* 0xbc28fcfe */
t6 = 6.1005386524e-03, /* 0x3bc7e707 */ t6 = 6.1005386524e-03f, /* 0x3bc7e707 */
t7 = -3.6845202558e-03, /* 0xbb7177fe */ t7 = -3.6845202558e-03f, /* 0xbb7177fe */
t8 = 2.2596477065e-03, /* 0x3b141699 */ t8 = 2.2596477065e-03f, /* 0x3b141699 */
t9 = -1.4034647029e-03, /* 0xbab7f476 */ t9 = -1.4034647029e-03f, /* 0xbab7f476 */
t10 = 8.8108185446e-04, /* 0x3a66f867 */ t10 = 8.8108185446e-04f, /* 0x3a66f867 */
t11 = -5.3859531181e-04, /* 0xba0d3085 */ t11 = -5.3859531181e-04f, /* 0xba0d3085 */
t12 = 3.1563205994e-04, /* 0x39a57b6b */ t12 = 3.1563205994e-04f, /* 0x39a57b6b */
t13 = -3.1275415677e-04, /* 0xb9a3f927 */ t13 = -3.1275415677e-04f, /* 0xb9a3f927 */
t14 = 3.3552918467e-04, /* 0x39afe9f7 */ t14 = 3.3552918467e-04f, /* 0x39afe9f7 */
u0 = -7.7215664089e-02, /* 0xbd9e233f */ u0 = -7.7215664089e-02f, /* 0xbd9e233f */
u1 = 6.3282704353e-01, /* 0x3f2200f4 */ u1 = 6.3282704353e-01f, /* 0x3f2200f4 */
u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ u2 = 1.4549225569e+00f, /* 0x3fba3ae7 */
u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ u3 = 9.7771751881e-01f, /* 0x3f7a4bb2 */
u4 = 2.2896373272e-01, /* 0x3e6a7578 */ u4 = 2.2896373272e-01f, /* 0x3e6a7578 */
u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ u5 = 1.3381091878e-02f, /* 0x3c5b3c5e */
v1 = 2.4559779167e+00, /* 0x401d2ebe */ v1 = 2.4559779167e+00f, /* 0x401d2ebe */
v2 = 2.1284897327e+00, /* 0x4008392d */ v2 = 2.1284897327e+00f, /* 0x4008392d */
v3 = 7.6928514242e-01, /* 0x3f44efdf */ v3 = 7.6928514242e-01f, /* 0x3f44efdf */
v4 = 1.0422264785e-01, /* 0x3dd572af */ v4 = 1.0422264785e-01f, /* 0x3dd572af */
v5 = 3.2170924824e-03, /* 0x3b52d5db */ v5 = 3.2170924824e-03f, /* 0x3b52d5db */
s0 = -7.7215664089e-02, /* 0xbd9e233f */ s0 = -7.7215664089e-02f, /* 0xbd9e233f */
s1 = 2.1498242021e-01, /* 0x3e5c245a */ s1 = 2.1498242021e-01f, /* 0x3e5c245a */
s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ s2 = 3.2577878237e-01f, /* 0x3ea6cc7a */
s3 = 1.4635047317e-01, /* 0x3e15dce6 */ s3 = 1.4635047317e-01f, /* 0x3e15dce6 */
s4 = 2.6642270386e-02, /* 0x3cda40e4 */ s4 = 2.6642270386e-02f, /* 0x3cda40e4 */
s5 = 1.8402845599e-03, /* 0x3af135b4 */ s5 = 1.8402845599e-03f, /* 0x3af135b4 */
s6 = 3.1947532989e-05, /* 0x3805ff67 */ s6 = 3.1947532989e-05f, /* 0x3805ff67 */
r1 = 1.3920053244e+00, /* 0x3fb22d3b */ r1 = 1.3920053244e+00f, /* 0x3fb22d3b */
r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ r2 = 7.2193557024e-01f, /* 0x3f38d0c5 */
r3 = 1.7193385959e-01, /* 0x3e300f6e */ r3 = 1.7193385959e-01f, /* 0x3e300f6e */
r4 = 1.8645919859e-02, /* 0x3c98bf54 */ r4 = 1.8645919859e-02f, /* 0x3c98bf54 */
r5 = 7.7794247773e-04, /* 0x3a4beed6 */ r5 = 7.7794247773e-04f, /* 0x3a4beed6 */
r6 = 7.3266842264e-06, /* 0x36f5d7bd */ r6 = 7.3266842264e-06f, /* 0x36f5d7bd */
w0 = 4.1893854737e-01, /* 0x3ed67f1d */ w0 = 4.1893854737e-01f, /* 0x3ed67f1d */
w1 = 8.3333335817e-02, /* 0x3daaaaab */ w1 = 8.3333335817e-02f, /* 0x3daaaaab */
w2 = -2.7777778450e-03, /* 0xbb360b61 */ w2 = -2.7777778450e-03f, /* 0xbb360b61 */
w3 = 7.9365057172e-04, /* 0x3a500cfd */ w3 = 7.9365057172e-04f, /* 0x3a500cfd */
w4 = -5.9518753551e-04, /* 0xba1c065c */ w4 = -5.9518753551e-04f, /* 0xba1c065c */
w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ w5 = 8.3633989561e-04f, /* 0x3a5b3dd2 */
w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ w6 = -1.6309292987e-03f; /* 0xbad5c4e8 */
#ifdef __STDC__ #ifdef __STDC__
static const float zero= 0.0000000000e+00; static const float zero= 0.0000000000e+00f;
#else #else
static float zero= 0.0000000000e+00; static float zero= 0.0000000000e+00f;
#endif #endif
#ifdef __STDC__ #ifdef __STDC__

View File

@ -29,13 +29,13 @@ static const float
#else #else
static float static float
#endif #endif
one = 1.0000000000e+00, /* 0x3f800000 */ one = 1.0000000000e+00f, /* 0x3f800000 */
C1 = 4.1666667908e-02, /* 0x3d2aaaab */ C1 = 4.1666667908e-02f, /* 0x3d2aaaab */
C2 = -1.3888889225e-03, /* 0xbab60b61 */ C2 = -1.3888889225e-03f, /* 0xbab60b61 */
C3 = 2.4801587642e-05, /* 0x37d00d01 */ C3 = 2.4801587642e-05f, /* 0x37d00d01 */
C4 = -2.7557314297e-07, /* 0xb493f27c */ C4 = -2.7557314297e-07f, /* 0xb493f27c */
C5 = 2.0875723372e-09, /* 0x310f74f6 */ C5 = 2.0875723372e-09f, /* 0x310f74f6 */
C6 = -1.1359647598e-11; /* 0xad47d74e */ C6 = -1.1359647598e-11f; /* 0xad47d74e */
#ifdef __STDC__ #ifdef __STDC__
float __kernel_cosf(float x, float y) float __kernel_cosf(float x, float y)

View File

@ -38,17 +38,17 @@ static const float PIo2[] = {
#else #else
static float PIo2[] = { static float PIo2[] = {
#endif #endif
1.5703125000e+00, /* 0x3fc90000 */ 1.5703125000e+00f, /* 0x3fc90000 */
4.5776367188e-04, /* 0x39f00000 */ 4.5776367188e-04f, /* 0x39f00000 */
2.5987625122e-05, /* 0x37da0000 */ 2.5987625122e-05f, /* 0x37da0000 */
7.5437128544e-08, /* 0x33a20000 */ 7.5437128544e-08f, /* 0x33a20000 */
6.0026650317e-11, /* 0x2e840000 */ 6.0026650317e-11f, /* 0x2e840000 */
7.3896444519e-13, /* 0x2b500000 */ 7.3896444519e-13f, /* 0x2b500000 */
5.3845816694e-15, /* 0x27c20000 */ 5.3845816694e-15f, /* 0x27c20000 */
5.6378512969e-18, /* 0x22d00000 */ 5.6378512969e-18f, /* 0x22d00000 */
8.3009228831e-20, /* 0x1fc40000 */ 8.3009228831e-20f, /* 0x1fc40000 */
3.2756352257e-22, /* 0x1bc60000 */ 3.2756352257e-22f, /* 0x1bc60000 */
6.3331015649e-25, /* 0x17440000 */ 6.3331015649e-25f, /* 0x17440000 */
}; };
#ifdef __STDC__ #ifdef __STDC__
@ -56,10 +56,10 @@ static const float
#else #else
static float static float
#endif #endif
zero = 0.0, zero = 0.0f,
one = 1.0, one = 1.0f,
two8 = 2.5600000000e+02, /* 0x43800000 */ two8 = 2.5600000000e+02f, /* 0x43800000 */
twon8 = 3.9062500000e-03; /* 0x3b800000 */ twon8 = 3.9062500000e-03f; /* 0x3b800000 */
#ifdef __STDC__ #ifdef __STDC__
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __uint8_t *ipio2) int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __uint8_t *ipio2)

View File

@ -29,13 +29,13 @@ static const float
#else #else
static float static float
#endif #endif
half = 5.0000000000e-01,/* 0x3f000000 */ half = 5.0000000000e-01f,/* 0x3f000000 */
S1 = -1.6666667163e-01, /* 0xbe2aaaab */ S1 = -1.6666667163e-01f, /* 0xbe2aaaab */
S2 = 8.3333337680e-03, /* 0x3c088889 */ S2 = 8.3333337680e-03f, /* 0x3c088889 */
S3 = -1.9841270114e-04, /* 0xb9500d01 */ S3 = -1.9841270114e-04f, /* 0xb9500d01 */
S4 = 2.7557314297e-06, /* 0x3638ef1b */ S4 = 2.7557314297e-06f, /* 0x3638ef1b */
S5 = -2.5050759689e-08, /* 0xb2d72f34 */ S5 = -2.5050759689e-08f, /* 0xb2d72f34 */
S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */ S6 = 1.5896910177e-10f; /* 0x2f2ec9d3 */
#ifdef __STDC__ #ifdef __STDC__
float __kernel_sinf(float x, float y, int iy) float __kernel_sinf(float x, float y, int iy)

View File

@ -28,23 +28,23 @@ static const float
#else #else
static float static float
#endif #endif
one = 1.0000000000e+00, /* 0x3f800000 */ one = 1.0000000000e+00f, /* 0x3f800000 */
pio4 = 7.8539812565e-01, /* 0x3f490fda */ pio4 = 7.8539812565e-01f, /* 0x3f490fda */
pio4lo= 3.7748947079e-08, /* 0x33222168 */ pio4lo= 3.7748947079e-08f, /* 0x33222168 */
T[] = { T[] = {
3.3333334327e-01, /* 0x3eaaaaab */ 3.3333334327e-01f, /* 0x3eaaaaab */
1.3333334029e-01, /* 0x3e088889 */ 1.3333334029e-01f, /* 0x3e088889 */
5.3968254477e-02, /* 0x3d5d0dd1 */ 5.3968254477e-02f, /* 0x3d5d0dd1 */
2.1869488060e-02, /* 0x3cb327a4 */ 2.1869488060e-02f, /* 0x3cb327a4 */
8.8632395491e-03, /* 0x3c11371f */ 8.8632395491e-03f, /* 0x3c11371f */
3.5920790397e-03, /* 0x3b6b6916 */ 3.5920790397e-03f, /* 0x3b6b6916 */
1.4562094584e-03, /* 0x3abede48 */ 1.4562094584e-03f, /* 0x3abede48 */
5.8804126456e-04, /* 0x3a1a26c8 */ 5.8804126456e-04f, /* 0x3a1a26c8 */
2.4646313977e-04, /* 0x398137b9 */ 2.4646313977e-04f, /* 0x398137b9 */
7.8179444245e-05, /* 0x38a3f445 */ 7.8179444245e-05f, /* 0x38a3f445 */
7.1407252108e-05, /* 0x3895c07a */ 7.1407252108e-05f, /* 0x3895c07a */
-1.8558637748e-05, /* 0xb79bae5f */ -1.8558637748e-05f, /* 0xb79bae5f */
2.5907305826e-05, /* 0x37d95384 */ 2.5907305826e-05f, /* 0x37d95384 */
}; };
#ifdef __STDC__ #ifdef __STDC__

View File

@ -21,13 +21,13 @@
#pragma GCC diagnostic ignored "-Wfloat-equal" #pragma GCC diagnostic ignored "-Wfloat-equal"
static const float static const float
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ /* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ Lg1 = 0xaaaaaa.0p-24f, /* 0.66666662693 */
Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ Lg2 = 0xccce13.0p-25f, /* 0.40000972152 */
Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ Lg3 = 0x91e9ee.0p-25f, /* 0.28498786688 */
Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ Lg4 = 0xf89e26.0p-26f; /* 0.24279078841 */
float log1pf(float x) float log1pf(float x)
{ {

View File

@ -53,7 +53,7 @@ float copysignf(float x, float y) {
} }
#endif #endif
static const float _M_LN10 = 2.30258509299404; // 0x40135d8e static const float _M_LN10 = 2.30258509299404f; // 0x40135d8e
float log10f(float x) { return logf(x) / (float)_M_LN10; } float log10f(float x) { return logf(x) / (float)_M_LN10; }
#undef _M_LN2 #undef _M_LN2
static const float _M_LN2 = 0.6931472; static const float _M_LN2 = 0.6931472;
@ -142,34 +142,34 @@ float scalbnf(float x, int n)
*/ */
static const float static const float
bp[] = {1.0, 1.5,}, bp[] = {1.0f, 1.5f,},
dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */ dp_h[] = { 0.0f, 5.84960938e-01f,}, /* 0x3f15c000 */
dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */ dp_l[] = { 0.0f, 1.56322085e-06f,}, /* 0x35d1cfdc */
two24 = 16777216.0, /* 0x4b800000 */ two24 = 16777216.0f, /* 0x4b800000 */
huge = 1.0e30, huge = 1.0e30f,
tiny = 1.0e-30, tiny = 1.0e-30f,
/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
L1 = 6.0000002384e-01, /* 0x3f19999a */ L1 = 6.0000002384e-01f, /* 0x3f19999a */
L2 = 4.2857143283e-01, /* 0x3edb6db7 */ L2 = 4.2857143283e-01f, /* 0x3edb6db7 */
L3 = 3.3333334327e-01, /* 0x3eaaaaab */ L3 = 3.3333334327e-01f, /* 0x3eaaaaab */
L4 = 2.7272811532e-01, /* 0x3e8ba305 */ L4 = 2.7272811532e-01f, /* 0x3e8ba305 */
L5 = 2.3066075146e-01, /* 0x3e6c3255 */ L5 = 2.3066075146e-01f, /* 0x3e6c3255 */
L6 = 2.0697501302e-01, /* 0x3e53f142 */ L6 = 2.0697501302e-01f, /* 0x3e53f142 */
P1 = 1.6666667163e-01, /* 0x3e2aaaab */ P1 = 1.6666667163e-01f, /* 0x3e2aaaab */
P2 = -2.7777778450e-03, /* 0xbb360b61 */ P2 = -2.7777778450e-03f, /* 0xbb360b61 */
P3 = 6.6137559770e-05, /* 0x388ab355 */ P3 = 6.6137559770e-05f, /* 0x388ab355 */
P4 = -1.6533901999e-06, /* 0xb5ddea0e */ P4 = -1.6533901999e-06f, /* 0xb5ddea0e */
P5 = 4.1381369442e-08, /* 0x3331bb4c */ P5 = 4.1381369442e-08f, /* 0x3331bb4c */
lg2 = 6.9314718246e-01, /* 0x3f317218 */ lg2 = 6.9314718246e-01f, /* 0x3f317218 */
lg2_h = 6.93145752e-01, /* 0x3f317200 */ lg2_h = 6.93145752e-01f, /* 0x3f317200 */
lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ lg2_l = 1.42860654e-06f, /* 0x35bfbe8c */
ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ ovt = 4.2995665694e-08f, /* -(128-log2(ovfl+.5ulp)) */
cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ cp = 9.6179670095e-01f, /* 0x3f76384f =2/(3ln2) */
cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */ cp_h = 9.6191406250e-01f, /* 0x3f764000 =12b cp */
cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */ cp_l = -1.1736857402e-04f, /* 0xb8f623c6 =tail of cp_h */
ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ ivln2 = 1.4426950216e+00f, /* 0x3fb8aa3b =1/ln2 */
ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ ivln2_h = 1.4426879883e+00f, /* 0x3fb8aa00 =16b 1/ln2*/
ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ ivln2_l = 7.0526075433e-06f; /* 0x36eca570 =1/ln2 tail*/
float powf(float x, float y) float powf(float x, float y)
{ {
@ -406,7 +406,7 @@ float powf(float x, float y)
*/ */
static const float static const float
half[2] = {0.5,-0.5}, half[2] = {0.5f,-0.5f},
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */ ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */ ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */ invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
@ -445,7 +445,7 @@ float expf(float x)
/* argument reduction */ /* argument reduction */
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
k = invln2*x + half[sign]; k = (int)(invln2*x + half[sign]);
else else
k = 1 - sign - sign; k = 1 - sign - sign;
hi = x - k*ln2hi; /* k*ln2hi is exact here */ hi = x - k*ln2hi; /* k*ln2hi is exact here */
@ -492,17 +492,17 @@ float expf(float x)
*/ */
static const float static const float
o_threshold = 8.8721679688e+01, /* 0x42b17180 */ o_threshold = 8.8721679688e+01f, /* 0x42b17180 */
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ //invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
/* /*
* Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
*/ */
Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ Q1 = -3.3333212137e-2f, /* -0x888868.0p-28 */
Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ Q2 = 1.5807170421e-3f; /* 0xcf3010.0p-33 */
float expm1f(float x) float expm1f(float x)
{ {
@ -536,7 +536,7 @@ float expm1f(float x)
k = -1; k = -1;
} }
} else { } else {
k = invln2*x + (sign ? -0.5f : 0.5f); k = (int)(invln2*x + (sign ? -0.5f : 0.5f));
t = k; t = k;
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
lo = t*ln2_lo; lo = t*ln2_lo;

View File

@ -35,79 +35,79 @@ static const float
#else #else
static float static float
#endif #endif
tiny = 1e-30, tiny = 1e-30f,
half= 5.0000000000e-01, /* 0x3F000000 */ half= 5.0000000000e-01f, /* 0x3F000000 */
one = 1.0000000000e+00, /* 0x3F800000 */ one = 1.0000000000e+00f, /* 0x3F800000 */
two = 2.0000000000e+00, /* 0x40000000 */ two = 2.0000000000e+00f, /* 0x40000000 */
/* c = (subfloat)0.84506291151 */ /* c = (subfloat)0.84506291151 */
erx = 8.4506291151e-01, /* 0x3f58560b */ erx = 8.4506291151e-01f, /* 0x3f58560b */
/* /*
* Coefficients for approximation to erf on [0,0.84375] * Coefficients for approximation to erf on [0,0.84375]
*/ */
efx = 1.2837916613e-01, /* 0x3e0375d4 */ efx = 1.2837916613e-01f, /* 0x3e0375d4 */
efx8= 1.0270333290e+00, /* 0x3f8375d4 */ efx8= 1.0270333290e+00f, /* 0x3f8375d4 */
pp0 = 1.2837916613e-01, /* 0x3e0375d4 */ pp0 = 1.2837916613e-01f, /* 0x3e0375d4 */
pp1 = -3.2504209876e-01, /* 0xbea66beb */ pp1 = -3.2504209876e-01f, /* 0xbea66beb */
pp2 = -2.8481749818e-02, /* 0xbce9528f */ pp2 = -2.8481749818e-02f, /* 0xbce9528f */
pp3 = -5.7702702470e-03, /* 0xbbbd1489 */ pp3 = -5.7702702470e-03f, /* 0xbbbd1489 */
pp4 = -2.3763017452e-05, /* 0xb7c756b1 */ pp4 = -2.3763017452e-05f, /* 0xb7c756b1 */
qq1 = 3.9791721106e-01, /* 0x3ecbbbce */ qq1 = 3.9791721106e-01f, /* 0x3ecbbbce */
qq2 = 6.5022252500e-02, /* 0x3d852a63 */ qq2 = 6.5022252500e-02f, /* 0x3d852a63 */
qq3 = 5.0813062117e-03, /* 0x3ba68116 */ qq3 = 5.0813062117e-03f, /* 0x3ba68116 */
qq4 = 1.3249473704e-04, /* 0x390aee49 */ qq4 = 1.3249473704e-04f, /* 0x390aee49 */
qq5 = -3.9602282413e-06, /* 0xb684e21a */ qq5 = -3.9602282413e-06f, /* 0xb684e21a */
/* /*
* Coefficients for approximation to erf in [0.84375,1.25] * Coefficients for approximation to erf in [0.84375,1.25]
*/ */
pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */ pa0 = -2.3621185683e-03f, /* 0xbb1acdc6 */
pa1 = 4.1485610604e-01, /* 0x3ed46805 */ pa1 = 4.1485610604e-01f, /* 0x3ed46805 */
pa2 = -3.7220788002e-01, /* 0xbebe9208 */ pa2 = -3.7220788002e-01f, /* 0xbebe9208 */
pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */ pa3 = 3.1834661961e-01f, /* 0x3ea2fe54 */
pa4 = -1.1089469492e-01, /* 0xbde31cc2 */ pa4 = -1.1089469492e-01f, /* 0xbde31cc2 */
pa5 = 3.5478305072e-02, /* 0x3d1151b3 */ pa5 = 3.5478305072e-02f, /* 0x3d1151b3 */
pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */ pa6 = -2.1663755178e-03f, /* 0xbb0df9c0 */
qa1 = 1.0642088205e-01, /* 0x3dd9f331 */ qa1 = 1.0642088205e-01f, /* 0x3dd9f331 */
qa2 = 5.4039794207e-01, /* 0x3f0a5785 */ qa2 = 5.4039794207e-01f, /* 0x3f0a5785 */
qa3 = 7.1828655899e-02, /* 0x3d931ae7 */ qa3 = 7.1828655899e-02f, /* 0x3d931ae7 */
qa4 = 1.2617121637e-01, /* 0x3e013307 */ qa4 = 1.2617121637e-01f, /* 0x3e013307 */
qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */ qa5 = 1.3637083583e-02f, /* 0x3c5f6e13 */
qa6 = 1.1984500103e-02, /* 0x3c445aa3 */ qa6 = 1.1984500103e-02f, /* 0x3c445aa3 */
/* /*
* Coefficients for approximation to erfc in [1.25,1/0.35] * Coefficients for approximation to erfc in [1.25,1/0.35]
*/ */
ra0 = -9.8649440333e-03, /* 0xbc21a093 */ ra0 = -9.8649440333e-03f, /* 0xbc21a093 */
ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */ ra1 = -6.9385856390e-01f, /* 0xbf31a0b7 */
ra2 = -1.0558626175e+01, /* 0xc128f022 */ ra2 = -1.0558626175e+01f, /* 0xc128f022 */
ra3 = -6.2375331879e+01, /* 0xc2798057 */ ra3 = -6.2375331879e+01f, /* 0xc2798057 */
ra4 = -1.6239666748e+02, /* 0xc322658c */ ra4 = -1.6239666748e+02f, /* 0xc322658c */
ra5 = -1.8460508728e+02, /* 0xc3389ae7 */ ra5 = -1.8460508728e+02f, /* 0xc3389ae7 */
ra6 = -8.1287437439e+01, /* 0xc2a2932b */ ra6 = -8.1287437439e+01f, /* 0xc2a2932b */
ra7 = -9.8143291473e+00, /* 0xc11d077e */ ra7 = -9.8143291473e+00f, /* 0xc11d077e */
sa1 = 1.9651271820e+01, /* 0x419d35ce */ sa1 = 1.9651271820e+01f, /* 0x419d35ce */
sa2 = 1.3765776062e+02, /* 0x4309a863 */ sa2 = 1.3765776062e+02f, /* 0x4309a863 */
sa3 = 4.3456588745e+02, /* 0x43d9486f */ sa3 = 4.3456588745e+02f, /* 0x43d9486f */
sa4 = 6.4538726807e+02, /* 0x442158c9 */ sa4 = 6.4538726807e+02f, /* 0x442158c9 */
sa5 = 4.2900814819e+02, /* 0x43d6810b */ sa5 = 4.2900814819e+02f, /* 0x43d6810b */
sa6 = 1.0863500214e+02, /* 0x42d9451f */ sa6 = 1.0863500214e+02f, /* 0x42d9451f */
sa7 = 6.5702495575e+00, /* 0x40d23f7c */ sa7 = 6.5702495575e+00f, /* 0x40d23f7c */
sa8 = -6.0424413532e-02, /* 0xbd777f97 */ sa8 = -6.0424413532e-02f, /* 0xbd777f97 */
/* /*
* Coefficients for approximation to erfc in [1/.35,28] * Coefficients for approximation to erfc in [1/.35,28]
*/ */
rb0 = -9.8649431020e-03, /* 0xbc21a092 */ rb0 = -9.8649431020e-03f, /* 0xbc21a092 */
rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */ rb1 = -7.9928326607e-01f, /* 0xbf4c9dd4 */
rb2 = -1.7757955551e+01, /* 0xc18e104b */ rb2 = -1.7757955551e+01f, /* 0xc18e104b */
rb3 = -1.6063638306e+02, /* 0xc320a2ea */ rb3 = -1.6063638306e+02f, /* 0xc320a2ea */
rb4 = -6.3756646729e+02, /* 0xc41f6441 */ rb4 = -6.3756646729e+02f, /* 0xc41f6441 */
rb5 = -1.0250950928e+03, /* 0xc480230b */ rb5 = -1.0250950928e+03f, /* 0xc480230b */
rb6 = -4.8351919556e+02, /* 0xc3f1c275 */ rb6 = -4.8351919556e+02f, /* 0xc3f1c275 */
sb1 = 3.0338060379e+01, /* 0x41f2b459 */ sb1 = 3.0338060379e+01f, /* 0x41f2b459 */
sb2 = 3.2579251099e+02, /* 0x43a2e571 */ sb2 = 3.2579251099e+02f, /* 0x43a2e571 */
sb3 = 1.5367296143e+03, /* 0x44c01759 */ sb3 = 1.5367296143e+03f, /* 0x44c01759 */
sb4 = 3.1998581543e+03, /* 0x4547fdbb */ sb4 = 3.1998581543e+03f, /* 0x4547fdbb */
sb5 = 2.5530502930e+03, /* 0x451f90ce */ sb5 = 2.5530502930e+03f, /* 0x451f90ce */
sb6 = 4.7452853394e+02, /* 0x43ed43a7 */ sb6 = 4.7452853394e+02f, /* 0x43ed43a7 */
sb7 = -2.2440952301e+01; /* 0xc1b38712 */ sb7 = -2.2440952301e+01f; /* 0xc1b38712 */
#ifdef __STDC__ #ifdef __STDC__
float erff(float x) float erff(float x)

View File

@ -29,7 +29,7 @@ static const float
#else #else
static float static float
#endif #endif
two25 = 3.3554432000e+07; /* 0x4c000000 */ two25 = 3.3554432000e+07f; /* 0x4c000000 */
#ifdef __STDC__ #ifdef __STDC__
float frexpf(float x, int *eptr) float frexpf(float x, int *eptr)

View File

@ -23,7 +23,6 @@
*/ */
#include "fdlibm.h" #include "fdlibm.h"
//#include <errno.h>
#ifdef __STDC__ #ifdef __STDC__
float ldexpf(float value, int exp) float ldexpf(float value, int exp)

View File

@ -25,9 +25,9 @@
#include "fdlibm.h" #include "fdlibm.h"
#ifdef __STDC__ #ifdef __STDC__
static const float one = 1.0; static const float one = 1.0f;
#else #else
static float one = 1.0; static float one = 1.0f;
#endif #endif
#ifdef __STDC__ #ifdef __STDC__

View File

@ -25,8 +25,6 @@
#include "fdlibm.h" #include "fdlibm.h"
#define _IEEE_LIBM 1 #define _IEEE_LIBM 1
//#include <reent.h>
//#include <errno.h>
#ifdef __STDC__ #ifdef __STDC__
float lgammaf(float x) float lgammaf(float x)

View File

@ -1,4 +1,3 @@
//#include <fenv.h>
#include <math.h> #include <math.h>
/* nearbyint is the same as rint, but it must not raise the inexact exception */ /* nearbyint is the same as rint, but it must not raise the inexact exception */

35
lib/libm_dbl/round.c Normal file
View File

@ -0,0 +1,35 @@
#include "libm.h"
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
#define EPS DBL_EPSILON
#elif FLT_EVAL_METHOD==2
#define EPS LDBL_EPSILON
#endif
static const double_t toint = 1/EPS;
double round(double x)
{
union {double f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double_t y;
if (e >= 0x3ff+52)
return x;
if (u.i >> 63)
x = -x;
if (e < 0x3ff-1) {
/* raise inexact if x!=0 */
FORCE_EVAL(x + toint);
return 0*u.f;
}
y = x + toint - toint - x;
if (y > 0.5)
y = y + x - 1;
else if (y <= -0.5)
y = y + x + 1;
else
y = y + x;
if (u.i >> 63)
y = -y;
return y;
}

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ extern "C"
// Software library version // Software library version
// Major (top-nibble), incremented on backwards incompatible changes // Major (top-nibble), incremented on backwards incompatible changes
// Minor (bottom-nibble), incremented on feature additions // Minor (bottom-nibble), incremented on feature additions
#define LFS2_VERSION 0x00020001 #define LFS2_VERSION 0x00020002
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
@ -355,6 +355,11 @@ typedef struct lfs2_superblock {
lfs2_size_t attr_max; lfs2_size_t attr_max;
} lfs2_superblock_t; } lfs2_superblock_t;
typedef struct lfs2_gstate {
uint32_t tag;
lfs2_block_t pair[2];
} lfs2_gstate_t;
// The littlefs filesystem type // The littlefs filesystem type
typedef struct lfs2 { typedef struct lfs2 {
lfs2_cache_t rcache; lfs2_cache_t rcache;
@ -369,10 +374,9 @@ typedef struct lfs2 {
} *mlist; } *mlist;
uint32_t seed; uint32_t seed;
struct lfs2_gstate { lfs2_gstate_t gstate;
uint32_t tag; lfs2_gstate_t gdisk;
lfs2_block_t pair[2]; lfs2_gstate_t gdelta;
} gstate, gpending, gdelta;
struct lfs2_free { struct lfs2_free {
lfs2_block_t off; lfs2_block_t off;

View File

@ -50,31 +50,35 @@ extern "C"
// Logging functions // Logging functions
#ifdef LFS2_YES_TRACE #ifdef LFS2_YES_TRACE
#define LFS2_TRACE(fmt, ...) \ #define LFS2_TRACE_(fmt, ...) \
printf("lfs2_trace:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
#else #else
#define LFS2_TRACE(fmt, ...) #define LFS2_TRACE(...)
#endif #endif
#ifndef LFS2_NO_DEBUG #ifndef LFS2_NO_DEBUG
#define LFS2_DEBUG(fmt, ...) \ #define LFS2_DEBUG_(fmt, ...) \
printf("lfs2_debug:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "")
#else #else
#define LFS2_DEBUG(fmt, ...) #define LFS2_DEBUG(...)
#endif #endif
#ifndef LFS2_NO_WARN #ifndef LFS2_NO_WARN
#define LFS2_WARN(fmt, ...) \ #define LFS2_WARN_(fmt, ...) \
printf("lfs2_warn:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "")
#else #else
#define LFS2_WARN(fmt, ...) #define LFS2_WARN(...)
#endif #endif
#ifndef LFS2_NO_ERROR #ifndef LFS2_NO_ERROR
#define LFS2_ERROR(fmt, ...) \ #define LFS2_ERROR_(fmt, ...) \
printf("lfs2_error:%d: " fmt "\n", __LINE__, __VA_ARGS__) printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
#define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "")
#else #else
#define LFS2_ERROR(fmt, ...) #define LFS2_ERROR(...)
#endif #endif
// Runtime assertions // Runtime assertions
@ -107,7 +111,7 @@ static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) {
return lfs2_aligndown(a + alignment-1, alignment); return lfs2_aligndown(a + alignment-1, alignment);
} }
// Find the next smallest power of 2 less than or equal to a // Find the smallest power of 2 greater than or equal to a
static inline uint32_t lfs2_npw2(uint32_t a) { static inline uint32_t lfs2_npw2(uint32_t a) {
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) #if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
return 32 - __builtin_clz(a-1); return 32 - __builtin_clz(a-1);

View File

@ -84,6 +84,7 @@ STATIC void mp_hal_move_cursor_back(uint pos) {
// snprintf needs space for the terminating null character // snprintf needs space for the terminating null character
int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos); int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos);
if (n > 0) { if (n > 0) {
assert((unsigned)n < sizeof(vt100_command));
vt100_command[n] = 'D'; // replace null char vt100_command[n] = 'D'; // replace null char
mp_hal_stdout_tx_strn(vt100_command, n + 1); mp_hal_stdout_tx_strn(vt100_command, n + 1);
} }
@ -109,6 +110,35 @@ typedef struct _readline_t {
STATIC readline_t rl; STATIC readline_t rl;
#if MICROPY_REPL_EMACS_WORDS_MOVE
STATIC size_t cursor_count_word(int forward) {
const char *line_buf = vstr_str(rl.line);
size_t pos = rl.cursor_pos;
bool in_word = false;
for (;;) {
// if moving backwards and we've reached 0... break
if (!forward && pos == 0) {
break;
}
// or if moving forwards and we've reached to the end of line... break
else if (forward && pos == vstr_len(rl.line)) {
break;
}
if (unichar_isalnum(line_buf[pos + (forward - 1)])) {
in_word = true;
} else if (in_word) {
break;
}
pos += forward ? forward : -1;
}
return forward ? pos - rl.cursor_pos : rl.cursor_pos - pos;
}
#endif
int readline_process_char(int c) { int readline_process_char(int c) {
size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len); size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len);
int cont_chars = 0; int cont_chars = 0;
@ -161,6 +191,10 @@ int readline_process_char(int c) {
redraw_step_back = rl.cursor_pos - rl.orig_line_len; redraw_step_back = rl.cursor_pos - rl.orig_line_len;
redraw_from_cursor = true; redraw_from_cursor = true;
#endif #endif
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
} else if (c == CHAR_CTRL_W) {
goto backward_kill_word;
#endif
} else if (c == '\r') { } else if (c == '\r') {
// newline // newline
mp_hal_stdout_tx_str("\r\n"); mp_hal_stdout_tx_str("\r\n");
@ -255,9 +289,40 @@ int readline_process_char(int c) {
case 'O': case 'O':
rl.escape_seq = ESEQ_ESC_O; rl.escape_seq = ESEQ_ESC_O;
break; break;
#if MICROPY_REPL_EMACS_WORDS_MOVE
case 'b':
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
backward_word:
#endif
redraw_step_back = cursor_count_word(0);
rl.escape_seq = ESEQ_NONE;
break;
case 'f':
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
forward_word:
#endif
redraw_step_forward = cursor_count_word(1);
rl.escape_seq = ESEQ_NONE;
break;
case 'd':
vstr_cut_out_bytes(rl.line, rl.cursor_pos, cursor_count_word(1));
redraw_from_cursor = true;
rl.escape_seq = ESEQ_NONE;
break;
case 127:
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
backward_kill_word:
#endif
redraw_step_back = cursor_count_word(0);
vstr_cut_out_bytes(rl.line, rl.cursor_pos - redraw_step_back, redraw_step_back);
redraw_from_cursor = true;
rl.escape_seq = ESEQ_NONE;
break;
#endif
default: default:
DEBUG_printf("(ESC %d)", c); DEBUG_printf("(ESC %d)", c);
rl.escape_seq = ESEQ_NONE; rl.escape_seq = ESEQ_NONE;
break;
} }
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) { } else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
if ('0' <= c && c <= '9') { if ('0' <= c && c <= '9') {
@ -365,6 +430,24 @@ delete_key:
} else { } else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
} }
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
} else if (c == ';' && rl.escape_seq_buf[0] == '1') {
// ';' is used to separate parameters. so first parameter was '1',
// that's used for sequences like ctrl+left, which we will try to parse.
// escape_seq state is reset back to ESEQ_ESC_BRACKET, as if we've just received
// the opening bracket, because more parameters are to come.
// we don't track the parameters themselves to keep low on logic and code size. that
// might be required in the future if more complex sequences are added.
rl.escape_seq = ESEQ_ESC_BRACKET;
// goto away from the state-machine, as rl.escape_seq will be overridden.
goto redraw;
} else if (rl.escape_seq_buf[0] == '5' && c == 'C') {
// ctrl+right
goto forward_word;
} else if (rl.escape_seq_buf[0] == '5' && c == 'D') {
// ctrl+left
goto backward_word;
#endif
} else { } else {
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c); DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
} }
@ -383,6 +466,10 @@ delete_key:
rl.escape_seq = ESEQ_NONE; rl.escape_seq = ESEQ_NONE;
} }
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
redraw:
#endif
// redraw command prompt, efficiently // redraw command prompt, efficiently
if (redraw_step_back > 0) { if (redraw_step_back > 0) {
mp_hal_move_cursor_back(redraw_step_back-cont_chars); mp_hal_move_cursor_back(redraw_step_back-cont_chars);

View File

@ -38,6 +38,7 @@
#define CHAR_CTRL_N (14) #define CHAR_CTRL_N (14)
#define CHAR_CTRL_P (16) #define CHAR_CTRL_P (16)
#define CHAR_CTRL_U (21) #define CHAR_CTRL_U (21)
#define CHAR_CTRL_W (23)
void readline_init0(void); void readline_init0(void);
int readline(vstr_t *line, const char *prompt); int readline(vstr_t *line, const char *prompt);

View File

@ -80,7 +80,7 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian
} else if (i > 0 && s < s_top && *s == '.') { } else if (i > 0 && s < s_top && *s == '.') {
s++; s++;
} else { } else {
mp_raise_ValueError(translate("invalid arguments")); mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
} }
} }
} }

View File

@ -159,14 +159,14 @@ mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
} }
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) { void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
t -= EPOCH1970_EPOCH2000_DIFF_SECS; t -= TIMEUTILS_SECONDS_1970_TO_2000;
timeutils_seconds_since_2000_to_struct_time(t, tm); timeutils_seconds_since_2000_to_struct_time(t, tm);
} }
mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date,
mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
mp_uint_t t = timeutils_seconds_since_2000(year, month, date, hour, minute, second); mp_uint_t t = timeutils_seconds_since_2000(year, month, date, hour, minute, second);
return t + EPOCH1970_EPOCH2000_DIFF_SECS; return t + TIMEUTILS_SECONDS_1970_TO_2000;
} }
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,

View File

@ -27,7 +27,9 @@
#ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
#define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
#define EPOCH1970_EPOCH2000_DIFF_SECS 946684800 // The number of seconds between 1970/1/1 and 2000/1/1 is calculated using:
// time.mktime((2000,1,1,0,0,0,0,0,0)) - time.mktime((1970,1,1,0,0,0,0,0,0))
#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800ULL)
typedef struct _timeutils_struct_time_t { typedef struct _timeutils_struct_time_t {
uint16_t tm_year; // i.e. 2014 uint16_t tm_year; // i.e. 2014
@ -40,6 +42,14 @@ typedef struct _timeutils_struct_time_t {
uint16_t tm_yday; // 1..366 uint16_t tm_yday; // 1..366
} timeutils_struct_time_t; } timeutils_struct_time_t;
static inline uint64_t timeutils_seconds_since_2000_to_nanoseconds_since_1970(mp_uint_t s) {
return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL;
}
static inline mp_uint_t timeutils_seconds_since_2000_from_nanoseconds_since_1970(uint64_t ns) {
return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000;
}
bool timeutils_is_leap_year(mp_uint_t year); bool timeutils_is_leap_year(mp_uint_t year);
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
@ -58,4 +68,10 @@ mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
mp_int_t hours, mp_int_t minutes, mp_int_t seconds); mp_int_t hours, mp_int_t minutes, mp_int_t seconds);
static inline uint64_t timeutils_nanoseconds_since_1970(mp_uint_t year, mp_uint_t month,
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
return timeutils_seconds_since_2000_to_nanoseconds_since_1970(
timeutils_seconds_since_2000(year, month, date, hour, minute, second));
}
#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H

View File

@ -28,7 +28,21 @@
#include <stdint.h> #include <stdint.h>
uintptr_t gc_helper_get_sp(void); #if MICROPY_GCREGS_SETJMP
uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs); #include <setjmp.h>
typedef jmp_buf gc_helper_regs_t;
#else
#if defined(__x86_64__)
typedef uintptr_t gc_helper_regs_t[6];
#elif defined(__i386__)
typedef uintptr_t gc_helper_regs_t[4];
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
typedef uintptr_t gc_helper_regs_t[10];
#endif
#endif
void gc_helper_collect_regs_and_stack(void);
#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H #endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H

View File

@ -0,0 +1,156 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "py/mpstate.h"
#include "py/gc.h"
#include "lib/utils/gchelper.h"
#if MICROPY_ENABLE_GC
// Even if we have specific support for an architecture, it is
// possible to force use of setjmp-based implementation.
#if !MICROPY_GCREGS_SETJMP
// We capture here callee-save registers, i.e. ones which may contain
// interesting values held there by our callers. It doesn't make sense
// to capture caller-saved registers, because they, well, put on the
// stack already by the caller.
#if defined(__x86_64__)
STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
register long rbx asm ("rbx");
register long rbp asm ("rbp");
register long r12 asm ("r12");
register long r13 asm ("r13");
register long r14 asm ("r14");
register long r15 asm ("r15");
#ifdef __clang__
// TODO:
// This is dirty workaround for Clang. It tries to get around
// uncompliant (wrt to GCC) behavior of handling register variables.
// Application of this patch here is random, and done only to unbreak
// MacOS build. Better, cross-arch ways to deal with Clang issues should
// be found.
asm ("" : "=r" (rbx));
asm ("" : "=r" (rbp));
asm ("" : "=r" (r12));
asm ("" : "=r" (r13));
asm ("" : "=r" (r14));
asm ("" : "=r" (r15));
#endif
arr[0] = rbx;
arr[1] = rbp;
arr[2] = r12;
arr[3] = r13;
arr[4] = r14;
arr[5] = r15;
}
#elif defined(__i386__)
STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
register long ebx asm ("ebx");
register long esi asm ("esi");
register long edi asm ("edi");
register long ebp asm ("ebp");
#ifdef __clang__
// TODO:
// This is dirty workaround for Clang. It tries to get around
// uncompliant (wrt to GCC) behavior of handling register variables.
// Application of this patch here is random, and done only to unbreak
// MacOS build. Better, cross-arch ways to deal with Clang issues should
// be found.
asm ("" : "=r" (ebx));
asm ("" : "=r" (esi));
asm ("" : "=r" (edi));
asm ("" : "=r" (ebp));
#endif
arr[0] = ebx;
arr[1] = esi;
arr[2] = edi;
arr[3] = ebp;
}
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
// Fallback implementation, prefer gchelper_m0.s or gchelper_m3.s
STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
register long r4 asm ("r4");
register long r5 asm ("r5");
register long r6 asm ("r6");
register long r7 asm ("r7");
register long r8 asm ("r8");
register long r9 asm ("r9");
register long r10 asm ("r10");
register long r11 asm ("r11");
register long r12 asm ("r12");
register long r13 asm ("r13");
arr[0] = r4;
arr[1] = r5;
arr[2] = r6;
arr[3] = r7;
arr[4] = r8;
arr[5] = r9;
arr[6] = r10;
arr[7] = r11;
arr[8] = r12;
arr[9] = r13;
}
#else
#error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation."
#endif
#else // !MICROPY_GCREGS_SETJMP
// Even if we have specific support for an architecture, it is
// possible to force use of setjmp-based implementation.
STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
setjmp(arr);
}
#endif // MICROPY_GCREGS_SETJMP
// Explicitly mark this as noinline to make sure the regs variable
// is effectively at the top of the stack: otherwise, in builds where
// LTO is enabled and a lot of inlining takes place we risk a stack
// layout where regs is lower on the stack than pointers which have
// just been allocated but not yet marked, and get incorrectly sweeped.
MP_NOINLINE void gc_helper_collect_regs_and_stack(void) {
gc_helper_regs_t regs;
gc_helper_get_regs(regs);
// GC stack (and regs because we captured them)
void **regs_ptr = (void **)(void *)&regs;
gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)&regs) / sizeof(uintptr_t));
}
#endif // MICROPY_ENABLE_GC

View File

@ -31,18 +31,6 @@
.section .text .section .text
.align 2 .align 2
.global gc_helper_get_sp
.type gc_helper_get_sp, %function
@ uint gc_helper_get_sp(void)
gc_helper_get_sp:
@ return the sp
mov r0, sp
bx lr
.size gc_helper_get_sp, .-gc_helper_get_sp
.global gc_helper_get_regs_and_sp .global gc_helper_get_regs_and_sp
.type gc_helper_get_regs_and_sp, %function .type gc_helper_get_regs_and_sp, %function

View File

@ -0,0 +1,47 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "py/mpstate.h"
#include "py/gc.h"
#include "lib/utils/gchelper.h"
#if MICROPY_ENABLE_GC
// provided by gchelper_*.s
uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs);
MP_NOINLINE void gc_helper_collect_regs_and_stack(void) {
// get the registers and the sp
gc_helper_regs_t regs;
uintptr_t sp = gc_helper_get_regs_and_sp(regs);
// trace the stack, including the registers (since they live on the stack in this function)
gc_collect_root((void **)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
}
#endif

View File

@ -32,9 +32,6 @@
int mp_interrupt_char = -1; int mp_interrupt_char = -1;
void mp_hal_set_interrupt_char(int c) { void mp_hal_set_interrupt_char(int c) {
if (c != -1) {
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
}
mp_interrupt_char = c; mp_interrupt_char = c;
} }

View File

@ -31,12 +31,14 @@
#include "py/gc.h" #include "py/gc.h"
#include "lib/utils/mpirq.h" #include "lib/utils/mpirq.h"
#if MICROPY_ENABLE_SCHEDULER
/****************************************************************************** /******************************************************************************
DECLARE PUBLIC DATA DECLARE PUBLIC DATA
******************************************************************************/ ******************************************************************************/
const mp_arg_t mp_irq_init_args[] = { const mp_arg_t mp_irq_init_args[] = {
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
}; };
@ -62,8 +64,10 @@ mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) {
void mp_irq_handler(mp_irq_obj_t *self) { void mp_irq_handler(mp_irq_obj_t *self) {
if (self->handler != mp_const_none) { if (self->handler != mp_const_none) {
if (self->ishard) { if (self->ishard) {
// When executing code within a handler we must lock the GC to prevent // When executing code within a handler we must lock the scheduler to
// any memory allocations. // prevent any scheduled callbacks from running, and lock the GC to
// prevent any memory allocations.
mp_sched_lock();
gc_lock(); gc_lock();
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
@ -77,6 +81,7 @@ void mp_irq_handler(mp_irq_obj_t *self) {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
} }
gc_unlock(); gc_unlock();
mp_sched_unlock();
} else { } else {
// Schedule call to user function // Schedule call to user function
mp_sched_schedule(self->handler, self->parent); mp_sched_schedule(self->handler, self->parent);
@ -122,3 +127,5 @@ const mp_obj_type_t mp_irq_type = {
.call = mp_irq_call, .call = mp_irq_call,
.locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict, .locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict,
}; };
#endif // MICROPY_ENABLE_SCHEDULER

View File

@ -46,7 +46,10 @@
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
int pyexec_system_exit = 0; int pyexec_system_exit = 0;
#if MICROPY_REPL_INFO
STATIC bool repl_display_debugging_info = 0; STATIC bool repl_display_debugging_info = 0;
#endif
#define EXEC_FLAG_PRINT_EOF (1) #define EXEC_FLAG_PRINT_EOF (1)
#define EXEC_FLAG_ALLOW_DEBUGGING (2) #define EXEC_FLAG_ALLOW_DEBUGGING (2)
@ -62,7 +65,9 @@ STATIC bool repl_display_debugging_info = 0;
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile) // EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) { STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
int ret = 0; int ret = 0;
#if MICROPY_REPL_INFO
uint32_t start = 0; uint32_t start = 0;
#endif
// by default a SystemExit exception returns 0 // by default a SystemExit exception returns 0
pyexec_system_exit = 0; pyexec_system_exit = 0;
@ -97,7 +102,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
// Clear the parse tree because it has a heap pointer we don't need anymore. // Clear the parse tree because it has a heap pointer we don't need anymore.
*((uint32_t volatile *)&parse_tree.chunk) = 0; *((uint32_t volatile *)&parse_tree.chunk) = 0;
#else #else
mp_raise_msg(&mp_type_RuntimeError, translate("script compilation not supported")); mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported"));
#endif #endif
} }
@ -110,11 +115,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
// execute code // execute code
mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
#if MICROPY_REPL_INFO
start = mp_hal_ticks_ms(); start = mp_hal_ticks_ms();
#endif
mp_call_function_0(module_fun); mp_call_function_0(module_fun);
mp_hal_set_interrupt_char(-1); // disable interrupt mp_hal_set_interrupt_char(-1); // disable interrupt
// Handle any ctrl-c interrupt that arrived just in time mp_handle_pending(true); // handle any pending exceptions (and any callbacks)
mp_handle_pending();
nlr_pop(); nlr_pop();
ret = 0; ret = 0;
if (exec_flags & EXEC_FLAG_PRINT_EOF) { if (exec_flags & EXEC_FLAG_PRINT_EOF) {
@ -122,8 +128,8 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
} }
} else { } else {
// uncaught exception // uncaught exception
// FIXME it could be that an interrupt happens just before we disable it here
mp_hal_set_interrupt_char(-1); // disable interrupt mp_hal_set_interrupt_char(-1); // disable interrupt
mp_handle_pending(false); // clear any pending exceptions (and run any callbacks)
// print EOF after normal output // print EOF after normal output
if (exec_flags & EXEC_FLAG_PRINT_EOF) { if (exec_flags & EXEC_FLAG_PRINT_EOF) {
mp_hal_stdout_tx_strn("\x04", 1); mp_hal_stdout_tx_strn("\x04", 1);
@ -160,6 +166,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
} }
} }
#if MICROPY_REPL_INFO
// display debugging info if wanted // display debugging info if wanted
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly
@ -179,6 +186,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
gc_dump_info(); gc_dump_info();
#endif #endif
} }
#endif
if (exec_flags & EXEC_FLAG_PRINT_EOF) { if (exec_flags & EXEC_FLAG_PRINT_EOF) {
mp_hal_stdout_tx_strn("\x04", 1); mp_hal_stdout_tx_strn("\x04", 1);
@ -362,7 +370,7 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
} }
exec:; exec:;
int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR, NULL); int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
if (ret & PYEXEC_FORCED_EXIT) { if (ret & PYEXEC_FORCED_EXIT) {
return ret; return ret;
} }
@ -612,9 +620,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
} }
#endif #endif
#if MICROPY_REPL_INFO
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) { mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
repl_display_debugging_info = mp_obj_get_int(o_value); repl_display_debugging_info = mp_obj_get_int(o_value);
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info); MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
#endif

View File

@ -29,8 +29,8 @@
#include "py/obj.h" #include "py/obj.h"
typedef enum { typedef enum {
PYEXEC_MODE_RAW_REPL,
PYEXEC_MODE_FRIENDLY_REPL, PYEXEC_MODE_FRIENDLY_REPL,
PYEXEC_MODE_RAW_REPL,
} pyexec_mode_kind_t; } pyexec_mode_kind_t;
typedef struct { typedef struct {
@ -59,8 +59,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result);
void pyexec_event_repl_init(void); void pyexec_event_repl_init(void);
int pyexec_event_repl_process_char(int c); int pyexec_event_repl_process_char(int c);
extern uint8_t pyexec_repl_active; extern uint8_t pyexec_repl_active;
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
#if MICROPY_REPL_INFO
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj); MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);
#endif
#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H #endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H

View File

@ -86,13 +86,8 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size,
} }
STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in); (void)self_in;
(void)self; if (request == MP_STREAM_POLL) {
// For now, pretend we actually flush the stdio stream.
if (request == MP_STREAM_FLUSH) {
return 0;
} else if (request == MP_STREAM_POLL) {
return mp_hal_stdio_poll(arg); return mp_hal_stdio_poll(arg);
} else { } else {
*errcode = MP_EINVAL; *errcode = MP_EINVAL;

View File

@ -70,7 +70,7 @@ msgstr ""
msgid "%q in use" msgid "%q in use"
msgstr "" msgstr ""
#: extmod/moductypes.c ports/atmel-samd/common-hal/pulseio/PulseIn.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c
#: ports/cxd56/common-hal/pulseio/PulseIn.c #: ports/cxd56/common-hal/pulseio/PulseIn.c
#: ports/nrf/common-hal/pulseio/PulseIn.c #: ports/nrf/common-hal/pulseio/PulseIn.c
#: ports/raspberrypi/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/pulseio/PulseIn.c
@ -80,7 +80,7 @@ msgid "%q index out of range"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "%q indices must be integers, not %q" msgid "%q indices must be integers, not %s"
msgstr "" msgstr ""
#: shared-bindings/vectorio/Polygon.c #: shared-bindings/vectorio/Polygon.c
@ -129,26 +129,10 @@ msgstr ""
msgid "'%q' argument required" msgid "'%q' argument required"
msgstr "" msgstr ""
#: py/runtime.c
msgid "'%q' object cannot assign attribute '%q'"
msgstr ""
#: py/proto.c #: py/proto.c
msgid "'%q' object does not support '%q'" msgid "'%q' object does not support '%q'"
msgstr "" msgstr ""
#: py/obj.c
msgid "'%q' object does not support item assignment"
msgstr ""
#: py/obj.c
msgid "'%q' object does not support item deletion"
msgstr ""
#: py/runtime.c
msgid "'%q' object has no attribute '%q'"
msgstr ""
#: py/runtime.c #: py/runtime.c
msgid "'%q' object is not an iterator" msgid "'%q' object is not an iterator"
msgstr "" msgstr ""
@ -161,10 +145,6 @@ msgstr ""
msgid "'%q' object is not iterable" msgid "'%q' object is not iterable"
msgstr "" msgstr ""
#: py/obj.c
msgid "'%q' object is not subscriptable"
msgstr ""
#: py/emitinlinethumb.c py/emitinlinextensa.c #: py/emitinlinethumb.c py/emitinlinextensa.c
#, c-format #, c-format
msgid "'%s' expects a label" msgid "'%s' expects a label"
@ -207,12 +187,31 @@ msgstr ""
#: py/emitinlinextensa.c #: py/emitinlinextensa.c
#, c-format #, c-format
msgid "'%s' integer %d is not within range %d..%d" msgid "'%s' integer %d isn't within range %d..%d"
msgstr "" msgstr ""
#: py/emitinlinethumb.c #: py/emitinlinethumb.c
#, c-format #, c-format
msgid "'%s' integer 0x%x does not fit in mask 0x%x" msgid "'%s' integer 0x%x doesn't fit in mask 0x%x"
msgstr ""
#: py/obj.c
#, c-format
msgid "'%s' object doesn't support item assignment"
msgstr ""
#: py/obj.c
#, c-format
msgid "'%s' object doesn't support item deletion"
msgstr ""
#: py/runtime.c
msgid "'%s' object has no attribute '%q'"
msgstr ""
#: py/obj.c
#, c-format
msgid "'%s' object isn't subscriptable"
msgstr "" msgstr ""
#: py/objstr.c #: py/objstr.c
@ -664,18 +663,10 @@ msgstr ""
msgid "Cannot specify RTS or CTS in RS485 mode" msgid "Cannot specify RTS or CTS in RS485 mode"
msgstr "" msgstr ""
#: py/objslice.c
msgid "Cannot subclass slice"
msgstr ""
#: shared-module/bitbangio/SPI.c #: shared-module/bitbangio/SPI.c
msgid "Cannot transfer without MOSI and MISO pins." msgid "Cannot transfer without MOSI and MISO pins."
msgstr "" msgstr ""
#: extmod/moductypes.c
msgid "Cannot unambiguously get sizeof scalar"
msgstr ""
#: shared-bindings/pwmio/PWMOut.c #: shared-bindings/pwmio/PWMOut.c
msgid "Cannot vary frequency on a timer that is already in use" msgid "Cannot vary frequency on a timer that is already in use"
msgstr "" msgstr ""
@ -1382,14 +1373,6 @@ msgstr ""
msgid "Layer must be a Group or TileGrid subclass." msgid "Layer must be a Group or TileGrid subclass."
msgstr "" msgstr ""
#: py/objslice.c
msgid "Length must be an int"
msgstr ""
#: py/objslice.c
msgid "Length must be non-negative"
msgstr ""
#: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c #: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c
msgid "MAC address was invalid" msgid "MAC address was invalid"
msgstr "" msgstr ""
@ -2404,6 +2387,10 @@ msgstr ""
msgid "arg is an empty sequence" msgid "arg is an empty sequence"
msgstr "" msgstr ""
#: py/objobject.c
msgid "arg must be user-type"
msgstr ""
#: extmod/ulab/code/numpy/numerical/numerical.c #: extmod/ulab/code/numpy/numerical/numerical.c
msgid "argsort argument must be an ndarray" msgid "argsort argument must be an ndarray"
msgstr "" msgstr ""
@ -2416,6 +2403,10 @@ msgstr ""
msgid "argument has wrong type" msgid "argument has wrong type"
msgstr "" msgstr ""
#: py/compile.c
msgid "argument name reused"
msgstr ""
#: py/argcheck.c shared-bindings/_stage/__init__.c #: py/argcheck.c shared-bindings/_stage/__init__.c
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c #: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c
msgid "argument num/types mismatch" msgid "argument num/types mismatch"
@ -2569,6 +2560,10 @@ msgstr ""
msgid "can't assign to expression" msgid "can't assign to expression"
msgstr "" msgstr ""
#: extmod/moduasyncio.c
msgid "can't cancel self"
msgstr ""
#: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c #: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c
#: shared-module/_pixelbuf/PixelBuf.c #: shared-module/_pixelbuf/PixelBuf.c
msgid "can't convert %q to %q" msgid "can't convert %q to %q"
@ -2578,6 +2573,11 @@ msgstr ""
msgid "can't convert %q to int" msgid "can't convert %q to int"
msgstr "" msgstr ""
#: py/obj.c
#, c-format
msgid "can't convert %s to complex"
msgstr ""
#: py/objstr.c #: py/objstr.c
msgid "can't convert '%q' object to %q implicitly" msgid "can't convert '%q' object to %q implicitly"
msgstr "" msgstr ""
@ -2586,6 +2586,10 @@ msgstr ""
msgid "can't convert to %q" msgid "can't convert to %q"
msgstr "" msgstr ""
#: py/obj.c
msgid "can't convert to complex"
msgstr ""
#: py/runtime.c #: py/runtime.c
msgid "can't convert to int" msgid "can't convert to int"
msgstr "" msgstr ""
@ -2684,6 +2688,10 @@ msgstr ""
msgid "cannot perform relative import" msgid "cannot perform relative import"
msgstr "" msgstr ""
#: extmod/moductypes.c
msgid "cannot unambiguously get sizeof scalar"
msgstr ""
#: py/emitnative.c #: py/emitnative.c
msgid "casting" msgid "casting"
msgstr "" msgstr ""
@ -2732,6 +2740,10 @@ msgstr ""
msgid "color should be an int" msgid "color should be an int"
msgstr "" msgstr ""
#: py/emitnative.c
msgid "comparison of int and uint"
msgstr ""
#: py/objcomplex.c #: py/objcomplex.c
msgid "complex division by zero" msgid "complex division by zero"
msgstr "" msgstr ""
@ -2834,7 +2846,15 @@ msgstr ""
msgid "dimensions do not match" msgid "dimensions do not match"
msgstr "" msgstr ""
#: py/modmath.c py/objfloat.c py/objint_longlong.c py/objint_mpz.c py/runtime.c #: py/emitnative.c
msgid "div/mod not implemented for uint"
msgstr ""
#: py/objfloat.c py/objint_mpz.c
msgid "divide by zero"
msgstr ""
#: py/modmath.c py/objint_longlong.c py/runtime.c
#: shared-bindings/math/__init__.c #: shared-bindings/math/__init__.c
msgid "division by zero" msgid "division by zero"
msgstr "" msgstr ""
@ -2843,7 +2863,7 @@ msgstr ""
msgid "empty" msgid "empty"
msgstr "" msgstr ""
#: extmod/moduheapq.c extmod/modutimeq.c #: extmod/moduasyncio.c extmod/moduheapq.c extmod/modutimeq.c
msgid "empty heap" msgid "empty heap"
msgstr "" msgstr ""
@ -3077,10 +3097,6 @@ msgstr ""
msgid "import * not at module level" msgid "import * not at module level"
msgstr "" msgstr ""
#: py/persistentcode.c
msgid "incompatible .mpy file"
msgstr ""
#: py/persistentcode.c #: py/persistentcode.c
msgid "incompatible native .mpy architecture" msgid "incompatible native .mpy architecture"
msgstr "" msgstr ""
@ -3217,10 +3233,6 @@ msgstr ""
msgid "invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32" msgid "invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32"
msgstr "" msgstr ""
#: py/compile.c
msgid "invalid decorator"
msgstr ""
#: shared-bindings/bitmaptools/__init__.c #: shared-bindings/bitmaptools/__init__.c
#, c-format #, c-format
msgid "invalid element size %d for bits_per_pixel %d\n" msgid "invalid element size %d for bits_per_pixel %d\n"
@ -3427,10 +3439,6 @@ msgstr ""
msgid "name not defined" msgid "name not defined"
msgstr "" msgstr ""
#: py/compile.c
msgid "name reused for argument"
msgstr ""
#: py/emitnative.c #: py/emitnative.c
msgid "native yield" msgid "native yield"
msgstr "" msgstr ""
@ -3485,7 +3493,7 @@ msgstr ""
msgid "no response from SD card" msgid "no response from SD card"
msgstr "" msgstr ""
#: py/runtime.c #: py/objobject.c py/runtime.c
msgid "no such attribute" msgid "no such attribute"
msgstr "" msgstr ""
@ -3538,15 +3546,16 @@ msgid "object "
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "object '%q' is not a tuple or list" #, c-format
msgid "object '%s' isn't a tuple or list"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "object does not support item assignment" msgid "object doesn't support item assignment"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "object does not support item deletion" msgid "object doesn't support item deletion"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
@ -3554,7 +3563,7 @@ msgid "object has no len"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "object is not subscriptable" msgid "object isn't subscriptable"
msgstr "" msgstr ""
#: py/runtime.c #: py/runtime.c
@ -3574,7 +3583,8 @@ msgid "object not iterable"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
msgid "object of type '%q' has no len()" #, c-format
msgid "object of type '%s' has no len()"
msgstr "" msgstr ""
#: py/obj.c #: py/obj.c
@ -3844,6 +3854,10 @@ msgstr ""
msgid "script compilation not supported" msgid "script compilation not supported"
msgstr "" msgstr ""
#: py/nativeglue.c
msgid "set unsupported"
msgstr ""
#: extmod/ulab/code/ndarray.c #: extmod/ulab/code/ndarray.c
msgid "shape must be a tuple" msgid "shape must be a tuple"
msgstr "" msgstr ""
@ -3872,12 +3886,12 @@ msgstr ""
msgid "sleep length must be non-negative" msgid "sleep length must be non-negative"
msgstr "" msgstr ""
#: extmod/ulab/code/ndarray.c #: extmod/ulab/code/ndarray.c py/objslice.c
msgid "slice step can't be zero" msgid "slice step can't be zero"
msgstr "" msgstr ""
#: py/objslice.c py/sequence.c #: py/nativeglue.c
msgid "slice step cannot be zero" msgid "slice unsupported"
msgstr "" msgstr ""
#: py/objint.c py/sequence.c #: py/objint.c py/sequence.c
@ -3941,7 +3955,11 @@ msgid "string not supported; use bytes or bytearray"
msgstr "" msgstr ""
#: extmod/moductypes.c #: extmod/moductypes.c
msgid "struct: cannot index" msgid "struct: can't index"
msgstr ""
#: extmod/moductypes.c
msgid "struct: index out of range"
msgstr "" msgstr ""
#: extmod/moductypes.c #: extmod/moductypes.c

View File

@ -8,120 +8,13 @@
#include "py/mpstate.h" #include "py/mpstate.h"
#include "py/gc.h" #include "py/gc.h"
#include "lib/utils/gchelper.h"
#if MICROPY_ENABLE_GC #if MICROPY_ENABLE_GC
// Even if we have specific support for an architecture, it is
// possible to force use of setjmp-based implementation.
#if !MICROPY_GCREGS_SETJMP
// We capture here callee-save registers, i.e. ones which may contain
// interesting values held there by our callers. It doesn't make sense
// to capture caller-saved registers, because they, well, put on the
// stack already by the caller.
#if defined(__x86_64__)
typedef mp_uint_t regs_t[6];
STATIC void gc_helper_get_regs(regs_t arr) {
register long rbx asm ("rbx");
register long rbp asm ("rbp");
register long r12 asm ("r12");
register long r13 asm ("r13");
register long r14 asm ("r14");
register long r15 asm ("r15");
#ifdef __clang__
// TODO:
// This is dirty workaround for Clang. It tries to get around
// uncompliant (wrt to GCC) behavior of handling register variables.
// Application of this patch here is random, and done only to unbreak
// MacOS build. Better, cross-arch ways to deal with Clang issues should
// be found.
asm ("" : "=r" (rbx));
asm ("" : "=r" (rbp));
asm ("" : "=r" (r12));
asm ("" : "=r" (r13));
asm ("" : "=r" (r14));
asm ("" : "=r" (r15));
#endif
arr[0] = rbx;
arr[1] = rbp;
arr[2] = r12;
arr[3] = r13;
arr[4] = r14;
arr[5] = r15;
}
#elif defined(__i386__)
typedef mp_uint_t regs_t[4];
STATIC void gc_helper_get_regs(regs_t arr) {
register long ebx asm ("ebx");
register long esi asm ("esi");
register long edi asm ("edi");
register long ebp asm ("ebp");
arr[0] = ebx;
arr[1] = esi;
arr[2] = edi;
arr[3] = ebp;
}
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
typedef mp_uint_t regs_t[10];
STATIC void gc_helper_get_regs(regs_t arr) {
register long r4 asm ("r4");
register long r5 asm ("r5");
register long r6 asm ("r6");
register long r7 asm ("r7");
register long r8 asm ("r8");
register long r9 asm ("r9");
register long r10 asm ("r10");
register long r11 asm ("r11");
register long r12 asm ("r12");
register long r13 asm ("r13");
arr[0] = r4;
arr[1] = r5;
arr[2] = r6;
arr[3] = r7;
arr[4] = r8;
arr[5] = r9;
arr[6] = r10;
arr[7] = r11;
arr[8] = r12;
arr[9] = r13;
}
#else
// If we don't have architecture-specific optimized support,
// just fall back to setjmp-based implementation.
#undef MICROPY_GCREGS_SETJMP
#define MICROPY_GCREGS_SETJMP (1)
#endif // Arch-specific selection
#endif // !MICROPY_GCREGS_SETJMP
// If MICROPY_GCREGS_SETJMP was requested explicitly, or if
// we enabled it as a fallback above.
#if MICROPY_GCREGS_SETJMP
#include <setjmp.h>
typedef jmp_buf regs_t;
STATIC void gc_helper_get_regs(regs_t arr) {
setjmp(arr);
}
#endif // MICROPY_GCREGS_SETJMP
void gc_collect(void) { void gc_collect(void) {
gc_collect_start(); gc_collect_start();
regs_t regs; gc_helper_collect_regs_and_stack();
gc_helper_get_regs(regs);
// GC stack (and regs because we captured them)
void **regs_ptr = (void **)(void *)&regs;
gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&regs) / sizeof(mp_uint_t));
gc_collect_end(); gc_collect_end();
} }

View File

@ -26,7 +26,7 @@ mp_uint_t mp_verbose_flag = 0;
// Make it larger on a 64 bit machine, because pointers are larger. // Make it larger on a 64 bit machine, because pointers are larger.
long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4); long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) { STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
(void)env; (void)env;
ssize_t dummy = write(STDERR_FILENO, str, len); ssize_t dummy = write(STDERR_FILENO, str, len);
(void)dummy; (void)dummy;
@ -324,7 +324,7 @@ uint mp_import_stat(const char *path) {
} }
void nlr_jump_fail(void *val) { void nlr_jump_fail(void *val) {
printf("FATAL: uncaught NLR %p\n", val); fprintf(stderr, "FATAL: uncaught NLR %p\n", val);
exit(1); exit(1);
} }

View File

@ -48,14 +48,9 @@
#define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1)
// Define to 1 to use undertested inefficient GC helper implementation #if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
// (if more efficient arch-specific one is not available). // Fall back to setjmp() implementation for discovery of GC pointers in registers.
#ifndef MICROPY_GCREGS_SETJMP #define MICROPY_GCREGS_SETJMP (1)
#ifdef __mips__
#define MICROPY_GCREGS_SETJMP (1)
#else
#define MICROPY_GCREGS_SETJMP (0)
#endif
#endif #endif
#define MICROPY_PY___FILE__ (0) #define MICROPY_PY___FILE__ (0)

Some files were not shown because too many files have changed in this diff Show More