Merge pull request #4720 from tannewt/merge_1.13
Merge in MicroPython 1.13
This commit is contained in:
commit
446169e078
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@ -71,27 +71,18 @@ jobs:
|
||||
run: make -C mpy-cross -j2
|
||||
- name: Build unix port
|
||||
run: |
|
||||
make -C ports/unix deplibs -j2
|
||||
make -C ports/unix -j2
|
||||
make -C ports/unix coverage -j2
|
||||
make -C ports/unix VARIANT=coverage -j2
|
||||
- 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-coverage ./run-tests -j1
|
||||
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
|
||||
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-coverage ./run-tests -j1 --emit native
|
||||
working-directory: 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-coverage ./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-coverage ./run-tests -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
|
||||
working-directory: tests
|
||||
- name: Build mpy-cross.static-aarch64
|
||||
run: make -C mpy-cross -j2 -f Makefile.static-aarch64
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -37,8 +37,7 @@ build-*/
|
||||
|
||||
# Test failure outputs
|
||||
######################
|
||||
tests/*.exp
|
||||
tests/*.out
|
||||
tests/results/*
|
||||
|
||||
# Python cache files
|
||||
######################
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
6
Makefile
6
Makefile
@ -7,7 +7,7 @@
|
||||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python3
|
||||
SPHINXOPTS =
|
||||
SPHINXOPTS = -W --keep-going
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
# path to build the generated docs
|
||||
@ -223,7 +223,7 @@ pseudoxml:
|
||||
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.
|
||||
# However, this was a frequent source of merge conflicts. Weblate can perform
|
||||
@ -248,7 +248,7 @@ merge-translate:
|
||||
|
||||
.PHONY: 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
|
||||
|
||||
stubs:
|
||||
|
4
conf.py
4
conf.py
@ -25,7 +25,6 @@ import sys
|
||||
import urllib.parse
|
||||
import time
|
||||
|
||||
import recommonmark
|
||||
from sphinx.transforms import SphinxTransform
|
||||
from docutils import nodes
|
||||
from sphinx import addnodes
|
||||
@ -68,8 +67,9 @@ extensions = [
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx_search.extension',
|
||||
'rstjinja',
|
||||
'recommonmark',
|
||||
'myst_parser',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -587,10 +587,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.
|
||||
|
||||
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
|
||||
:py:class:`~microcontroller.Pin` object alone would limit the driver to pins on
|
||||
the actual microcontroller instead of pins provided by another driver such as an
|
||||
IO expander.
|
||||
toggle instead of a :py:class:`~microcontroller.Pin` from :py:mod:`board`.
|
||||
Taking in the :py:class:`~microcontroller.Pin` object alone would limit the
|
||||
driver to pins on the actual microcontroller instead of pins provided by another
|
||||
driver such as an IO expander.
|
||||
|
||||
Lots of small modules
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -36,6 +36,7 @@ Full Table of Contents
|
||||
:caption: MicroPython specific
|
||||
|
||||
library/index.rst
|
||||
reference/glossary.rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -78,7 +78,7 @@ Example::
|
||||
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
|
||||
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.
|
||||
|
||||
.. method:: btree.__getitem__(key)
|
||||
btree.get(key, default=None)
|
||||
btree.get(key, default=None, /)
|
||||
btree.__setitem__(key, val)
|
||||
btree.__detitem__(key)
|
||||
btree.__contains__(key)
|
||||
|
@ -7,6 +7,7 @@
|
||||
|see_cpython_module| :mod:`cpython:errno`.
|
||||
|
||||
This module provides access to symbolic error codes for `OSError` exception.
|
||||
A particular inventory of codes depends on :term:`MicroPython port`.
|
||||
|
||||
Constants
|
||||
---------
|
||||
@ -14,7 +15,8 @@ Constants
|
||||
.. data:: EEXIST, EAGAIN, etc.
|
||||
|
||||
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::
|
||||
|
||||
try:
|
||||
@ -28,5 +30,5 @@ Constants
|
||||
Dictionary mapping numeric error codes to strings with symbolic error
|
||||
code (see above)::
|
||||
|
||||
>>> print(errno.errorcode[uerrno.EEXIST])
|
||||
>>> print(errno.errorcode[errno.EEXIST])
|
||||
EEXIST
|
||||
|
@ -1,4 +1,4 @@
|
||||
:mod:`framebuf` --- Frame buffer manipulation
|
||||
:mod:`framebuf` --- frame buffer manipulation
|
||||
=============================================
|
||||
|
||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||
@ -30,7 +30,7 @@ For example::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width)
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width, /)
|
||||
|
||||
Construct a FrameBuffer object. The parameters are:
|
||||
|
||||
@ -132,7 +132,7 @@ Constants
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
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
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
@ -141,7 +141,7 @@ Constants
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
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
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
@ -37,6 +37,7 @@ with the ``u`` prefix dropped:
|
||||
json.rst
|
||||
re.rst
|
||||
sys.rst
|
||||
uasyncio.rst
|
||||
uctypes.rst
|
||||
uselect.rst
|
||||
uzlib.rst
|
||||
|
@ -73,17 +73,26 @@ Functions
|
||||
|
||||
.. function:: heap_lock()
|
||||
.. function:: heap_unlock()
|
||||
.. function:: heap_locked()
|
||||
|
||||
Lock or unlock the heap. When locked no memory allocation can occur and a
|
||||
`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
|
||||
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.
|
||||
|
||||
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
|
||||
unlocked.
|
||||
|
||||
Note: `heap_locked()` is not enabled on most ports by default,
|
||||
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
|
||||
|
||||
.. function:: kbd_intr(chr)
|
||||
|
||||
Set the character that will raise a `KeyboardInterrupt` exception. By
|
||||
|
@ -124,7 +124,7 @@ Functions
|
||||
string for first position which matches regex (which still may be
|
||||
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
|
||||
with *replace*, and returning the new string.
|
||||
@ -138,11 +138,12 @@ Functions
|
||||
If *count* is specified and non-zero then substitution will stop after
|
||||
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
|
||||
|
||||
Flag value, display debug information about compiled expression.
|
||||
(Availability depends on :term:`MicroPython port`.)
|
||||
|
||||
|
||||
.. _regex:
|
||||
@ -155,14 +156,14 @@ Compiled regular expression. Instances of this class are created using
|
||||
|
||||
.. method:: regex.match(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`
|
||||
and :meth:`sub`.
|
||||
Using methods is (much) more efficient if the same regex is applied to
|
||||
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
|
||||
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.
|
||||
|
||||
Note: availability of this method depends on MicroPython port.
|
||||
Note: availability of this method depends on :term:`MicroPython port`.
|
||||
|
||||
.. method:: match.start([index])
|
||||
match.end([index])
|
||||
@ -192,10 +193,10 @@ to the replacement function in `sub()`.
|
||||
substring group that was matched. *index* defaults to the entire
|
||||
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])
|
||||
|
||||
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`.
|
||||
|
@ -11,7 +11,7 @@
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: exit(retval=0)
|
||||
.. function:: exit(retval=0, /)
|
||||
|
||||
Terminate current program with a given exit code. Underlyingly, this
|
||||
function raise as `SystemExit` exception. If an argument is given, its
|
||||
|
303
docs/library/uasyncio.rst
Normal file
303
docs/library/uasyncio.rst
Normal 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'``.
|
@ -182,7 +182,7 @@ Following are encoding examples for various field types:
|
||||
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
|
||||
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
|
||||
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
|
||||
either a structure class or a specific instantiated structure object
|
||||
|
@ -60,7 +60,7 @@ Methods
|
||||
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
|
||||
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
|
||||
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.
|
||||
|
||||
.. 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
|
||||
``callee-owned tuples``. This function provides efficient, allocation-free
|
||||
|
@ -16,7 +16,7 @@ is not yet implemented.
|
||||
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
|
||||
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
|
||||
CPython and is ignored.
|
||||
|
||||
.. class:: DecompIO(stream, wbits=0)
|
||||
.. class:: DecompIO(stream, wbits=0, /)
|
||||
|
||||
Create a ``stream`` wrapper which allows transparent decompression of
|
||||
compressed data in another *stream*. This allows to process compressed
|
||||
|
175
docs/reference/glossary.rst
Normal file
175
docs/reference/glossary.rst
Normal 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.
|
@ -1,7 +1,8 @@
|
||||
sphinx<4
|
||||
recommonmark==0.6.0
|
||||
myst-parser==0.14.0
|
||||
sphinxcontrib-svg2pdfconverter==0.1.0
|
||||
astroid
|
||||
sphinx-autoapi
|
||||
isort
|
||||
black
|
||||
readthedocs-sphinx-search
|
||||
|
@ -225,7 +225,7 @@ def support_matrix_by_board(use_branded_name=True):
|
||||
# flatmap with comprehensions
|
||||
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
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
6
docs/templates/replace.inc
vendored
6
docs/templates/replace.inc
vendored
@ -4,6 +4,6 @@
|
||||
|
||||
.. |see_cpython_module| replace::
|
||||
|
||||
*This module implements a subset of the corresponding* ``CPython`` *module,
|
||||
as described below. For more information, refer to the original*
|
||||
``CPython`` *documentation:*
|
||||
*This module implements a subset of the corresponding* :term:`CPython` *module,
|
||||
as described below. For more information, refer to the original
|
||||
CPython documentation:*
|
||||
|
14
examples/natmod/features0/Makefile
Normal file
14
examples/natmod/features0/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module
|
||||
MOD = features0
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = features0.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
# Include to get the rules for compiling and linking the module
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
40
examples/natmod/features0/features0.c
Normal file
40
examples/natmod/features0/features0.c
Normal file
@ -0,0 +1,40 @@
|
||||
/* This example demonstrates the following features in a native module:
|
||||
- defining a simple function exposed to Python
|
||||
- defining a local, helper C function
|
||||
- getting and creating integer objects
|
||||
*/
|
||||
|
||||
// Include the header file to get access to the MicroPython API
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// Helper function to compute factorial
|
||||
STATIC mp_int_t factorial_helper(mp_int_t x) {
|
||||
if (x == 0) {
|
||||
return 1;
|
||||
}
|
||||
return x * factorial_helper(x - 1);
|
||||
}
|
||||
|
||||
// This is the function which will be called from Python, as factorial(x)
|
||||
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
|
||||
// Extract the integer from the MicroPython input object
|
||||
mp_int_t x = mp_obj_get_int(x_obj);
|
||||
// Calculate the factorial
|
||||
mp_int_t result = factorial_helper(x);
|
||||
// Convert the result to a MicroPython integer object and return it
|
||||
return mp_obj_new_int(result);
|
||||
}
|
||||
// Define a Python reference to the function above
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
|
||||
|
||||
// This is the entry point and is called when the module is imported
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
// This must be first, it sets up the globals dict and other things
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
// Make the function available in the module's namespace
|
||||
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
|
||||
|
||||
// This must be last, it restores the globals dict
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
57
extmod/btstack/btstack.mk
Normal file
57
extmod/btstack/btstack.mk
Normal 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
|
47
extmod/btstack/btstack_config.h
Normal file
47
extmod/btstack/btstack_config.h
Normal 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
|
1047
extmod/btstack/modbluetooth_btstack.c
Normal file
1047
extmod/btstack/modbluetooth_btstack.c
Normal file
File diff suppressed because it is too large
Load Diff
70
extmod/btstack/modbluetooth_btstack.h
Normal file
70
extmod/btstack/modbluetooth_btstack.h
Normal 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
|
@ -51,7 +51,7 @@ CFLAGS_MOD += -DMICROPY_PY_USSL=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
|
||||
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)/,\
|
||||
ssl/asn1.c \
|
||||
ssl/loader.c \
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
typedef struct _mp_obj_btree_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t stream; // retain a reference to prevent GC from reclaiming it
|
||||
DB *db;
|
||||
mp_obj_t start_key;
|
||||
mp_obj_t end_key;
|
||||
@ -44,9 +45,10 @@ void __dbpanic(DB *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);
|
||||
o->base.type = &btree_type;
|
||||
o->stream = stream;
|
||||
o->db = db;
|
||||
o->start_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) {
|
||||
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) {
|
||||
// delete
|
||||
DBT key;
|
||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||
int res = __bt_delete(self->db, &key, 0);
|
||||
if (res == RET_SPECIAL) {
|
||||
nlr_raise(mp_obj_new_exception(&mp_type_KeyError));
|
||||
mp_raise_type(&mp_type_KeyError);
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
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);
|
||||
int res = __bt_get(self->db, &key, &val, 0);
|
||||
if (res == RET_SPECIAL) {
|
||||
nlr_raise(mp_obj_new_exception(&mp_type_KeyError));
|
||||
mp_raise_type(&mp_type_KeyError);
|
||||
}
|
||||
CHECK_ERROR(res);
|
||||
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) {
|
||||
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);
|
||||
|
||||
|
@ -22,6 +22,10 @@ typedef struct _mp_obj_framebuf_t {
|
||||
uint8_t format;
|
||||
} 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 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);
|
||||
@ -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:
|
||||
break;
|
||||
default:
|
||||
mp_raise_ValueError(translate("invalid format"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
@ -288,8 +292,11 @@ STATIC const mp_obj_type_t mp_type_framebuf;
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
if (native_framebuf == MP_OBJ_NULL) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
return MP_OBJ_TO_PTR(native_framebuf);
|
||||
}
|
||||
|
||||
|
294
extmod/moduasyncio.c
Normal file
294
extmod/moduasyncio.c
Normal 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
|
@ -9,17 +9,16 @@
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "extmod/modubinascii.h"
|
||||
|
||||
static void check_not_unicode(const mp_obj_t arg) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (mp_obj_is_str(arg)) {
|
||||
mp_raise_TypeError(translate("a bytes-like object is required"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("a bytes-like object is required"));
|
||||
}
|
||||
#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
|
||||
// between values.
|
||||
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);
|
||||
}
|
||||
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_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
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_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)) {
|
||||
hex_byte += unichar_xdigit_value(hex_ch);
|
||||
} else {
|
||||
mp_raise_ValueError(translate("non-hex digit found"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit found"));
|
||||
}
|
||||
if (i & 1) {
|
||||
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);
|
||||
}
|
||||
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
|
||||
// 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_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
byte *in = bufinfo.buf;
|
||||
@ -145,14 +144,14 @@ mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
mp_buffer_info_t bufinfo;
|
||||
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';
|
||||
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
|
||||
#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;
|
||||
check_not_unicode(args[0]);
|
||||
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);
|
||||
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
|
||||
|
||||
#if MICROPY_PY_UBINASCII
|
||||
|
||||
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_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) },
|
||||
@ -238,5 +235,3 @@ const mp_obj_module_t mp_module_ubinascii = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
|
||||
};
|
||||
|
||||
#endif // MICROPY_PY_UBINASCII
|
||||
|
@ -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
|
@ -98,7 +98,7 @@ typedef struct _mp_obj_uctypes_struct_t {
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
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) {
|
||||
@ -118,11 +118,7 @@ STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_p
|
||||
(void)kind;
|
||||
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
const char *typen = "unk";
|
||||
if (mp_obj_is_type(self->desc, &mp_type_dict)
|
||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
||||
|| mp_obj_is_type(self->desc, &mp_type_ordereddict)
|
||||
#endif
|
||||
) {
|
||||
if (mp_obj_is_dict_or_ordereddict(self->desc)) {
|
||||
typen = "STRUCT";
|
||||
} else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
|
||||
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) {
|
||||
if (!mp_obj_is_type(desc_in, &mp_type_dict)
|
||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
||||
&& !mp_obj_is_type(desc_in, &mp_type_ordereddict)
|
||||
#endif
|
||||
) {
|
||||
if (!mp_obj_is_dict_or_ordereddict(desc_in)) {
|
||||
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);
|
||||
} 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
|
||||
// type info is lost. So, we cannot say if it's scalar type description,
|
||||
// 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();
|
||||
}
|
||||
@ -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]);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case FLOAT32:
|
||||
return mp_obj_new_float(((float *)p)[index]);
|
||||
return mp_obj_new_float_from_f(((float *)p)[index]);
|
||||
case FLOAT64:
|
||||
return mp_obj_new_float(((double *)p)[index]);
|
||||
return mp_obj_new_float_from_d(((double *)p)[index]);
|
||||
#endif
|
||||
default:
|
||||
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) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
if (val_type == FLOAT32 || val_type == FLOAT64) {
|
||||
mp_float_t v = mp_obj_get_float(val);
|
||||
if (val_type == FLOAT32) {
|
||||
((float *)p)[index] = v;
|
||||
((float *)p)[index] = mp_obj_get_float_to_f(val);
|
||||
} else {
|
||||
((double *)p)[index] = v;
|
||||
((double *)p)[index] = mp_obj_get_float_to_d(val);
|
||||
}
|
||||
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) {
|
||||
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
if (!mp_obj_is_type(self->desc, &mp_type_dict)
|
||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
||||
&& !mp_obj_is_type(self->desc, &mp_type_ordereddict)
|
||||
#endif
|
||||
) {
|
||||
mp_raise_TypeError(translate("struct: no fields"));
|
||||
if (!mp_obj_is_dict_or_ordereddict(self->desc)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
// 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 {
|
||||
// load / store
|
||||
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);
|
||||
@ -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);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
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) {
|
||||
|
@ -89,7 +89,7 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
|
||||
static void check_not_unicode(const mp_obj_t arg) {
|
||||
#if MICROPY_CPYTHON_COMPAT
|
||||
if (mp_obj_is_str(arg)) {
|
||||
mp_raise_TypeError(translate("a bytes-like object is required"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("a bytes-like object is required"));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
|
||||
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);
|
||||
}
|
||||
@ -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) {
|
||||
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
||||
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];
|
||||
heap->len -= 1;
|
||||
|
@ -135,7 +135,7 @@ STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
|
||||
stack.len = 0;
|
||||
stack.items = 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;
|
||||
S_NEXT(s);
|
||||
for (;;) {
|
||||
@ -339,7 +339,7 @@ success:
|
||||
return stack_top;
|
||||
|
||||
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) {
|
||||
|
@ -132,7 +132,7 @@ STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {
|
||||
if (len > 0) {
|
||||
return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
|
||||
} 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);
|
||||
@ -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
|
||||
STATIC mp_float_t yasmarang_float(void) {
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
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;
|
||||
mp_float_union_t u;
|
||||
u.p.sgn = 0;
|
||||
u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
|
||||
if (MP_FLOAT_FRAC_BITS <= 32) {
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "re1.5/re1.5.h"
|
||||
|
||||
#if CIRCUITPY_RE_DEBUG
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
#define FLAG_DEBUG 0x1000
|
||||
#endif
|
||||
|
||||
@ -34,6 +34,10 @@ typedef struct _mp_obj_match_t {
|
||||
const char *caps[0];
|
||||
} 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) {
|
||||
(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) {
|
||||
(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;
|
||||
size_t 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_list_append(retval, s);
|
||||
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];
|
||||
if (maxsplit > 0 && --maxsplit == 0) {
|
||||
@ -263,8 +272,13 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
|
||||
|
||||
#if MICROPY_PY_URE_SUB
|
||||
|
||||
STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
|
||||
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));
|
||||
}
|
||||
mp_obj_t replace = args[1];
|
||||
mp_obj_t where = args[2];
|
||||
mp_int_t count = 0;
|
||||
@ -368,10 +382,7 @@ STATIC mp_obj_t re_sub_helper(mp_obj_t self_in, size_t n_args, const mp_obj_t *a
|
||||
return mp_obj_new_str_from_vstr(mp_obj_get_type(where), &vstr_return);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_sub(size_t n_args, const mp_obj_t *args) {
|
||||
return re_sub_helper(args[0], n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
|
||||
|
||||
#endif
|
||||
|
||||
@ -408,7 +419,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);
|
||||
o->base.type = &re_type;
|
||||
#if CIRCUITPY_RE_DEBUG
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
int flags = 0;
|
||||
if (n_args > 1) {
|
||||
flags = mp_obj_get_int(args[1]);
|
||||
@ -419,9 +430,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);
|
||||
if (error != 0) {
|
||||
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) {
|
||||
re1_5_dumpcode(&o->re);
|
||||
}
|
||||
@ -430,33 +441,6 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
|
||||
|
||||
STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
mp_obj_t self = mod_re_compile(1, args);
|
||||
|
||||
const mp_obj_t args2[] = {self, args[1]};
|
||||
mp_obj_t match = ure_exec(is_anchored, 2, args2);
|
||||
return match;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_re_match(size_t n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(true, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_match_obj, 2, 4, mod_re_match);
|
||||
|
||||
STATIC mp_obj_t mod_re_search(size_t n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(false, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);
|
||||
|
||||
#if MICROPY_PY_URE_SUB
|
||||
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);
|
||||
return re_sub_helper(self, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
|
||||
#endif
|
||||
|
||||
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||
STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
|
||||
#if CIRCUITPY
|
||||
@ -465,12 +449,12 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&mod_re_match_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&mod_re_search_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
|
||||
#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(&re_sub_obj) },
|
||||
#endif
|
||||
#if CIRCUITPY_RE_DEBUG
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
|
||||
#endif
|
||||
};
|
||||
@ -488,7 +472,7 @@ const mp_obj_module_t mp_module_ure = {
|
||||
|
||||
#define re1_5_fatal(x) assert(!x)
|
||||
#include "re1.5/compilecode.c"
|
||||
#if CIRCUITPY_RE_DEBUG
|
||||
#if MICROPY_PY_URE_DEBUG
|
||||
#include "re1.5/dumpcode.c"
|
||||
#endif
|
||||
#include "re1.5/recursiveloop.c"
|
||||
|
@ -105,7 +105,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 4) {
|
||||
if (args[3] != mp_const_none) {
|
||||
#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) {
|
||||
timeout = (mp_uint_t)(timeout_f * 1000);
|
||||
}
|
||||
|
@ -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_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
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;
|
||||
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) {
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
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);
|
||||
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) {
|
||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
mp_raise_IndexError(translate("empty heap"));
|
||||
mp_raise_IndexError(MP_ERROR_TEXT("empty heap"));
|
||||
}
|
||||
|
||||
struct qentry *item = &heap->items[0];
|
||||
|
@ -43,7 +43,7 @@ STATIC int read_src_stream(TINF_DATA *data) {
|
||||
mp_raise_OSError(err);
|
||||
}
|
||||
if (out_sz == 0) {
|
||||
nlr_raise(mp_obj_new_exception(&mp_type_EOFError));
|
||||
mp_raise_type(&mp_type_EOFError);
|
||||
}
|
||||
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);
|
||||
if (dict_opt < 0) {
|
||||
header_error:
|
||||
mp_raise_ValueError(translate("compression header"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("compression header"));
|
||||
}
|
||||
dict_sz = 1 << dict_opt;
|
||||
} else {
|
||||
|
29
extmod/uasyncio/__init__.py
Normal file
29
extmod/uasyncio/__init__.py
Normal 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
277
extmod/uasyncio/core.py
Normal 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
31
extmod/uasyncio/event.py
Normal 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
54
extmod/uasyncio/funcs.py
Normal 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
53
extmod/uasyncio/lock.py
Normal 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()
|
13
extmod/uasyncio/manifest.py
Normal file
13
extmod/uasyncio/manifest.py
Normal 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
158
extmod/uasyncio/stream.py
Normal 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
168
extmod/uasyncio/task.py
Normal 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
|
32
extmod/vfs.c
32
extmod/vfs.c
@ -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) {
|
||||
enum { ARG_readonly, ARG_mkfs };
|
||||
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_mkfs, 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_FALSE} },
|
||||
};
|
||||
|
||||
// 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) {
|
||||
enum { ARG_file, ARG_mode, ARG_encoding };
|
||||
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_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
|
||||
@ -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 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 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
|
||||
@ -314,9 +313,11 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfs = MP_VFS_ROOT;
|
||||
} else {
|
||||
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out);
|
||||
}
|
||||
MP_STATE_VM(vfs_cur) = vfs;
|
||||
return mp_const_none;
|
||||
}
|
||||
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);
|
||||
|
||||
// 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
|
||||
|
@ -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_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_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.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[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size
|
||||
t->items[7] = seconds; // st_atime
|
||||
t->items[8] = seconds; // st_mtime
|
||||
t->items[9] = seconds; // st_ctime
|
||||
t->items[7] = seconds; // st_atime
|
||||
t->items[8] = seconds; // st_mtime
|
||||
t->items[9] = seconds; // st_ctime
|
||||
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
@ -429,7 +430,7 @@ STATIC mp_obj_t vfs_fat_setlabel(mp_obj_t self_in, mp_obj_t label_in) {
|
||||
FRESULT res = f_setlabel(&self->fatfs, label_str);
|
||||
if (res != FR_OK) {
|
||||
if (res == FR_WRITE_PROTECTED) {
|
||||
mp_raise_msg(&mp_type_OSError, translate("Read-only filesystem"));
|
||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Read-only filesystem"));
|
||||
}
|
||||
mp_raise_OSError(fresult_to_errno_table[res]);
|
||||
}
|
||||
@ -440,7 +441,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&fat_vfs_getlabel_obj,
|
||||
(mp_obj_t)&fat_vfs_setlabel_obj,
|
||||
(mp_obj_t)&mp_const_none_obj},
|
||||
MP_ROM_NONE},
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -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,
|
||||
// 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[] = {
|
||||
{ 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_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)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -25,18 +25,20 @@
|
||||
*/
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/vfs.h"
|
||||
#include "extmod/vfs_lfs.h"
|
||||
|
||||
#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[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ 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_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
|
||||
@ -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_(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 {
|
||||
mp_obj_base_t base;
|
||||
mp_vfs_blockdev_t blockdev;
|
||||
bool enable_mtime;
|
||||
vstr_t cur_dir;
|
||||
struct lfs2_config config;
|
||||
lfs2_t lfs;
|
||||
@ -109,14 +115,25 @@ typedef struct _mp_obj_vfs_lfs2_t {
|
||||
typedef struct _mp_obj_vfs_lfs2_file_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_vfs_lfs2_t *vfs;
|
||||
uint8_t mtime[8];
|
||||
lfs2_file_t file;
|
||||
struct lfs2_file_config cfg;
|
||||
struct lfs2_attr attrs[1];
|
||||
uint8_t file_buffer[0];
|
||||
} mp_obj_vfs_lfs2_file_t;
|
||||
|
||||
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);
|
||||
|
||||
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_file.c"
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -31,8 +31,10 @@
|
||||
#include "py/stream.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/objarray.h"
|
||||
#include "py/objstr.h"
|
||||
#include "py/mperrno.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) {
|
||||
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;
|
||||
vstr_init(&self->cur_dir, 16);
|
||||
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,
|
||||
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);
|
||||
@ -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) {
|
||||
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 = mp_obj_str_get_str(path_new_in);
|
||||
vstr_t path_new;
|
||||
vstr_init(&path_new, vstr_len(&self->cur_dir));
|
||||
vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir));
|
||||
vstr_add_str(&path_new, mp_obj_str_get_str(path_new_in));
|
||||
if (path[0] != '/') {
|
||||
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));
|
||||
vstr_clear(&path_new);
|
||||
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
|
||||
// and then normalise the path
|
||||
if (vstr_len(&self->cur_dir) != 1) {
|
||||
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;
|
||||
@ -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) {
|
||||
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;
|
||||
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
||||
if (ret < 0) {
|
||||
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));
|
||||
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
|
||||
@ -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[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
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[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime
|
||||
t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
|
||||
t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
|
||||
t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
|
||||
|
||||
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) {
|
||||
MP_OBJ_VFS_LFSx *self = self_in;
|
||||
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);
|
||||
if (ret == 0) {
|
||||
if (info.type == LFSx_MACRO(_TYPE_REG)) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
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);
|
||||
int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg);
|
||||
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) {
|
||||
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
|
||||
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);
|
||||
if (sz < 0) {
|
||||
*errcode = -sz;
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/mpthread.h"
|
||||
#include "extmod/vfs.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 (;;) {
|
||||
MP_THREAD_GIL_EXIT();
|
||||
struct dirent *dirent = readdir(self->dir);
|
||||
if (dirent == NULL) {
|
||||
closedir(self->dir);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
self->dir = NULL;
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
MP_THREAD_GIL_ENTER();
|
||||
const char *fn = dirent->d_name;
|
||||
|
||||
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') {
|
||||
path = ".";
|
||||
}
|
||||
MP_THREAD_GIL_EXIT();
|
||||
iter->dir = opendir(path);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
if (iter->dir == NULL) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
MP_THREAD_GIL_EXIT();
|
||||
int ret = rename(old_path, new_path);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
if (ret != 0) {
|
||||
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) {
|
||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
struct stat sb;
|
||||
int ret = stat(vfs_posix_get_path_str(self, path_in), &sb);
|
||||
if (ret != 0) {
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||
int ret;
|
||||
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));
|
||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
|
||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);
|
||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev);
|
||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink);
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid);
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid);
|
||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size);
|
||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime);
|
||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime);
|
||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime);
|
||||
t->items[1] = mp_obj_new_int_from_uint(sb.st_ino);
|
||||
t->items[2] = mp_obj_new_int_from_uint(sb.st_dev);
|
||||
t->items[3] = mp_obj_new_int_from_uint(sb.st_nlink);
|
||||
t->items[4] = mp_obj_new_int_from_uint(sb.st_uid);
|
||||
t->items[5] = mp_obj_new_int_from_uint(sb.st_gid);
|
||||
t->items[6] = mp_obj_new_int_from_uint(sb.st_size);
|
||||
t->items[7] = mp_obj_new_int_from_uint(sb.st_atime);
|
||||
t->items[8] = mp_obj_new_int_from_uint(sb.st_mtime);
|
||||
t->items[9] = mp_obj_new_int_from_uint(sb.st_ctime);
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
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);
|
||||
STRUCT_STATVFS sb;
|
||||
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||
int ret = STATVFS(path, &sb);
|
||||
if (ret != 0) {
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
int ret;
|
||||
MP_HAL_RETRY_SYSCALL(ret, STATVFS(path, &sb), mp_raise_OSError(err));
|
||||
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[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);
|
||||
|
@ -3,14 +3,17 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "py/mpthread.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "extmod/vfs_posix.h"
|
||||
#include "supervisor/shared/translate.h"
|
||||
|
||||
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX
|
||||
#if (defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX) || (defined(MICROPY_VFS_POSIX_FILE) && MICROPY_VFS_POSIX_FILE)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define fsync _commit
|
||||
@ -24,7 +27,7 @@ typedef struct _mp_obj_vfs_posix_file_t {
|
||||
#ifdef MICROPY_CPYTHON_COMPAT
|
||||
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
|
||||
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
|
||||
@ -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);
|
||||
int fd = open(fname, mode_x | mode_rw, 0644);
|
||||
if (fd == -1) {
|
||||
mp_raise_OSError(errno);
|
||||
}
|
||||
int fd;
|
||||
MP_HAL_RETRY_SYSCALL(fd, open(fname, mode_x | mode_rw, 0644), mp_raise_OSError(err));
|
||||
o->fd = fd;
|
||||
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 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)} },
|
||||
};
|
||||
|
||||
@ -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) {
|
||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
check_fd_is_open(o);
|
||||
mp_int_t r = read(o->fd, buf, size);
|
||||
if (r == -1) {
|
||||
*errcode = errno;
|
||||
ssize_t r;
|
||||
MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
|
||||
*errcode = err;
|
||||
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) {
|
||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
check_fd_is_open(o);
|
||||
mp_int_t r = write(o->fd, buf, size);
|
||||
while (r == -1 && errno == EINTR) {
|
||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
||||
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;
|
||||
ssize_t r;
|
||||
MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
|
||||
*errcode = err;
|
||||
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) {
|
||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||
check_fd_is_open(o);
|
||||
switch (request) {
|
||||
case MP_STREAM_FLUSH:
|
||||
if (fsync(o->fd) < 0) {
|
||||
*errcode = errno;
|
||||
case MP_STREAM_FLUSH: {
|
||||
int ret;
|
||||
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 0;
|
||||
}
|
||||
case MP_STREAM_SEEK: {
|
||||
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);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
if (off == (off_t)-1) {
|
||||
*errcode = errno;
|
||||
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;
|
||||
}
|
||||
case MP_STREAM_CLOSE:
|
||||
MP_THREAD_GIL_EXIT();
|
||||
close(o->fd);
|
||||
MP_THREAD_GIL_ENTER();
|
||||
#ifdef MICROPY_CPYTHON_COMPAT
|
||||
o->fd = -1;
|
||||
#endif
|
||||
return 0;
|
||||
case MP_STREAM_GET_FILENO:
|
||||
return o->fd;
|
||||
default:
|
||||
*errcode = EINVAL;
|
||||
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_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
|
||||
|
||||
#endif // MICROPY_VFS_POSIX
|
||||
#endif // MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_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) {
|
||||
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
|
||||
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));
|
||||
rf->file = mp_vfs_open(1, &arg, (mp_map_t *)&mp_const_empty_map);
|
||||
mp_obj_t args[2] = {
|
||||
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;
|
||||
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
||||
if (errcode != 0) {
|
||||
|
13
lib/embed/__errno.c
Normal file
13
lib/embed/__errno.c
Normal 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;
|
||||
}
|
@ -5,5 +5,5 @@
|
||||
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"));
|
||||
}
|
||||
|
@ -173,6 +173,25 @@ char *strcpy(char *dest, const char *src) {
|
||||
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
|
||||
char *stpcpy(char *dest, const char *src) {
|
||||
while (*src) {
|
||||
|
@ -23,15 +23,15 @@
|
||||
|
||||
// dpgeorge: pio2 was double in original implementation of asinf
|
||||
static const float
|
||||
pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
|
||||
pio2_lo = 7.5497894159e-08; /* 0x33a22168 */
|
||||
pio2_hi = 1.5707962513e+00f, /* 0x3fc90fda */
|
||||
pio2_lo = 7.5497894159e-08f; /* 0x33a22168 */
|
||||
|
||||
static const float
|
||||
/* coefficients for R(x^2) */
|
||||
pS0 = 1.6666586697e-01,
|
||||
pS1 = -4.2743422091e-02,
|
||||
pS2 = -8.6563630030e-03,
|
||||
qS1 = -7.0662963390e-01;
|
||||
pS0 = 1.6666586697e-01f,
|
||||
pS1 = -4.2743422091e-02f,
|
||||
pS2 = -8.6563630030e-03f,
|
||||
qS1 = -7.0662963390e-01f;
|
||||
|
||||
static float R(float z)
|
||||
{
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "libm.h"
|
||||
|
||||
static const float
|
||||
pi = 3.1415927410e+00, /* 0x40490fdb */
|
||||
pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */
|
||||
pi = 3.1415927410e+00f, /* 0x40490fdb */
|
||||
pi_lo = -8.7422776573e-08f; /* 0xb3bbbd2e */
|
||||
|
||||
float atan2f(float y, float x)
|
||||
{
|
||||
|
@ -23,25 +23,25 @@
|
||||
#include "libm.h"
|
||||
|
||||
static const float atanhi[] = {
|
||||
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
|
||||
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
|
||||
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
|
||||
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
|
||||
4.6364760399e-01f, /* atan(0.5)hi 0x3eed6338 */
|
||||
7.8539812565e-01f, /* atan(1.0)hi 0x3f490fda */
|
||||
9.8279368877e-01f, /* atan(1.5)hi 0x3f7b985e */
|
||||
1.5707962513e+00f, /* atan(inf)hi 0x3fc90fda */
|
||||
};
|
||||
|
||||
static const float atanlo[] = {
|
||||
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
|
||||
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
|
||||
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
|
||||
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
|
||||
5.0121582440e-09f, /* atan(0.5)lo 0x31ac3769 */
|
||||
3.7748947079e-08f, /* atan(1.0)lo 0x33222168 */
|
||||
3.4473217170e-08f, /* atan(1.5)lo 0x33140fb4 */
|
||||
7.5497894159e-08f, /* atan(inf)lo 0x33a22168 */
|
||||
};
|
||||
|
||||
static const float aT[] = {
|
||||
3.3333328366e-01,
|
||||
-1.9999158382e-01,
|
||||
1.4253635705e-01,
|
||||
-1.0648017377e-01,
|
||||
6.1687607318e-02,
|
||||
3.3333328366e-01f,
|
||||
-1.9999158382e-01f,
|
||||
1.4253635705e-01f,
|
||||
-1.0648017377e-01f,
|
||||
6.1687607318e-02f,
|
||||
};
|
||||
|
||||
float atanf(float x)
|
||||
|
@ -93,16 +93,16 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
zero = 0.0000000000e+00, /* 0x00000000 */
|
||||
half = 5.0000000000e-01, /* 0x3f000000 */
|
||||
two8 = 2.5600000000e+02, /* 0x43800000 */
|
||||
invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
|
||||
pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
|
||||
pio2_1t = 1.0804334124e-05, /* 0x37354443 */
|
||||
pio2_2 = 1.0804273188e-05, /* 0x37354400 */
|
||||
pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
|
||||
pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
|
||||
pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
|
||||
zero = 0.0000000000e+00f, /* 0x00000000 */
|
||||
half = 5.0000000000e-01f, /* 0x3f000000 */
|
||||
two8 = 2.5600000000e+02f, /* 0x43800000 */
|
||||
invpio2 = 6.3661980629e-01f, /* 0x3f22f984 */
|
||||
pio2_1 = 1.5707855225e+00f, /* 0x3fc90f80 */
|
||||
pio2_1t = 1.0804334124e-05f, /* 0x37354443 */
|
||||
pio2_2 = 1.0804273188e-05f, /* 0x37354400 */
|
||||
pio2_2t = 6.0770999344e-11f, /* 0x2e85a308 */
|
||||
pio2_3 = 6.0770943833e-11f, /* 0x2e85a300 */
|
||||
pio2_3t = 6.1232342629e-17f; /* 0x248d3132 */
|
||||
|
||||
#ifdef __STDC__
|
||||
__int32_t __ieee754_rem_pio2f(float x, float *y)
|
||||
|
@ -25,9 +25,9 @@
|
||||
#include "fdlibm.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
static const float one = 1.0, tiny=1.0e-30;
|
||||
static const float one = 1.0f, tiny=1.0e-30f;
|
||||
#else
|
||||
static float one = 1.0, tiny=1.0e-30;
|
||||
static float one = 1.0f, tiny=1.0e-30f;
|
||||
#endif
|
||||
|
||||
// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined
|
||||
|
@ -33,77 +33,77 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
two23= 8.3886080000e+06, /* 0x4b000000 */
|
||||
half= 5.0000000000e-01, /* 0x3f000000 */
|
||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
||||
pi = 3.1415927410e+00, /* 0x40490fdb */
|
||||
a0 = 7.7215664089e-02, /* 0x3d9e233f */
|
||||
a1 = 3.2246702909e-01, /* 0x3ea51a66 */
|
||||
a2 = 6.7352302372e-02, /* 0x3d89f001 */
|
||||
a3 = 2.0580807701e-02, /* 0x3ca89915 */
|
||||
a4 = 7.3855509982e-03, /* 0x3bf2027e */
|
||||
a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
|
||||
a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
|
||||
a7 = 5.1006977446e-04, /* 0x3a05b634 */
|
||||
a8 = 2.2086278477e-04, /* 0x39679767 */
|
||||
a9 = 1.0801156895e-04, /* 0x38e28445 */
|
||||
a10 = 2.5214456400e-05, /* 0x37d383a2 */
|
||||
a11 = 4.4864096708e-05, /* 0x383c2c75 */
|
||||
tc = 1.4616321325e+00, /* 0x3fbb16c3 */
|
||||
tf = -1.2148628384e-01, /* 0xbdf8cdcd */
|
||||
two23= 8.3886080000e+06f, /* 0x4b000000 */
|
||||
half= 5.0000000000e-01f, /* 0x3f000000 */
|
||||
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||
pi = 3.1415927410e+00f, /* 0x40490fdb */
|
||||
a0 = 7.7215664089e-02f, /* 0x3d9e233f */
|
||||
a1 = 3.2246702909e-01f, /* 0x3ea51a66 */
|
||||
a2 = 6.7352302372e-02f, /* 0x3d89f001 */
|
||||
a3 = 2.0580807701e-02f, /* 0x3ca89915 */
|
||||
a4 = 7.3855509982e-03f, /* 0x3bf2027e */
|
||||
a5 = 2.8905137442e-03f, /* 0x3b3d6ec6 */
|
||||
a6 = 1.1927076848e-03f, /* 0x3a9c54a1 */
|
||||
a7 = 5.1006977446e-04f, /* 0x3a05b634 */
|
||||
a8 = 2.2086278477e-04f, /* 0x39679767 */
|
||||
a9 = 1.0801156895e-04f, /* 0x38e28445 */
|
||||
a10 = 2.5214456400e-05f, /* 0x37d383a2 */
|
||||
a11 = 4.4864096708e-05f, /* 0x383c2c75 */
|
||||
tc = 1.4616321325e+00f, /* 0x3fbb16c3 */
|
||||
tf = -1.2148628384e-01f, /* 0xbdf8cdcd */
|
||||
/* tt = -(tail of tf) */
|
||||
tt = 6.6971006518e-09, /* 0x31e61c52 */
|
||||
t0 = 4.8383611441e-01, /* 0x3ef7b95e */
|
||||
t1 = -1.4758771658e-01, /* 0xbe17213c */
|
||||
t2 = 6.4624942839e-02, /* 0x3d845a15 */
|
||||
t3 = -3.2788541168e-02, /* 0xbd064d47 */
|
||||
t4 = 1.7970675603e-02, /* 0x3c93373d */
|
||||
t5 = -1.0314224288e-02, /* 0xbc28fcfe */
|
||||
t6 = 6.1005386524e-03, /* 0x3bc7e707 */
|
||||
t7 = -3.6845202558e-03, /* 0xbb7177fe */
|
||||
t8 = 2.2596477065e-03, /* 0x3b141699 */
|
||||
t9 = -1.4034647029e-03, /* 0xbab7f476 */
|
||||
t10 = 8.8108185446e-04, /* 0x3a66f867 */
|
||||
t11 = -5.3859531181e-04, /* 0xba0d3085 */
|
||||
t12 = 3.1563205994e-04, /* 0x39a57b6b */
|
||||
t13 = -3.1275415677e-04, /* 0xb9a3f927 */
|
||||
t14 = 3.3552918467e-04, /* 0x39afe9f7 */
|
||||
u0 = -7.7215664089e-02, /* 0xbd9e233f */
|
||||
u1 = 6.3282704353e-01, /* 0x3f2200f4 */
|
||||
u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
|
||||
u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
|
||||
u4 = 2.2896373272e-01, /* 0x3e6a7578 */
|
||||
u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
|
||||
v1 = 2.4559779167e+00, /* 0x401d2ebe */
|
||||
v2 = 2.1284897327e+00, /* 0x4008392d */
|
||||
v3 = 7.6928514242e-01, /* 0x3f44efdf */
|
||||
v4 = 1.0422264785e-01, /* 0x3dd572af */
|
||||
v5 = 3.2170924824e-03, /* 0x3b52d5db */
|
||||
s0 = -7.7215664089e-02, /* 0xbd9e233f */
|
||||
s1 = 2.1498242021e-01, /* 0x3e5c245a */
|
||||
s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
|
||||
s3 = 1.4635047317e-01, /* 0x3e15dce6 */
|
||||
s4 = 2.6642270386e-02, /* 0x3cda40e4 */
|
||||
s5 = 1.8402845599e-03, /* 0x3af135b4 */
|
||||
s6 = 3.1947532989e-05, /* 0x3805ff67 */
|
||||
r1 = 1.3920053244e+00, /* 0x3fb22d3b */
|
||||
r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
|
||||
r3 = 1.7193385959e-01, /* 0x3e300f6e */
|
||||
r4 = 1.8645919859e-02, /* 0x3c98bf54 */
|
||||
r5 = 7.7794247773e-04, /* 0x3a4beed6 */
|
||||
r6 = 7.3266842264e-06, /* 0x36f5d7bd */
|
||||
w0 = 4.1893854737e-01, /* 0x3ed67f1d */
|
||||
w1 = 8.3333335817e-02, /* 0x3daaaaab */
|
||||
w2 = -2.7777778450e-03, /* 0xbb360b61 */
|
||||
w3 = 7.9365057172e-04, /* 0x3a500cfd */
|
||||
w4 = -5.9518753551e-04, /* 0xba1c065c */
|
||||
w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
|
||||
w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
|
||||
tt = 6.6971006518e-09f, /* 0x31e61c52 */
|
||||
t0 = 4.8383611441e-01f, /* 0x3ef7b95e */
|
||||
t1 = -1.4758771658e-01f, /* 0xbe17213c */
|
||||
t2 = 6.4624942839e-02f, /* 0x3d845a15 */
|
||||
t3 = -3.2788541168e-02f, /* 0xbd064d47 */
|
||||
t4 = 1.7970675603e-02f, /* 0x3c93373d */
|
||||
t5 = -1.0314224288e-02f, /* 0xbc28fcfe */
|
||||
t6 = 6.1005386524e-03f, /* 0x3bc7e707 */
|
||||
t7 = -3.6845202558e-03f, /* 0xbb7177fe */
|
||||
t8 = 2.2596477065e-03f, /* 0x3b141699 */
|
||||
t9 = -1.4034647029e-03f, /* 0xbab7f476 */
|
||||
t10 = 8.8108185446e-04f, /* 0x3a66f867 */
|
||||
t11 = -5.3859531181e-04f, /* 0xba0d3085 */
|
||||
t12 = 3.1563205994e-04f, /* 0x39a57b6b */
|
||||
t13 = -3.1275415677e-04f, /* 0xb9a3f927 */
|
||||
t14 = 3.3552918467e-04f, /* 0x39afe9f7 */
|
||||
u0 = -7.7215664089e-02f, /* 0xbd9e233f */
|
||||
u1 = 6.3282704353e-01f, /* 0x3f2200f4 */
|
||||
u2 = 1.4549225569e+00f, /* 0x3fba3ae7 */
|
||||
u3 = 9.7771751881e-01f, /* 0x3f7a4bb2 */
|
||||
u4 = 2.2896373272e-01f, /* 0x3e6a7578 */
|
||||
u5 = 1.3381091878e-02f, /* 0x3c5b3c5e */
|
||||
v1 = 2.4559779167e+00f, /* 0x401d2ebe */
|
||||
v2 = 2.1284897327e+00f, /* 0x4008392d */
|
||||
v3 = 7.6928514242e-01f, /* 0x3f44efdf */
|
||||
v4 = 1.0422264785e-01f, /* 0x3dd572af */
|
||||
v5 = 3.2170924824e-03f, /* 0x3b52d5db */
|
||||
s0 = -7.7215664089e-02f, /* 0xbd9e233f */
|
||||
s1 = 2.1498242021e-01f, /* 0x3e5c245a */
|
||||
s2 = 3.2577878237e-01f, /* 0x3ea6cc7a */
|
||||
s3 = 1.4635047317e-01f, /* 0x3e15dce6 */
|
||||
s4 = 2.6642270386e-02f, /* 0x3cda40e4 */
|
||||
s5 = 1.8402845599e-03f, /* 0x3af135b4 */
|
||||
s6 = 3.1947532989e-05f, /* 0x3805ff67 */
|
||||
r1 = 1.3920053244e+00f, /* 0x3fb22d3b */
|
||||
r2 = 7.2193557024e-01f, /* 0x3f38d0c5 */
|
||||
r3 = 1.7193385959e-01f, /* 0x3e300f6e */
|
||||
r4 = 1.8645919859e-02f, /* 0x3c98bf54 */
|
||||
r5 = 7.7794247773e-04f, /* 0x3a4beed6 */
|
||||
r6 = 7.3266842264e-06f, /* 0x36f5d7bd */
|
||||
w0 = 4.1893854737e-01f, /* 0x3ed67f1d */
|
||||
w1 = 8.3333335817e-02f, /* 0x3daaaaab */
|
||||
w2 = -2.7777778450e-03f, /* 0xbb360b61 */
|
||||
w3 = 7.9365057172e-04f, /* 0x3a500cfd */
|
||||
w4 = -5.9518753551e-04f, /* 0xba1c065c */
|
||||
w5 = 8.3633989561e-04f, /* 0x3a5b3dd2 */
|
||||
w6 = -1.6309292987e-03f; /* 0xbad5c4e8 */
|
||||
|
||||
#ifdef __STDC__
|
||||
static const float zero= 0.0000000000e+00;
|
||||
static const float zero= 0.0000000000e+00f;
|
||||
#else
|
||||
static float zero= 0.0000000000e+00;
|
||||
static float zero= 0.0000000000e+00f;
|
||||
#endif
|
||||
|
||||
#ifdef __STDC__
|
||||
|
@ -29,13 +29,13 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
||||
C1 = 4.1666667908e-02, /* 0x3d2aaaab */
|
||||
C2 = -1.3888889225e-03, /* 0xbab60b61 */
|
||||
C3 = 2.4801587642e-05, /* 0x37d00d01 */
|
||||
C4 = -2.7557314297e-07, /* 0xb493f27c */
|
||||
C5 = 2.0875723372e-09, /* 0x310f74f6 */
|
||||
C6 = -1.1359647598e-11; /* 0xad47d74e */
|
||||
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||
C1 = 4.1666667908e-02f, /* 0x3d2aaaab */
|
||||
C2 = -1.3888889225e-03f, /* 0xbab60b61 */
|
||||
C3 = 2.4801587642e-05f, /* 0x37d00d01 */
|
||||
C4 = -2.7557314297e-07f, /* 0xb493f27c */
|
||||
C5 = 2.0875723372e-09f, /* 0x310f74f6 */
|
||||
C6 = -1.1359647598e-11f; /* 0xad47d74e */
|
||||
|
||||
#ifdef __STDC__
|
||||
float __kernel_cosf(float x, float y)
|
||||
|
@ -38,17 +38,17 @@ static const float PIo2[] = {
|
||||
#else
|
||||
static float PIo2[] = {
|
||||
#endif
|
||||
1.5703125000e+00, /* 0x3fc90000 */
|
||||
4.5776367188e-04, /* 0x39f00000 */
|
||||
2.5987625122e-05, /* 0x37da0000 */
|
||||
7.5437128544e-08, /* 0x33a20000 */
|
||||
6.0026650317e-11, /* 0x2e840000 */
|
||||
7.3896444519e-13, /* 0x2b500000 */
|
||||
5.3845816694e-15, /* 0x27c20000 */
|
||||
5.6378512969e-18, /* 0x22d00000 */
|
||||
8.3009228831e-20, /* 0x1fc40000 */
|
||||
3.2756352257e-22, /* 0x1bc60000 */
|
||||
6.3331015649e-25, /* 0x17440000 */
|
||||
1.5703125000e+00f, /* 0x3fc90000 */
|
||||
4.5776367188e-04f, /* 0x39f00000 */
|
||||
2.5987625122e-05f, /* 0x37da0000 */
|
||||
7.5437128544e-08f, /* 0x33a20000 */
|
||||
6.0026650317e-11f, /* 0x2e840000 */
|
||||
7.3896444519e-13f, /* 0x2b500000 */
|
||||
5.3845816694e-15f, /* 0x27c20000 */
|
||||
5.6378512969e-18f, /* 0x22d00000 */
|
||||
8.3009228831e-20f, /* 0x1fc40000 */
|
||||
3.2756352257e-22f, /* 0x1bc60000 */
|
||||
6.3331015649e-25f, /* 0x17440000 */
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
@ -56,10 +56,10 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
zero = 0.0,
|
||||
one = 1.0,
|
||||
two8 = 2.5600000000e+02, /* 0x43800000 */
|
||||
twon8 = 3.9062500000e-03; /* 0x3b800000 */
|
||||
zero = 0.0f,
|
||||
one = 1.0f,
|
||||
two8 = 2.5600000000e+02f, /* 0x43800000 */
|
||||
twon8 = 3.9062500000e-03f; /* 0x3b800000 */
|
||||
|
||||
#ifdef __STDC__
|
||||
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __uint8_t *ipio2)
|
||||
|
@ -29,13 +29,13 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
half = 5.0000000000e-01,/* 0x3f000000 */
|
||||
S1 = -1.6666667163e-01, /* 0xbe2aaaab */
|
||||
S2 = 8.3333337680e-03, /* 0x3c088889 */
|
||||
S3 = -1.9841270114e-04, /* 0xb9500d01 */
|
||||
S4 = 2.7557314297e-06, /* 0x3638ef1b */
|
||||
S5 = -2.5050759689e-08, /* 0xb2d72f34 */
|
||||
S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
|
||||
half = 5.0000000000e-01f,/* 0x3f000000 */
|
||||
S1 = -1.6666667163e-01f, /* 0xbe2aaaab */
|
||||
S2 = 8.3333337680e-03f, /* 0x3c088889 */
|
||||
S3 = -1.9841270114e-04f, /* 0xb9500d01 */
|
||||
S4 = 2.7557314297e-06f, /* 0x3638ef1b */
|
||||
S5 = -2.5050759689e-08f, /* 0xb2d72f34 */
|
||||
S6 = 1.5896910177e-10f; /* 0x2f2ec9d3 */
|
||||
|
||||
#ifdef __STDC__
|
||||
float __kernel_sinf(float x, float y, int iy)
|
||||
|
@ -28,23 +28,23 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
||||
pio4 = 7.8539812565e-01, /* 0x3f490fda */
|
||||
pio4lo= 3.7748947079e-08, /* 0x33222168 */
|
||||
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||
pio4 = 7.8539812565e-01f, /* 0x3f490fda */
|
||||
pio4lo= 3.7748947079e-08f, /* 0x33222168 */
|
||||
T[] = {
|
||||
3.3333334327e-01, /* 0x3eaaaaab */
|
||||
1.3333334029e-01, /* 0x3e088889 */
|
||||
5.3968254477e-02, /* 0x3d5d0dd1 */
|
||||
2.1869488060e-02, /* 0x3cb327a4 */
|
||||
8.8632395491e-03, /* 0x3c11371f */
|
||||
3.5920790397e-03, /* 0x3b6b6916 */
|
||||
1.4562094584e-03, /* 0x3abede48 */
|
||||
5.8804126456e-04, /* 0x3a1a26c8 */
|
||||
2.4646313977e-04, /* 0x398137b9 */
|
||||
7.8179444245e-05, /* 0x38a3f445 */
|
||||
7.1407252108e-05, /* 0x3895c07a */
|
||||
-1.8558637748e-05, /* 0xb79bae5f */
|
||||
2.5907305826e-05, /* 0x37d95384 */
|
||||
3.3333334327e-01f, /* 0x3eaaaaab */
|
||||
1.3333334029e-01f, /* 0x3e088889 */
|
||||
5.3968254477e-02f, /* 0x3d5d0dd1 */
|
||||
2.1869488060e-02f, /* 0x3cb327a4 */
|
||||
8.8632395491e-03f, /* 0x3c11371f */
|
||||
3.5920790397e-03f, /* 0x3b6b6916 */
|
||||
1.4562094584e-03f, /* 0x3abede48 */
|
||||
5.8804126456e-04f, /* 0x3a1a26c8 */
|
||||
2.4646313977e-04f, /* 0x398137b9 */
|
||||
7.8179444245e-05f, /* 0x38a3f445 */
|
||||
7.1407252108e-05f, /* 0x3895c07a */
|
||||
-1.8558637748e-05f, /* 0xb79bae5f */
|
||||
2.5907305826e-05f, /* 0x37d95384 */
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
|
@ -21,13 +21,13 @@
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
|
||||
static const float
|
||||
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
|
||||
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
|
||||
ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
|
||||
ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
|
||||
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
|
||||
Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
|
||||
Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
|
||||
Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
|
||||
Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
|
||||
Lg1 = 0xaaaaaa.0p-24f, /* 0.66666662693 */
|
||||
Lg2 = 0xccce13.0p-25f, /* 0.40000972152 */
|
||||
Lg3 = 0x91e9ee.0p-25f, /* 0.28498786688 */
|
||||
Lg4 = 0xf89e26.0p-26f; /* 0.24279078841 */
|
||||
|
||||
float log1pf(float x)
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ float copysignf(float x, float y) {
|
||||
}
|
||||
#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; }
|
||||
#undef _M_LN2
|
||||
static const float _M_LN2 = 0.6931472;
|
||||
@ -142,34 +142,34 @@ float scalbnf(float x, int n)
|
||||
*/
|
||||
|
||||
static const float
|
||||
bp[] = {1.0, 1.5,},
|
||||
dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
|
||||
dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
|
||||
two24 = 16777216.0, /* 0x4b800000 */
|
||||
huge = 1.0e30,
|
||||
tiny = 1.0e-30,
|
||||
bp[] = {1.0f, 1.5f,},
|
||||
dp_h[] = { 0.0f, 5.84960938e-01f,}, /* 0x3f15c000 */
|
||||
dp_l[] = { 0.0f, 1.56322085e-06f,}, /* 0x35d1cfdc */
|
||||
two24 = 16777216.0f, /* 0x4b800000 */
|
||||
huge = 1.0e30f,
|
||||
tiny = 1.0e-30f,
|
||||
/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
|
||||
L1 = 6.0000002384e-01, /* 0x3f19999a */
|
||||
L2 = 4.2857143283e-01, /* 0x3edb6db7 */
|
||||
L3 = 3.3333334327e-01, /* 0x3eaaaaab */
|
||||
L4 = 2.7272811532e-01, /* 0x3e8ba305 */
|
||||
L5 = 2.3066075146e-01, /* 0x3e6c3255 */
|
||||
L6 = 2.0697501302e-01, /* 0x3e53f142 */
|
||||
P1 = 1.6666667163e-01, /* 0x3e2aaaab */
|
||||
P2 = -2.7777778450e-03, /* 0xbb360b61 */
|
||||
P3 = 6.6137559770e-05, /* 0x388ab355 */
|
||||
P4 = -1.6533901999e-06, /* 0xb5ddea0e */
|
||||
P5 = 4.1381369442e-08, /* 0x3331bb4c */
|
||||
lg2 = 6.9314718246e-01, /* 0x3f317218 */
|
||||
lg2_h = 6.93145752e-01, /* 0x3f317200 */
|
||||
lg2_l = 1.42860654e-06, /* 0x35bfbe8c */
|
||||
ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
|
||||
cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
|
||||
cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */
|
||||
cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */
|
||||
ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
|
||||
ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
|
||||
ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
|
||||
L1 = 6.0000002384e-01f, /* 0x3f19999a */
|
||||
L2 = 4.2857143283e-01f, /* 0x3edb6db7 */
|
||||
L3 = 3.3333334327e-01f, /* 0x3eaaaaab */
|
||||
L4 = 2.7272811532e-01f, /* 0x3e8ba305 */
|
||||
L5 = 2.3066075146e-01f, /* 0x3e6c3255 */
|
||||
L6 = 2.0697501302e-01f, /* 0x3e53f142 */
|
||||
P1 = 1.6666667163e-01f, /* 0x3e2aaaab */
|
||||
P2 = -2.7777778450e-03f, /* 0xbb360b61 */
|
||||
P3 = 6.6137559770e-05f, /* 0x388ab355 */
|
||||
P4 = -1.6533901999e-06f, /* 0xb5ddea0e */
|
||||
P5 = 4.1381369442e-08f, /* 0x3331bb4c */
|
||||
lg2 = 6.9314718246e-01f, /* 0x3f317218 */
|
||||
lg2_h = 6.93145752e-01f, /* 0x3f317200 */
|
||||
lg2_l = 1.42860654e-06f, /* 0x35bfbe8c */
|
||||
ovt = 4.2995665694e-08f, /* -(128-log2(ovfl+.5ulp)) */
|
||||
cp = 9.6179670095e-01f, /* 0x3f76384f =2/(3ln2) */
|
||||
cp_h = 9.6191406250e-01f, /* 0x3f764000 =12b cp */
|
||||
cp_l = -1.1736857402e-04f, /* 0xb8f623c6 =tail of cp_h */
|
||||
ivln2 = 1.4426950216e+00f, /* 0x3fb8aa3b =1/ln2 */
|
||||
ivln2_h = 1.4426879883e+00f, /* 0x3fb8aa00 =16b 1/ln2*/
|
||||
ivln2_l = 7.0526075433e-06f; /* 0x36eca570 =1/ln2 tail*/
|
||||
|
||||
float powf(float x, float y)
|
||||
{
|
||||
@ -406,7 +406,7 @@ float powf(float x, float y)
|
||||
*/
|
||||
|
||||
static const float
|
||||
half[2] = {0.5,-0.5},
|
||||
half[2] = {0.5f,-0.5f},
|
||||
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
|
||||
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
|
||||
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
|
||||
@ -445,7 +445,7 @@ float expf(float x)
|
||||
/* argument reduction */
|
||||
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
|
||||
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
|
||||
k = invln2*x + half[sign];
|
||||
k = (int)(invln2*x + half[sign]);
|
||||
else
|
||||
k = 1 - sign - sign;
|
||||
hi = x - k*ln2hi; /* k*ln2hi is exact here */
|
||||
@ -492,17 +492,17 @@ float expf(float x)
|
||||
*/
|
||||
|
||||
static const float
|
||||
o_threshold = 8.8721679688e+01, /* 0x42b17180 */
|
||||
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
|
||||
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
|
||||
o_threshold = 8.8721679688e+01f, /* 0x42b17180 */
|
||||
ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
|
||||
ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
|
||||
//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
|
||||
/*
|
||||
* 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
|
||||
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
|
||||
*/
|
||||
Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
|
||||
Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
|
||||
Q1 = -3.3333212137e-2f, /* -0x888868.0p-28 */
|
||||
Q2 = 1.5807170421e-3f; /* 0xcf3010.0p-33 */
|
||||
|
||||
float expm1f(float x)
|
||||
{
|
||||
@ -536,7 +536,7 @@ float expm1f(float x)
|
||||
k = -1;
|
||||
}
|
||||
} else {
|
||||
k = invln2*x + (sign ? -0.5f : 0.5f);
|
||||
k = (int)(invln2*x + (sign ? -0.5f : 0.5f));
|
||||
t = k;
|
||||
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
|
||||
lo = t*ln2_lo;
|
||||
|
@ -35,79 +35,79 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
tiny = 1e-30,
|
||||
half= 5.0000000000e-01, /* 0x3F000000 */
|
||||
one = 1.0000000000e+00, /* 0x3F800000 */
|
||||
two = 2.0000000000e+00, /* 0x40000000 */
|
||||
tiny = 1e-30f,
|
||||
half= 5.0000000000e-01f, /* 0x3F000000 */
|
||||
one = 1.0000000000e+00f, /* 0x3F800000 */
|
||||
two = 2.0000000000e+00f, /* 0x40000000 */
|
||||
/* c = (subfloat)0.84506291151 */
|
||||
erx = 8.4506291151e-01, /* 0x3f58560b */
|
||||
erx = 8.4506291151e-01f, /* 0x3f58560b */
|
||||
/*
|
||||
* Coefficients for approximation to erf on [0,0.84375]
|
||||
*/
|
||||
efx = 1.2837916613e-01, /* 0x3e0375d4 */
|
||||
efx8= 1.0270333290e+00, /* 0x3f8375d4 */
|
||||
pp0 = 1.2837916613e-01, /* 0x3e0375d4 */
|
||||
pp1 = -3.2504209876e-01, /* 0xbea66beb */
|
||||
pp2 = -2.8481749818e-02, /* 0xbce9528f */
|
||||
pp3 = -5.7702702470e-03, /* 0xbbbd1489 */
|
||||
pp4 = -2.3763017452e-05, /* 0xb7c756b1 */
|
||||
qq1 = 3.9791721106e-01, /* 0x3ecbbbce */
|
||||
qq2 = 6.5022252500e-02, /* 0x3d852a63 */
|
||||
qq3 = 5.0813062117e-03, /* 0x3ba68116 */
|
||||
qq4 = 1.3249473704e-04, /* 0x390aee49 */
|
||||
qq5 = -3.9602282413e-06, /* 0xb684e21a */
|
||||
efx = 1.2837916613e-01f, /* 0x3e0375d4 */
|
||||
efx8= 1.0270333290e+00f, /* 0x3f8375d4 */
|
||||
pp0 = 1.2837916613e-01f, /* 0x3e0375d4 */
|
||||
pp1 = -3.2504209876e-01f, /* 0xbea66beb */
|
||||
pp2 = -2.8481749818e-02f, /* 0xbce9528f */
|
||||
pp3 = -5.7702702470e-03f, /* 0xbbbd1489 */
|
||||
pp4 = -2.3763017452e-05f, /* 0xb7c756b1 */
|
||||
qq1 = 3.9791721106e-01f, /* 0x3ecbbbce */
|
||||
qq2 = 6.5022252500e-02f, /* 0x3d852a63 */
|
||||
qq3 = 5.0813062117e-03f, /* 0x3ba68116 */
|
||||
qq4 = 1.3249473704e-04f, /* 0x390aee49 */
|
||||
qq5 = -3.9602282413e-06f, /* 0xb684e21a */
|
||||
/*
|
||||
* Coefficients for approximation to erf in [0.84375,1.25]
|
||||
*/
|
||||
pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */
|
||||
pa1 = 4.1485610604e-01, /* 0x3ed46805 */
|
||||
pa2 = -3.7220788002e-01, /* 0xbebe9208 */
|
||||
pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */
|
||||
pa4 = -1.1089469492e-01, /* 0xbde31cc2 */
|
||||
pa5 = 3.5478305072e-02, /* 0x3d1151b3 */
|
||||
pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */
|
||||
qa1 = 1.0642088205e-01, /* 0x3dd9f331 */
|
||||
qa2 = 5.4039794207e-01, /* 0x3f0a5785 */
|
||||
qa3 = 7.1828655899e-02, /* 0x3d931ae7 */
|
||||
qa4 = 1.2617121637e-01, /* 0x3e013307 */
|
||||
qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */
|
||||
qa6 = 1.1984500103e-02, /* 0x3c445aa3 */
|
||||
pa0 = -2.3621185683e-03f, /* 0xbb1acdc6 */
|
||||
pa1 = 4.1485610604e-01f, /* 0x3ed46805 */
|
||||
pa2 = -3.7220788002e-01f, /* 0xbebe9208 */
|
||||
pa3 = 3.1834661961e-01f, /* 0x3ea2fe54 */
|
||||
pa4 = -1.1089469492e-01f, /* 0xbde31cc2 */
|
||||
pa5 = 3.5478305072e-02f, /* 0x3d1151b3 */
|
||||
pa6 = -2.1663755178e-03f, /* 0xbb0df9c0 */
|
||||
qa1 = 1.0642088205e-01f, /* 0x3dd9f331 */
|
||||
qa2 = 5.4039794207e-01f, /* 0x3f0a5785 */
|
||||
qa3 = 7.1828655899e-02f, /* 0x3d931ae7 */
|
||||
qa4 = 1.2617121637e-01f, /* 0x3e013307 */
|
||||
qa5 = 1.3637083583e-02f, /* 0x3c5f6e13 */
|
||||
qa6 = 1.1984500103e-02f, /* 0x3c445aa3 */
|
||||
/*
|
||||
* Coefficients for approximation to erfc in [1.25,1/0.35]
|
||||
*/
|
||||
ra0 = -9.8649440333e-03, /* 0xbc21a093 */
|
||||
ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */
|
||||
ra2 = -1.0558626175e+01, /* 0xc128f022 */
|
||||
ra3 = -6.2375331879e+01, /* 0xc2798057 */
|
||||
ra4 = -1.6239666748e+02, /* 0xc322658c */
|
||||
ra5 = -1.8460508728e+02, /* 0xc3389ae7 */
|
||||
ra6 = -8.1287437439e+01, /* 0xc2a2932b */
|
||||
ra7 = -9.8143291473e+00, /* 0xc11d077e */
|
||||
sa1 = 1.9651271820e+01, /* 0x419d35ce */
|
||||
sa2 = 1.3765776062e+02, /* 0x4309a863 */
|
||||
sa3 = 4.3456588745e+02, /* 0x43d9486f */
|
||||
sa4 = 6.4538726807e+02, /* 0x442158c9 */
|
||||
sa5 = 4.2900814819e+02, /* 0x43d6810b */
|
||||
sa6 = 1.0863500214e+02, /* 0x42d9451f */
|
||||
sa7 = 6.5702495575e+00, /* 0x40d23f7c */
|
||||
sa8 = -6.0424413532e-02, /* 0xbd777f97 */
|
||||
ra0 = -9.8649440333e-03f, /* 0xbc21a093 */
|
||||
ra1 = -6.9385856390e-01f, /* 0xbf31a0b7 */
|
||||
ra2 = -1.0558626175e+01f, /* 0xc128f022 */
|
||||
ra3 = -6.2375331879e+01f, /* 0xc2798057 */
|
||||
ra4 = -1.6239666748e+02f, /* 0xc322658c */
|
||||
ra5 = -1.8460508728e+02f, /* 0xc3389ae7 */
|
||||
ra6 = -8.1287437439e+01f, /* 0xc2a2932b */
|
||||
ra7 = -9.8143291473e+00f, /* 0xc11d077e */
|
||||
sa1 = 1.9651271820e+01f, /* 0x419d35ce */
|
||||
sa2 = 1.3765776062e+02f, /* 0x4309a863 */
|
||||
sa3 = 4.3456588745e+02f, /* 0x43d9486f */
|
||||
sa4 = 6.4538726807e+02f, /* 0x442158c9 */
|
||||
sa5 = 4.2900814819e+02f, /* 0x43d6810b */
|
||||
sa6 = 1.0863500214e+02f, /* 0x42d9451f */
|
||||
sa7 = 6.5702495575e+00f, /* 0x40d23f7c */
|
||||
sa8 = -6.0424413532e-02f, /* 0xbd777f97 */
|
||||
/*
|
||||
* Coefficients for approximation to erfc in [1/.35,28]
|
||||
*/
|
||||
rb0 = -9.8649431020e-03, /* 0xbc21a092 */
|
||||
rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */
|
||||
rb2 = -1.7757955551e+01, /* 0xc18e104b */
|
||||
rb3 = -1.6063638306e+02, /* 0xc320a2ea */
|
||||
rb4 = -6.3756646729e+02, /* 0xc41f6441 */
|
||||
rb5 = -1.0250950928e+03, /* 0xc480230b */
|
||||
rb6 = -4.8351919556e+02, /* 0xc3f1c275 */
|
||||
sb1 = 3.0338060379e+01, /* 0x41f2b459 */
|
||||
sb2 = 3.2579251099e+02, /* 0x43a2e571 */
|
||||
sb3 = 1.5367296143e+03, /* 0x44c01759 */
|
||||
sb4 = 3.1998581543e+03, /* 0x4547fdbb */
|
||||
sb5 = 2.5530502930e+03, /* 0x451f90ce */
|
||||
sb6 = 4.7452853394e+02, /* 0x43ed43a7 */
|
||||
sb7 = -2.2440952301e+01; /* 0xc1b38712 */
|
||||
rb0 = -9.8649431020e-03f, /* 0xbc21a092 */
|
||||
rb1 = -7.9928326607e-01f, /* 0xbf4c9dd4 */
|
||||
rb2 = -1.7757955551e+01f, /* 0xc18e104b */
|
||||
rb3 = -1.6063638306e+02f, /* 0xc320a2ea */
|
||||
rb4 = -6.3756646729e+02f, /* 0xc41f6441 */
|
||||
rb5 = -1.0250950928e+03f, /* 0xc480230b */
|
||||
rb6 = -4.8351919556e+02f, /* 0xc3f1c275 */
|
||||
sb1 = 3.0338060379e+01f, /* 0x41f2b459 */
|
||||
sb2 = 3.2579251099e+02f, /* 0x43a2e571 */
|
||||
sb3 = 1.5367296143e+03f, /* 0x44c01759 */
|
||||
sb4 = 3.1998581543e+03f, /* 0x4547fdbb */
|
||||
sb5 = 2.5530502930e+03f, /* 0x451f90ce */
|
||||
sb6 = 4.7452853394e+02f, /* 0x43ed43a7 */
|
||||
sb7 = -2.2440952301e+01f; /* 0xc1b38712 */
|
||||
|
||||
#ifdef __STDC__
|
||||
float erff(float x)
|
||||
|
@ -29,7 +29,7 @@ static const float
|
||||
#else
|
||||
static float
|
||||
#endif
|
||||
two25 = 3.3554432000e+07; /* 0x4c000000 */
|
||||
two25 = 3.3554432000e+07f; /* 0x4c000000 */
|
||||
|
||||
#ifdef __STDC__
|
||||
float frexpf(float x, int *eptr)
|
||||
|
@ -23,7 +23,6 @@
|
||||
*/
|
||||
|
||||
#include "fdlibm.h"
|
||||
//#include <errno.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
float ldexpf(float value, int exp)
|
||||
|
@ -25,9 +25,9 @@
|
||||
#include "fdlibm.h"
|
||||
|
||||
#ifdef __STDC__
|
||||
static const float one = 1.0;
|
||||
static const float one = 1.0f;
|
||||
#else
|
||||
static float one = 1.0;
|
||||
static float one = 1.0f;
|
||||
#endif
|
||||
|
||||
#ifdef __STDC__
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
#include "fdlibm.h"
|
||||
#define _IEEE_LIBM 1
|
||||
//#include <reent.h>
|
||||
//#include <errno.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
float lgammaf(float x)
|
||||
|
@ -1,4 +1,3 @@
|
||||
//#include <fenv.h>
|
||||
#include <math.h>
|
||||
|
||||
/* nearbyint is the same as rint, but it must not raise the inexact exception */
|
||||
|
35
lib/libm_dbl/round.c
Normal file
35
lib/libm_dbl/round.c
Normal 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
@ -21,7 +21,7 @@ extern "C"
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// 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_MINOR (0xffff & (LFS2_VERSION >> 0))
|
||||
|
||||
@ -355,6 +355,11 @@ typedef struct lfs2_superblock {
|
||||
lfs2_size_t attr_max;
|
||||
} lfs2_superblock_t;
|
||||
|
||||
typedef struct lfs2_gstate {
|
||||
uint32_t tag;
|
||||
lfs2_block_t pair[2];
|
||||
} lfs2_gstate_t;
|
||||
|
||||
// The littlefs filesystem type
|
||||
typedef struct lfs2 {
|
||||
lfs2_cache_t rcache;
|
||||
@ -369,10 +374,9 @@ typedef struct lfs2 {
|
||||
} *mlist;
|
||||
uint32_t seed;
|
||||
|
||||
struct lfs2_gstate {
|
||||
uint32_t tag;
|
||||
lfs2_block_t pair[2];
|
||||
} gstate, gpending, gdelta;
|
||||
lfs2_gstate_t gstate;
|
||||
lfs2_gstate_t gdisk;
|
||||
lfs2_gstate_t gdelta;
|
||||
|
||||
struct lfs2_free {
|
||||
lfs2_block_t off;
|
||||
|
@ -50,31 +50,35 @@ extern "C"
|
||||
|
||||
// Logging functions
|
||||
#ifdef LFS2_YES_TRACE
|
||||
#define LFS2_TRACE(fmt, ...) \
|
||||
printf("lfs2_trace:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#define LFS2_TRACE_(fmt, ...) \
|
||||
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS2_TRACE(fmt, ...)
|
||||
#define LFS2_TRACE(...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_NO_DEBUG
|
||||
#define LFS2_DEBUG(fmt, ...) \
|
||||
printf("lfs2_debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#define LFS2_DEBUG_(fmt, ...) \
|
||||
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS2_DEBUG(fmt, ...)
|
||||
#define LFS2_DEBUG(...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_NO_WARN
|
||||
#define LFS2_WARN(fmt, ...) \
|
||||
printf("lfs2_warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#define LFS2_WARN_(fmt, ...) \
|
||||
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS2_WARN(fmt, ...)
|
||||
#define LFS2_WARN(...)
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_NO_ERROR
|
||||
#define LFS2_ERROR(fmt, ...) \
|
||||
printf("lfs2_error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
||||
#define LFS2_ERROR_(fmt, ...) \
|
||||
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "")
|
||||
#else
|
||||
#define LFS2_ERROR(fmt, ...)
|
||||
#define LFS2_ERROR(...)
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return 32 - __builtin_clz(a-1);
|
||||
|
@ -84,6 +84,7 @@ STATIC void mp_hal_move_cursor_back(uint pos) {
|
||||
// snprintf needs space for the terminating null character
|
||||
int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos);
|
||||
if (n > 0) {
|
||||
assert((unsigned)n < sizeof(vt100_command));
|
||||
vt100_command[n] = 'D'; // replace null char
|
||||
mp_hal_stdout_tx_strn(vt100_command, n + 1);
|
||||
}
|
||||
@ -109,6 +110,35 @@ typedef struct _readline_t {
|
||||
|
||||
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) {
|
||||
size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len);
|
||||
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_from_cursor = true;
|
||||
#endif
|
||||
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||
} else if (c == CHAR_CTRL_W) {
|
||||
goto backward_kill_word;
|
||||
#endif
|
||||
} else if (c == '\r') {
|
||||
// newline
|
||||
mp_hal_stdout_tx_str("\r\n");
|
||||
@ -255,9 +289,40 @@ int readline_process_char(int c) {
|
||||
case 'O':
|
||||
rl.escape_seq = ESEQ_ESC_O;
|
||||
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:
|
||||
DEBUG_printf("(ESC %d)", c);
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
break;
|
||||
}
|
||||
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
@ -365,6 +430,24 @@ delete_key:
|
||||
} else {
|
||||
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 {
|
||||
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
||||
}
|
||||
@ -383,6 +466,10 @@ delete_key:
|
||||
rl.escape_seq = ESEQ_NONE;
|
||||
}
|
||||
|
||||
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||
redraw:
|
||||
#endif
|
||||
|
||||
// redraw command prompt, efficiently
|
||||
if (redraw_step_back > 0) {
|
||||
mp_hal_move_cursor_back(redraw_step_back-cont_chars);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define CHAR_CTRL_N (14)
|
||||
#define CHAR_CTRL_P (16)
|
||||
#define CHAR_CTRL_U (21)
|
||||
#define CHAR_CTRL_W (23)
|
||||
|
||||
void readline_init0(void);
|
||||
int readline(vstr_t *line, const char *prompt);
|
||||
|
@ -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 == '.') {
|
||||
s++;
|
||||
} else {
|
||||
mp_raise_ValueError(translate("invalid arguments"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
t -= EPOCH1970_EPOCH2000_DIFF_SECS;
|
||||
t -= TIMEUTILS_SECONDS_1970_TO_2000;
|
||||
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 hour, mp_uint_t minute, mp_uint_t 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,
|
||||
|
@ -27,7 +27,9 @@
|
||||
#ifndef 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 {
|
||||
uint16_t tm_year; // i.e. 2014
|
||||
@ -40,6 +42,14 @@ typedef struct _timeutils_struct_time_t {
|
||||
uint16_t tm_yday; // 1..366
|
||||
} 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);
|
||||
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);
|
||||
@ -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_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
|
||||
|
@ -28,7 +28,21 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uintptr_t gc_helper_get_sp(void);
|
||||
uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs);
|
||||
#if MICROPY_GCREGS_SETJMP
|
||||
#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
|
||||
|
156
lib/utils/gchelper_generic.c
Normal file
156
lib/utils/gchelper_generic.c
Normal 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 *)®s;
|
||||
gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)®s) / sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
#endif // MICROPY_ENABLE_GC
|
@ -31,18 +31,6 @@
|
||||
.section .text
|
||||
.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
|
||||
.type gc_helper_get_regs_and_sp, %function
|
||||
|
||||
|
47
lib/utils/gchelper_native.c
Normal file
47
lib/utils/gchelper_native.c
Normal 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
|
@ -32,21 +32,9 @@
|
||||
int mp_interrupt_char = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void mp_keyboard_interrupt(void) {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
|
||||
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check to see if we've been CTRL-C'ed by autoreload or the user.
|
||||
bool mp_hal_is_interrupted(void) {
|
||||
return MP_STATE_VM(mp_pending_exception) != NULL;
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
extern int mp_interrupt_char;
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
void mp_keyboard_interrupt(void);
|
||||
bool mp_hal_is_interrupted(void);
|
||||
|
||||
#endif // MICROPY_INCLUDED_LIB_UTILS_INTERRUPT_CHAR_H
|
||||
|
@ -31,12 +31,14 @@
|
||||
#include "py/gc.h"
|
||||
#include "lib/utils/mpirq.h"
|
||||
|
||||
#if MICROPY_ENABLE_SCHEDULER
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
|
||||
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_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) {
|
||||
if (self->handler != mp_const_none) {
|
||||
if (self->ishard) {
|
||||
// When executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations.
|
||||
// When executing code within a handler we must lock the scheduler to
|
||||
// prevent any scheduled callbacks from running, and lock the GC to
|
||||
// prevent any memory allocations.
|
||||
mp_sched_lock();
|
||||
gc_lock();
|
||||
nlr_buf_t nlr;
|
||||
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));
|
||||
}
|
||||
gc_unlock();
|
||||
mp_sched_unlock();
|
||||
} else {
|
||||
// Schedule call to user function
|
||||
mp_sched_schedule(self->handler, self->parent);
|
||||
@ -122,3 +127,5 @@ const mp_obj_type_t mp_irq_type = {
|
||||
.call = mp_irq_call,
|
||||
.locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict,
|
||||
};
|
||||
|
||||
#endif // MICROPY_ENABLE_SCHEDULER
|
||||
|
@ -46,7 +46,10 @@
|
||||
|
||||
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
||||
int pyexec_system_exit = 0;
|
||||
|
||||
#if MICROPY_REPL_INFO
|
||||
STATIC bool repl_display_debugging_info = 0;
|
||||
#endif
|
||||
|
||||
#define EXEC_FLAG_PRINT_EOF (1)
|
||||
#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)
|
||||
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;
|
||||
#if MICROPY_REPL_INFO
|
||||
uint32_t start = 0;
|
||||
#endif
|
||||
|
||||
// by default a SystemExit exception returns 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.
|
||||
*((uint32_t volatile *)&parse_tree.chunk) = 0;
|
||||
#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
|
||||
}
|
||||
|
||||
@ -110,11 +115,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
|
||||
// execute code
|
||||
mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
|
||||
#if MICROPY_REPL_INFO
|
||||
start = mp_hal_ticks_ms();
|
||||
#endif
|
||||
mp_call_function_0(module_fun);
|
||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||
// Handle any ctrl-c interrupt that arrived just in time
|
||||
mp_handle_pending();
|
||||
mp_handle_pending(true); // handle any pending exceptions (and any callbacks)
|
||||
nlr_pop();
|
||||
ret = 0;
|
||||
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 {
|
||||
// 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_handle_pending(false); // clear any pending exceptions (and run any callbacks)
|
||||
// print EOF after normal output
|
||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||
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
|
||||
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
|
||||
@ -179,6 +186,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||
gc_dump_info();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||
mp_hal_stdout_tx_strn("\x04", 1);
|
||||
@ -362,7 +370,7 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
|
||||
}
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
@ -612,9 +620,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MICROPY_REPL_INFO
|
||||
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
||||
repl_display_debugging_info = mp_obj_get_int(o_value);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
|
||||
#endif
|
||||
|
@ -29,8 +29,8 @@
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef enum {
|
||||
PYEXEC_MODE_RAW_REPL,
|
||||
PYEXEC_MODE_FRIENDLY_REPL,
|
||||
PYEXEC_MODE_RAW_REPL,
|
||||
} pyexec_mode_kind_t;
|
||||
|
||||
typedef struct {
|
||||
@ -59,8 +59,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result);
|
||||
void pyexec_event_repl_init(void);
|
||||
int pyexec_event_repl_process_char(int c);
|
||||
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);
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user