Merge MicroPython 1.13 into CircuitPython
This commit is contained in:
commit
f0bb26d70f
|
@ -71,27 +71,18 @@ jobs:
|
||||||
run: make -C mpy-cross -j2
|
run: make -C mpy-cross -j2
|
||||||
- name: Build unix port
|
- name: Build unix port
|
||||||
run: |
|
run: |
|
||||||
make -C ports/unix deplibs -j2
|
make -C ports/unix VARIANT=coverage -j2
|
||||||
make -C ports/unix -j2
|
|
||||||
make -C ports/unix coverage -j2
|
|
||||||
- name: Test all
|
- name: Test all
|
||||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1
|
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1
|
||||||
working-directory: tests
|
working-directory: tests
|
||||||
- name: Print failure info
|
|
||||||
run: |
|
|
||||||
shopt -s nullglob;
|
|
||||||
for exp in *.exp;
|
|
||||||
do testbase=$(basename $exp .exp);
|
|
||||||
echo -e "\nFAILURE $testbase";
|
|
||||||
diff -u $testbase.exp $testbase.out;
|
|
||||||
done
|
|
||||||
working-directory: tests
|
|
||||||
if: failure()
|
|
||||||
- name: Native Tests
|
- name: Native Tests
|
||||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 --emit native
|
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --emit native
|
||||||
working-directory: tests
|
working-directory: tests
|
||||||
- name: mpy Tests
|
- name: mpy Tests
|
||||||
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -j1 --via-mpy -d basics float
|
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy -d basics float micropython
|
||||||
|
working-directory: tests
|
||||||
|
- name: Native mpy Tests
|
||||||
|
run: MICROPY_CPYTHON3=python3.8 MICROPY_MICROPYTHON=../ports/unix/micropython ./run-tests -j1 --mpy-cross-flags='-mcache-lookup-bc' --via-mpy --emit native -d basics float micropython
|
||||||
working-directory: tests
|
working-directory: tests
|
||||||
- name: Build mpy-cross.static-raspbian
|
- name: Build mpy-cross.static-raspbian
|
||||||
run: make -C mpy-cross -j2 -f Makefile.static-raspbian
|
run: make -C mpy-cross -j2 -f Makefile.static-raspbian
|
||||||
|
|
|
@ -37,8 +37,7 @@ build-*/
|
||||||
|
|
||||||
# Test failure outputs
|
# Test failure outputs
|
||||||
######################
|
######################
|
||||||
tests/*.exp
|
tests/results/*
|
||||||
tests/*.out
|
|
||||||
|
|
||||||
# Python cache files
|
# Python cache files
|
||||||
######################
|
######################
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2013-2019 Damien P. George
|
Copyright (c) 2013-2020 Damien P. George
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line.
|
||||||
PYTHON = python3
|
PYTHON = python3
|
||||||
SPHINXOPTS =
|
SPHINXOPTS = -W --keep-going
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD = sphinx-build
|
||||||
PAPER =
|
PAPER =
|
||||||
# path to build the generated docs
|
# path to build the generated docs
|
||||||
|
@ -223,7 +223,7 @@ pseudoxml:
|
||||||
all-source:
|
all-source:
|
||||||
|
|
||||||
locale/circuitpython.pot: all-source
|
locale/circuitpython.pot: all-source
|
||||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o - | sed -e '/"POT-Creation-Date: /d' > $@
|
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' > $@
|
||||||
|
|
||||||
# Historically, `make translate` updated the .pot file and ran msgmerge.
|
# Historically, `make translate` updated the .pot file and ran msgmerge.
|
||||||
# However, this was a frequent source of merge conflicts. Weblate can perform
|
# However, this was a frequent source of merge conflicts. Weblate can perform
|
||||||
|
@ -248,7 +248,7 @@ merge-translate:
|
||||||
|
|
||||||
.PHONY: check-translate
|
.PHONY: check-translate
|
||||||
check-translate:
|
check-translate:
|
||||||
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate -o circuitpython.pot.tmp -p locale
|
find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -f- -L C -s --add-location=file --keyword=translate --keyword=MP_ERROR_TEXT -o circuitpython.pot.tmp -p locale
|
||||||
$(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status
|
$(PYTHON) tools/check_translations.py locale/circuitpython.pot.tmp locale/circuitpython.pot; status=$$?; rm -f locale/circuitpython.pot.tmp; exit $$status
|
||||||
|
|
||||||
stubs:
|
stubs:
|
||||||
|
|
|
@ -541,10 +541,10 @@ object instead of the pins themselves. This allows the calling code to provide
|
||||||
any object with the appropriate methods such as an I2C expansion board.
|
any object with the appropriate methods such as an I2C expansion board.
|
||||||
|
|
||||||
Another example is to expect a :py:class:`~digitalio.DigitalInOut` for a pin to
|
Another example is to expect a :py:class:`~digitalio.DigitalInOut` for a pin to
|
||||||
toggle instead of a :py:class:`~microcontroller.Pin` from `board`. Taking in the
|
toggle instead of a :py:class:`~microcontroller.Pin` from :py:mod:`board`.
|
||||||
:py:class:`~microcontroller.Pin` object alone would limit the driver to pins on
|
Taking in the :py:class:`~microcontroller.Pin` object alone would limit the
|
||||||
the actual microcontroller instead of pins provided by another driver such as an
|
driver to pins on the actual microcontroller instead of pins provided by another
|
||||||
IO expander.
|
driver such as an IO expander.
|
||||||
|
|
||||||
Lots of small modules
|
Lots of small modules
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
|
@ -36,6 +36,7 @@ Full Table of Contents
|
||||||
:caption: MicroPython specific
|
:caption: MicroPython specific
|
||||||
|
|
||||||
library/index.rst
|
library/index.rst
|
||||||
|
reference/glossary.rst
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
|
@ -78,7 +78,7 @@ Example::
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. function:: open(stream, \*, flags=0, pagesize=0, cachesize=0, minkeypage=0)
|
.. function:: open(stream, *, flags=0, pagesize=0, cachesize=0, minkeypage=0)
|
||||||
|
|
||||||
Open a database from a random-access ``stream`` (like an open file). All
|
Open a database from a random-access ``stream`` (like an open file). All
|
||||||
other parameters are optional and keyword-only, and allow to tweak advanced
|
other parameters are optional and keyword-only, and allow to tweak advanced
|
||||||
|
@ -118,7 +118,7 @@ Methods
|
||||||
Flush any data in cache to the underlying stream.
|
Flush any data in cache to the underlying stream.
|
||||||
|
|
||||||
.. method:: btree.__getitem__(key)
|
.. method:: btree.__getitem__(key)
|
||||||
btree.get(key, default=None)
|
btree.get(key, default=None, /)
|
||||||
btree.__setitem__(key, val)
|
btree.__setitem__(key, val)
|
||||||
btree.__detitem__(key)
|
btree.__detitem__(key)
|
||||||
btree.__contains__(key)
|
btree.__contains__(key)
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
:mod:`errno` -- system error codes
|
:mod:`uerrno` -- system error codes
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
.. module:: errno
|
.. module:: uerrno
|
||||||
:synopsis: system error codes
|
:synopsis: system error codes
|
||||||
|
|
||||||
|see_cpython_module| :mod:`cpython:errno`.
|
|see_cpython_module| :mod:`python:errno`.
|
||||||
|
|
||||||
This module provides access to symbolic error codes for `OSError` exception.
|
This module provides access to symbolic error codes for `OSError` exception.
|
||||||
|
A particular inventory of codes depends on :term:`MicroPython port`.
|
||||||
|
|
||||||
Constants
|
Constants
|
||||||
---------
|
---------
|
||||||
|
@ -14,13 +15,14 @@ Constants
|
||||||
.. data:: EEXIST, EAGAIN, etc.
|
.. data:: EEXIST, EAGAIN, etc.
|
||||||
|
|
||||||
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
Error codes, based on ANSI C/POSIX standard. All error codes start with
|
||||||
"E". Errors are usually accessible as ``exc.args[0]``
|
"E". As mentioned above, inventory of the codes depends on
|
||||||
|
:term:`MicroPython port`. Errors are usually accessible as ``exc.args[0]``
|
||||||
where ``exc`` is an instance of `OSError`. Usage example::
|
where ``exc`` is an instance of `OSError`. Usage example::
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.mkdir("my_dir")
|
uos.mkdir("my_dir")
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
if exc.args[0] == errno.EEXIST:
|
if exc.args[0] == uerrno.EEXIST:
|
||||||
print("Directory already exists")
|
print("Directory already exists")
|
||||||
|
|
||||||
.. data:: errorcode
|
.. data:: errorcode
|
||||||
|
@ -28,5 +30,5 @@ Constants
|
||||||
Dictionary mapping numeric error codes to strings with symbolic error
|
Dictionary mapping numeric error codes to strings with symbolic error
|
||||||
code (see above)::
|
code (see above)::
|
||||||
|
|
||||||
>>> print(errno.errorcode[uerrno.EEXIST])
|
>>> print(uerrno.errorcode[uerrno.EEXIST])
|
||||||
EEXIST
|
EEXIST
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
:mod:`framebuf` --- Frame buffer manipulation
|
:mod:`framebuf` --- frame buffer manipulation
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
.. include:: ../templates/unsupported_in_circuitpython.inc
|
.. include:: ../templates/unsupported_in_circuitpython.inc
|
||||||
|
@ -30,7 +30,7 @@ For example::
|
||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width)
|
.. class:: FrameBuffer(buffer, width, height, format, stride=width, /)
|
||||||
|
|
||||||
Construct a FrameBuffer object. The parameters are:
|
Construct a FrameBuffer object. The parameters are:
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ Constants
|
||||||
|
|
||||||
Monochrome (1-bit) color format
|
Monochrome (1-bit) color format
|
||||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||||
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
||||||
Subsequent bytes appear at successive horizontal locations until the
|
Subsequent bytes appear at successive horizontal locations until the
|
||||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||||
pixel lower.
|
pixel lower.
|
||||||
|
@ -141,7 +141,7 @@ Constants
|
||||||
|
|
||||||
Monochrome (1-bit) color format
|
Monochrome (1-bit) color format
|
||||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||||
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
||||||
Subsequent bytes appear at successive horizontal locations until the
|
Subsequent bytes appear at successive horizontal locations until the
|
||||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||||
pixel lower.
|
pixel lower.
|
||||||
|
|
|
@ -37,6 +37,7 @@ with the ``u`` prefix dropped:
|
||||||
json.rst
|
json.rst
|
||||||
re.rst
|
re.rst
|
||||||
sys.rst
|
sys.rst
|
||||||
|
uasyncio.rst
|
||||||
uctypes.rst
|
uctypes.rst
|
||||||
uselect.rst
|
uselect.rst
|
||||||
uzlib.rst
|
uzlib.rst
|
||||||
|
|
|
@ -73,17 +73,26 @@ Functions
|
||||||
|
|
||||||
.. function:: heap_lock()
|
.. function:: heap_lock()
|
||||||
.. function:: heap_unlock()
|
.. function:: heap_unlock()
|
||||||
|
.. function:: heap_locked()
|
||||||
|
|
||||||
Lock or unlock the heap. When locked no memory allocation can occur and a
|
Lock or unlock the heap. When locked no memory allocation can occur and a
|
||||||
`MemoryError` will be raised if any heap allocation is attempted.
|
`MemoryError` will be raised if any heap allocation is attempted.
|
||||||
|
`heap_locked()` returns a true value if the heap is currently locked.
|
||||||
|
|
||||||
These functions can be nested, ie `heap_lock()` can be called multiple times
|
These functions can be nested, ie `heap_lock()` can be called multiple times
|
||||||
in a row and the lock-depth will increase, and then `heap_unlock()` must be
|
in a row and the lock-depth will increase, and then `heap_unlock()` must be
|
||||||
called the same number of times to make the heap available again.
|
called the same number of times to make the heap available again.
|
||||||
|
|
||||||
|
Both `heap_unlock()` and `heap_locked()` return the current lock depth
|
||||||
|
(after unlocking for the former) as a non-negative integer, with 0 meaning
|
||||||
|
the heap is not locked.
|
||||||
|
|
||||||
If the REPL becomes active with the heap locked then it will be forcefully
|
If the REPL becomes active with the heap locked then it will be forcefully
|
||||||
unlocked.
|
unlocked.
|
||||||
|
|
||||||
|
Note: `heap_locked()` is not enabled on most ports by default,
|
||||||
|
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
|
||||||
|
|
||||||
.. function:: kbd_intr(chr)
|
.. function:: kbd_intr(chr)
|
||||||
|
|
||||||
Set the character that will raise a `KeyboardInterrupt` exception. By
|
Set the character that will raise a `KeyboardInterrupt` exception. By
|
||||||
|
|
|
@ -124,7 +124,7 @@ Functions
|
||||||
string for first position which matches regex (which still may be
|
string for first position which matches regex (which still may be
|
||||||
0 if regex is anchored).
|
0 if regex is anchored).
|
||||||
|
|
||||||
.. function:: sub(regex_str, replace, string, count=0, flags=0)
|
.. function:: sub(regex_str, replace, string, count=0, flags=0, /)
|
||||||
|
|
||||||
Compile *regex_str* and search for it in *string*, replacing all matches
|
Compile *regex_str* and search for it in *string*, replacing all matches
|
||||||
with *replace*, and returning the new string.
|
with *replace*, and returning the new string.
|
||||||
|
@ -138,11 +138,12 @@ Functions
|
||||||
If *count* is specified and non-zero then substitution will stop after
|
If *count* is specified and non-zero then substitution will stop after
|
||||||
this many substitutions are made. The *flags* argument is ignored.
|
this many substitutions are made. The *flags* argument is ignored.
|
||||||
|
|
||||||
Note: availability of this function depends on MicroPython port.
|
Note: availability of this function depends on :term:`MicroPython port`.
|
||||||
|
|
||||||
.. data:: DEBUG
|
.. data:: DEBUG
|
||||||
|
|
||||||
Flag value, display debug information about compiled expression.
|
Flag value, display debug information about compiled expression.
|
||||||
|
(Availability depends on :term:`MicroPython port`.)
|
||||||
|
|
||||||
|
|
||||||
.. _regex:
|
.. _regex:
|
||||||
|
@ -155,14 +156,14 @@ Compiled regular expression. Instances of this class are created using
|
||||||
|
|
||||||
.. method:: regex.match(string)
|
.. method:: regex.match(string)
|
||||||
regex.search(string)
|
regex.search(string)
|
||||||
regex.sub(replace, string, count=0, flags=0)
|
regex.sub(replace, string, count=0, flags=0, /)
|
||||||
|
|
||||||
Similar to the module-level functions :meth:`match`, :meth:`search`
|
Similar to the module-level functions :meth:`match`, :meth:`search`
|
||||||
and :meth:`sub`.
|
and :meth:`sub`.
|
||||||
Using methods is (much) more efficient if the same regex is applied to
|
Using methods is (much) more efficient if the same regex is applied to
|
||||||
multiple strings.
|
multiple strings.
|
||||||
|
|
||||||
.. method:: regex.split(string, max_split=-1)
|
.. method:: regex.split(string, max_split=-1, /)
|
||||||
|
|
||||||
Split a *string* using regex. If *max_split* is given, it specifies
|
Split a *string* using regex. If *max_split* is given, it specifies
|
||||||
maximum number of splits to perform. Returns list of strings (there
|
maximum number of splits to perform. Returns list of strings (there
|
||||||
|
@ -183,7 +184,7 @@ to the replacement function in `sub()`.
|
||||||
|
|
||||||
Return a tuple containing all the substrings of the groups of the match.
|
Return a tuple containing all the substrings of the groups of the match.
|
||||||
|
|
||||||
Note: availability of this method depends on MicroPython port.
|
Note: availability of this method depends on :term:`MicroPython port`.
|
||||||
|
|
||||||
.. method:: match.start([index])
|
.. method:: match.start([index])
|
||||||
match.end([index])
|
match.end([index])
|
||||||
|
@ -192,10 +193,10 @@ to the replacement function in `sub()`.
|
||||||
substring group that was matched. *index* defaults to the entire
|
substring group that was matched. *index* defaults to the entire
|
||||||
group, otherwise it will select a group.
|
group, otherwise it will select a group.
|
||||||
|
|
||||||
Note: availability of these methods depends on MicroPython port.
|
Note: availability of these methods depends on :term:`MicroPython port`.
|
||||||
|
|
||||||
.. method:: match.span([index])
|
.. method:: match.span([index])
|
||||||
|
|
||||||
Returns the 2-tuple ``(match.start(index), match.end(index))``.
|
Returns the 2-tuple ``(match.start(index), match.end(index))``.
|
||||||
|
|
||||||
Note: availability of this method depends on MicroPython port.
|
Note: availability of this method depends on :term:`MicroPython port`.
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. function:: exit(retval=0)
|
.. function:: exit(retval=0, /)
|
||||||
|
|
||||||
Terminate current program with a given exit code. Underlyingly, this
|
Terminate current program with a given exit code. Underlyingly, this
|
||||||
function raise as `SystemExit` exception. If an argument is given, its
|
function raise as `SystemExit` exception. If an argument is given, its
|
||||||
|
|
|
@ -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
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
.. class:: struct(addr, descriptor, layout_type=NATIVE)
|
.. class:: struct(addr, descriptor, layout_type=NATIVE, /)
|
||||||
|
|
||||||
Instantiate a "foreign data structure" object based on structure address in
|
Instantiate a "foreign data structure" object based on structure address in
|
||||||
memory, descriptor (encoded as a dictionary), and layout type (see below).
|
memory, descriptor (encoded as a dictionary), and layout type (see below).
|
||||||
|
@ -202,7 +202,7 @@ Module contents
|
||||||
Layout type for a native structure - with data endianness and alignment
|
Layout type for a native structure - with data endianness and alignment
|
||||||
conforming to the ABI of the system on which MicroPython runs.
|
conforming to the ABI of the system on which MicroPython runs.
|
||||||
|
|
||||||
.. function:: sizeof(struct, layout_type=NATIVE)
|
.. function:: sizeof(struct, layout_type=NATIVE, /)
|
||||||
|
|
||||||
Return size of data structure in bytes. The *struct* argument can be
|
Return size of data structure in bytes. The *struct* argument can be
|
||||||
either a structure class or a specific instantiated structure object
|
either a structure class or a specific instantiated structure object
|
||||||
|
|
|
@ -60,7 +60,7 @@ Methods
|
||||||
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
|
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
|
||||||
is raised with error of ENOENT.
|
is raised with error of ENOENT.
|
||||||
|
|
||||||
.. method:: poll.poll(timeout=-1)
|
.. method:: poll.poll(timeout=-1, /)
|
||||||
|
|
||||||
Wait for at least one of the registered objects to become ready or have an
|
Wait for at least one of the registered objects to become ready or have an
|
||||||
exceptional condition, with optional timeout in milliseconds (if *timeout*
|
exceptional condition, with optional timeout in milliseconds (if *timeout*
|
||||||
|
@ -83,7 +83,7 @@ Methods
|
||||||
|
|
||||||
Tuples returned may contain more than 2 elements as described above.
|
Tuples returned may contain more than 2 elements as described above.
|
||||||
|
|
||||||
.. method:: poll.ipoll(timeout=-1, flags=0)
|
.. method:: poll.ipoll(timeout=-1, flags=0, /)
|
||||||
|
|
||||||
Like :meth:`poll.poll`, but instead returns an iterator which yields a
|
Like :meth:`poll.poll`, but instead returns an iterator which yields a
|
||||||
``callee-owned tuples``. This function provides efficient, allocation-free
|
``callee-owned tuples``. This function provides efficient, allocation-free
|
||||||
|
|
|
@ -16,7 +16,7 @@ is not yet implemented.
|
||||||
Functions
|
Functions
|
||||||
---------
|
---------
|
||||||
|
|
||||||
.. function:: decompress(data, wbits=0, bufsize=0)
|
.. function:: decompress(data, wbits=0, bufsize=0, /)
|
||||||
|
|
||||||
Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
|
Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
|
||||||
size used during compression (8-15, the dictionary size is power of 2 of
|
size used during compression (8-15, the dictionary size is power of 2 of
|
||||||
|
@ -25,7 +25,7 @@ Functions
|
||||||
to be raw DEFLATE stream. *bufsize* parameter is for compatibility with
|
to be raw DEFLATE stream. *bufsize* parameter is for compatibility with
|
||||||
CPython and is ignored.
|
CPython and is ignored.
|
||||||
|
|
||||||
.. class:: DecompIO(stream, wbits=0)
|
.. class:: DecompIO(stream, wbits=0, /)
|
||||||
|
|
||||||
Create a ``stream`` wrapper which allows transparent decompression of
|
Create a ``stream`` wrapper which allows transparent decompression of
|
||||||
compressed data in another *stream*. This allows to process compressed
|
compressed data in another *stream*. This allows to process compressed
|
||||||
|
|
|
@ -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.
|
|
@ -4,6 +4,6 @@
|
||||||
|
|
||||||
.. |see_cpython_module| replace::
|
.. |see_cpython_module| replace::
|
||||||
|
|
||||||
*This module implements a subset of the corresponding* ``CPython`` *module,
|
*This module implements a subset of the corresponding* :term:`CPython` *module,
|
||||||
as described below. For more information, refer to the original*
|
as described below. For more information, refer to the original
|
||||||
``CPython`` *documentation:*
|
CPython documentation:*
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
|
||||||
|
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
|
||||||
|
|
||||||
|
// BTstack features that can be enabled
|
||||||
|
#define ENABLE_BLE
|
||||||
|
#define ENABLE_LE_PERIPHERAL
|
||||||
|
#define ENABLE_LE_CENTRAL
|
||||||
|
// #define ENABLE_CLASSIC
|
||||||
|
#define ENABLE_LE_DATA_CHANNELS
|
||||||
|
// #define ENABLE_LOG_INFO
|
||||||
|
#define ENABLE_LOG_ERROR
|
||||||
|
|
||||||
|
// BTstack configuration. buffers, sizes, ...
|
||||||
|
#define HCI_ACL_PAYLOAD_SIZE 1021
|
||||||
|
#define MAX_NR_GATT_CLIENTS 1
|
||||||
|
#define MAX_NR_HCI_CONNECTIONS 1
|
||||||
|
#define MAX_NR_L2CAP_SERVICES 3
|
||||||
|
#define MAX_NR_L2CAP_CHANNELS 3
|
||||||
|
#define MAX_NR_RFCOMM_MULTIPLEXERS 1
|
||||||
|
#define MAX_NR_RFCOMM_SERVICES 1
|
||||||
|
#define MAX_NR_RFCOMM_CHANNELS 1
|
||||||
|
#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
|
||||||
|
#define MAX_NR_BNEP_SERVICES 1
|
||||||
|
#define MAX_NR_BNEP_CHANNELS 1
|
||||||
|
#define MAX_NR_HFP_CONNECTIONS 1
|
||||||
|
#define MAX_NR_WHITELIST_ENTRIES 1
|
||||||
|
#define MAX_NR_SM_LOOKUP_ENTRIES 3
|
||||||
|
#define MAX_NR_SERVICE_RECORD_ITEMS 1
|
||||||
|
#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
|
||||||
|
#define MAX_NR_AVDTP_CONNECTIONS 1
|
||||||
|
#define MAX_NR_AVRCP_CONNECTIONS 1
|
||||||
|
|
||||||
|
#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
|
||||||
|
|
||||||
|
// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
|
||||||
|
// #define NVM_NUM_DEVICE_DB_ENTRIES 16
|
||||||
|
|
||||||
|
// We don't give btstack a malloc, so use a fixed-size ATT DB.
|
||||||
|
#define MAX_ATT_DB_SIZE 512
|
||||||
|
|
||||||
|
// BTstack HAL configuration
|
||||||
|
#define HAVE_EMBEDDED_TIME_MS
|
||||||
|
|
||||||
|
// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
|
||||||
|
#define HCI_RESET_RESEND_TIMEOUT_MS 1000
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
|
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
ifeq ($(MICROPY_SSL_AXTLS),1)
|
||||||
CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include
|
CFLAGS_MOD += -DMICROPY_SSL_AXTLS=1 -I$(TOP)/lib/axtls/ssl -I$(TOP)/lib/axtls/crypto -I$(TOP)/extmod/axtls-include
|
||||||
AXTLS_DIR = lib/axtls
|
AXTLS_DIR = lib/axtls
|
||||||
$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition $(AXTLS_DEFS_EXTRA)
|
$(BUILD)/$(AXTLS_DIR)/%.o: CFLAGS += -Wno-all -Wno-unused-parameter -Wno-uninitialized -Wno-sign-compare -Wno-old-style-definition -Dmp_stream_errno=errno $(AXTLS_DEFS_EXTRA)
|
||||||
SRC_MOD += $(addprefix $(AXTLS_DIR)/,\
|
SRC_MOD += $(addprefix $(AXTLS_DIR)/,\
|
||||||
ssl/asn1.c \
|
ssl/asn1.c \
|
||||||
ssl/loader.c \
|
ssl/loader.c \
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
typedef struct _mp_obj_btree_t {
|
typedef struct _mp_obj_btree_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
|
mp_obj_t stream; // retain a reference to prevent GC from reclaiming it
|
||||||
DB *db;
|
DB *db;
|
||||||
mp_obj_t start_key;
|
mp_obj_t start_key;
|
||||||
mp_obj_t end_key;
|
mp_obj_t end_key;
|
||||||
|
@ -44,9 +45,10 @@ void __dbpanic(DB *db) {
|
||||||
mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
|
mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_btree_t *btree_new(DB *db) {
|
STATIC mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) {
|
||||||
mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);
|
mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);
|
||||||
o->base.type = &btree_type;
|
o->base.type = &btree_type;
|
||||||
|
o->stream = stream;
|
||||||
o->db = db;
|
o->db = db;
|
||||||
o->start_key = mp_const_none;
|
o->start_key = mp_const_none;
|
||||||
o->end_key = mp_const_none;
|
o->end_key = mp_const_none;
|
||||||
|
@ -228,14 +230,14 @@ STATIC mp_obj_t btree_iternext(mp_obj_t self_in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||||
mp_obj_btree_t *self = mp_instance_cast_to_native_base(self_in, &btree_type);
|
mp_obj_btree_t *self = mp_obj_cast_to_native_base(self_in, &btree_type);
|
||||||
if (value == MP_OBJ_NULL) {
|
if (value == MP_OBJ_NULL) {
|
||||||
// delete
|
// delete
|
||||||
DBT key;
|
DBT key;
|
||||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||||
int res = __bt_delete(self->db, &key, 0);
|
int res = __bt_delete(self->db, &key, 0);
|
||||||
if (res == RET_SPECIAL) {
|
if (res == RET_SPECIAL) {
|
||||||
nlr_raise(mp_obj_new_exception(&mp_type_KeyError));
|
mp_raise_type(&mp_type_KeyError);
|
||||||
}
|
}
|
||||||
CHECK_ERROR(res);
|
CHECK_ERROR(res);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
|
@ -245,7 +247,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||||
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
key.data = (void *)mp_obj_str_get_data(index, &key.size);
|
||||||
int res = __bt_get(self->db, &key, &val, 0);
|
int res = __bt_get(self->db, &key, &val, 0);
|
||||||
if (res == RET_SPECIAL) {
|
if (res == RET_SPECIAL) {
|
||||||
nlr_raise(mp_obj_new_exception(&mp_type_KeyError));
|
mp_raise_type(&mp_type_KeyError);
|
||||||
}
|
}
|
||||||
CHECK_ERROR(res);
|
CHECK_ERROR(res);
|
||||||
return mp_obj_new_bytes(val.data, val.size);
|
return mp_obj_new_bytes(val.data, val.size);
|
||||||
|
@ -340,7 +342,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||||
if (db == NULL) {
|
if (db == NULL) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(btree_new(db));
|
return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0]));
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ typedef struct _mp_obj_framebuf_t {
|
||||||
uint8_t format;
|
uint8_t format;
|
||||||
} mp_obj_framebuf_t;
|
} mp_obj_framebuf_t;
|
||||||
|
|
||||||
|
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||||
|
STATIC const mp_obj_type_t mp_type_framebuf;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t);
|
typedef void (*setpixel_t)(const mp_obj_framebuf_t *, int, int, uint32_t);
|
||||||
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int);
|
typedef uint32_t (*getpixel_t)(const mp_obj_framebuf_t *, int, int);
|
||||||
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
|
typedef void (*fill_rect_t)(const mp_obj_framebuf_t *, int, int, int, int, uint32_t);
|
||||||
|
@ -278,7 +282,7 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, cons
|
||||||
case FRAMEBUF_GS8:
|
case FRAMEBUF_GS8:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mp_raise_ValueError(translate("invalid format"));
|
mp_raise_ValueError(MP_ERROR_TEXT("invalid format"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
|
@ -288,7 +292,7 @@ STATIC const mp_obj_type_t mp_type_framebuf;
|
||||||
|
|
||||||
// Helper to ensure we have the native super class instead of a subclass.
|
// Helper to ensure we have the native super class instead of a subclass.
|
||||||
static mp_obj_framebuf_t *native_framebuf(mp_obj_t framebuf_obj) {
|
static mp_obj_framebuf_t *native_framebuf(mp_obj_t framebuf_obj) {
|
||||||
mp_obj_t native_framebuf = mp_instance_cast_to_native_base(framebuf_obj, &mp_type_framebuf);
|
mp_obj_t native_framebuf = mp_obj_cast_to_native_base(framebuf_obj, &mp_type_framebuf);
|
||||||
mp_obj_assert_native_inited(native_framebuf);
|
mp_obj_assert_native_inited(native_framebuf);
|
||||||
return MP_OBJ_TO_PTR(native_framebuf);
|
return MP_OBJ_TO_PTR(native_framebuf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,7 +9,6 @@
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/binary.h"
|
#include "py/binary.h"
|
||||||
#include "extmod/modubinascii.h"
|
|
||||||
|
|
||||||
static void check_not_unicode(const mp_obj_t arg) {
|
static void check_not_unicode(const mp_obj_t arg) {
|
||||||
#if MICROPY_CPYTHON_COMPAT
|
#if MICROPY_CPYTHON_COMPAT
|
||||||
|
@ -19,7 +18,7 @@ static void check_not_unicode(const mp_obj_t arg) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
|
||||||
// Second argument is for an extension to allow a separator to be used
|
// Second argument is for an extension to allow a separator to be used
|
||||||
// between values.
|
// between values.
|
||||||
const char *sep = NULL;
|
const char *sep = NULL;
|
||||||
|
@ -59,14 +58,14 @@ mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) {
|
||||||
}
|
}
|
||||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj, 1, 2, mod_binascii_hexlify);
|
||||||
|
|
||||||
mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
|
STATIC mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||||
|
|
||||||
if ((bufinfo.len & 1) != 0) {
|
if ((bufinfo.len & 1) != 0) {
|
||||||
mp_raise_ValueError(translate("odd-length string"));
|
mp_raise_ValueError(MP_ERROR_TEXT("odd-length string"));
|
||||||
}
|
}
|
||||||
vstr_t vstr;
|
vstr_t vstr;
|
||||||
vstr_init_len(&vstr, bufinfo.len / 2);
|
vstr_init_len(&vstr, bufinfo.len / 2);
|
||||||
|
@ -77,7 +76,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
|
||||||
if (unichar_isxdigit(hex_ch)) {
|
if (unichar_isxdigit(hex_ch)) {
|
||||||
hex_byte += unichar_xdigit_value(hex_ch);
|
hex_byte += unichar_xdigit_value(hex_ch);
|
||||||
} else {
|
} else {
|
||||||
mp_raise_ValueError(translate("non-hex digit found"));
|
mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit found"));
|
||||||
}
|
}
|
||||||
if (i & 1) {
|
if (i & 1) {
|
||||||
hex_byte <<= 4;
|
hex_byte <<= 4;
|
||||||
|
@ -88,7 +87,7 @@ mp_obj_t mod_binascii_unhexlify(mp_obj_t data) {
|
||||||
}
|
}
|
||||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj, mod_binascii_unhexlify);
|
||||||
|
|
||||||
// If ch is a character in the base64 alphabet, and is not a pad character, then
|
// If ch is a character in the base64 alphabet, and is not a pad character, then
|
||||||
// the corresponding integer between 0 and 63, inclusively, is returned.
|
// the corresponding integer between 0 and 63, inclusively, is returned.
|
||||||
|
@ -109,7 +108,7 @@ static int mod_binascii_sextet(byte ch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
STATIC mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||||
byte *in = bufinfo.buf;
|
byte *in = bufinfo.buf;
|
||||||
|
@ -145,14 +144,14 @@ mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbits) {
|
if (nbits) {
|
||||||
mp_raise_ValueError(translate("incorrect padding"));
|
mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
|
||||||
|
|
||||||
mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
|
STATIC mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
|
||||||
check_not_unicode(data);
|
check_not_unicode(data);
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||||
|
@ -203,12 +202,12 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) {
|
||||||
*out = '\n';
|
*out = '\n';
|
||||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64);
|
||||||
|
|
||||||
#if MICROPY_PY_UBINASCII_CRC32
|
#if MICROPY_PY_UBINASCII_CRC32
|
||||||
#include "../../lib/uzlib/src/tinf.h"
|
#include "../../lib/uzlib/src/tinf.h"
|
||||||
|
|
||||||
mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
check_not_unicode(args[0]);
|
check_not_unicode(args[0]);
|
||||||
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
|
||||||
|
@ -216,11 +215,9 @@ mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
|
||||||
crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
|
crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
|
||||||
return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
|
return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_PY_UBINASCII
|
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
|
STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&mod_binascii_hexlify_obj) },
|
||||||
|
@ -238,5 +235,3 @@ const mp_obj_module_t mp_module_ubinascii = {
|
||||||
.base = { &mp_type_module },
|
.base = { &mp_type_module },
|
||||||
.globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
|
.globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MICROPY_PY_UBINASCII
|
|
||||||
|
|
|
@ -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;
|
} mp_obj_uctypes_struct_t;
|
||||||
|
|
||||||
STATIC NORETURN void syntax_error(void) {
|
STATIC NORETURN void syntax_error(void) {
|
||||||
mp_raise_TypeError(translate("syntax error in uctypes descriptor"));
|
mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor"));
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
|
@ -118,11 +118,7 @@ STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_p
|
||||||
(void)kind;
|
(void)kind;
|
||||||
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
const char *typen = "unk";
|
const char *typen = "unk";
|
||||||
if (mp_obj_is_type(self->desc, &mp_type_dict)
|
if (mp_obj_is_dict_or_ordereddict(self->desc)) {
|
||||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
|
||||||
|| mp_obj_is_type(self->desc, &mp_type_ordereddict)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
typen = "STRUCT";
|
typen = "STRUCT";
|
||||||
} else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
|
} else if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
|
||||||
|
@ -195,11 +191,7 @@ STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {
|
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) {
|
||||||
if (!mp_obj_is_type(desc_in, &mp_type_dict)
|
if (!mp_obj_is_dict_or_ordereddict(desc_in)) {
|
||||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
|
||||||
&& !mp_obj_is_type(desc_in, &mp_type_ordereddict)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
if (mp_obj_is_type(desc_in, &mp_type_tuple)) {
|
if (mp_obj_is_type(desc_in, &mp_type_tuple)) {
|
||||||
return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);
|
return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size);
|
||||||
} else if (mp_obj_is_small_int(desc_in)) {
|
} else if (mp_obj_is_small_int(desc_in)) {
|
||||||
|
@ -207,7 +199,7 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_
|
||||||
// but scalar structure field is lowered into native Python int, so all
|
// but scalar structure field is lowered into native Python int, so all
|
||||||
// type info is lost. So, we cannot say if it's scalar type description,
|
// type info is lost. So, we cannot say if it's scalar type description,
|
||||||
// or such lowered scalar.
|
// or such lowered scalar.
|
||||||
mp_raise_TypeError(translate("Cannot unambiguously get sizeof scalar"));
|
mp_raise_TypeError(MP_ERROR_TEXT("cannot unambiguously get sizeof scalar"));
|
||||||
}
|
}
|
||||||
syntax_error();
|
syntax_error();
|
||||||
}
|
}
|
||||||
|
@ -341,9 +333,9 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
||||||
return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
|
return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
|
||||||
#if MICROPY_PY_BUILTINS_FLOAT
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
case FLOAT32:
|
case FLOAT32:
|
||||||
return mp_obj_new_float(((float *)p)[index]);
|
return mp_obj_new_float_from_f(((float *)p)[index]);
|
||||||
case FLOAT64:
|
case FLOAT64:
|
||||||
return mp_obj_new_float(((double *)p)[index]);
|
return mp_obj_new_float_from_d(((double *)p)[index]);
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -354,11 +346,10 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
||||||
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||||
#if MICROPY_PY_BUILTINS_FLOAT
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
if (val_type == FLOAT32 || val_type == FLOAT64) {
|
if (val_type == FLOAT32 || val_type == FLOAT64) {
|
||||||
mp_float_t v = mp_obj_get_float(val);
|
|
||||||
if (val_type == FLOAT32) {
|
if (val_type == FLOAT32) {
|
||||||
((float *)p)[index] = v;
|
((float *)p)[index] = mp_obj_get_float_to_f(val);
|
||||||
} else {
|
} else {
|
||||||
((double *)p)[index] = v;
|
((double *)p)[index] = mp_obj_get_float_to_d(val);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -400,12 +391,8 @@ STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||||
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
|
STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) {
|
||||||
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
|
||||||
if (!mp_obj_is_type(self->desc, &mp_type_dict)
|
if (!mp_obj_is_dict_or_ordereddict(self->desc)) {
|
||||||
#if MICROPY_PY_COLLECTIONS_ORDEREDDICT
|
mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields"));
|
||||||
&& !mp_obj_is_type(self->desc, &mp_type_ordereddict)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
mp_raise_TypeError(translate("struct: no fields"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr));
|
||||||
|
@ -530,7 +517,7 @@ STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_obj_t value) {
|
STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_obj_t value) {
|
||||||
mp_obj_uctypes_struct_t *self = mp_instance_cast_to_native_base(base_in, &uctypes_struct_type);
|
mp_obj_uctypes_struct_t *self = mp_obj_cast_to_native_base(base_in, &uctypes_struct_type);
|
||||||
|
|
||||||
if (value == MP_OBJ_NULL) {
|
if (value == MP_OBJ_NULL) {
|
||||||
// delete
|
// delete
|
||||||
|
@ -538,7 +525,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
|
||||||
} else {
|
} else {
|
||||||
// load / store
|
// load / store
|
||||||
if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {
|
if (!mp_obj_is_type(self->desc, &mp_type_tuple)) {
|
||||||
mp_raise_TypeError(translate("struct: cannot index"));
|
mp_raise_TypeError(MP_ERROR_TEXT("struct: can't index"));
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
|
||||||
|
@ -552,7 +539,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t base_in, mp_obj_t index_in, mp_ob
|
||||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||||
if (index >= arr_sz) {
|
if (index >= arr_sz) {
|
||||||
mp_raise_IndexError_varg(translate("%q index out of range"), MP_QSTR_struct);
|
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("struct: index out of range"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->len == 2) {
|
if (t->len == 2) {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
|
STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
|
||||||
if (!mp_obj_is_type(heap_in, &mp_type_list)) {
|
if (!mp_obj_is_type(heap_in, &mp_type_list)) {
|
||||||
mp_raise_TypeError(translate("heap must be a list"));
|
mp_raise_TypeError(MP_ERROR_TEXT("heap must be a list"));
|
||||||
}
|
}
|
||||||
return MP_OBJ_TO_PTR(heap_in);
|
return MP_OBJ_TO_PTR(heap_in);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
|
||||||
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||||
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
mp_obj_list_t *heap = uheapq_get_heap(heap_in);
|
||||||
if (heap->len == 0) {
|
if (heap->len == 0) {
|
||||||
mp_raise_IndexError(translate("empty heap"));
|
mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
|
||||||
}
|
}
|
||||||
mp_obj_t item = heap->items[0];
|
mp_obj_t item = heap->items[0];
|
||||||
heap->len -= 1;
|
heap->len -= 1;
|
||||||
|
|
|
@ -135,7 +135,7 @@ STATIC mp_obj_t _mod_ujson_load(mp_obj_t stream_obj, bool return_first_json) {
|
||||||
stack.len = 0;
|
stack.len = 0;
|
||||||
stack.items = NULL;
|
stack.items = NULL;
|
||||||
mp_obj_t stack_top = MP_OBJ_NULL;
|
mp_obj_t stack_top = MP_OBJ_NULL;
|
||||||
mp_obj_type_t *stack_top_type = NULL;
|
const mp_obj_type_t *stack_top_type = NULL;
|
||||||
mp_obj_t stack_key = MP_OBJ_NULL;
|
mp_obj_t stack_key = MP_OBJ_NULL;
|
||||||
S_NEXT(s);
|
S_NEXT(s);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -339,7 +339,7 @@ success:
|
||||||
return stack_top;
|
return stack_top;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
mp_raise_ValueError(translate("syntax error in JSON"));
|
mp_raise_ValueError(MP_ERROR_TEXT("syntax error in JSON"));
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
|
STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
|
||||||
|
|
|
@ -132,7 +132,7 @@ STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
|
return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
|
||||||
} else {
|
} else {
|
||||||
nlr_raise(mp_obj_new_exception(&mp_type_IndexError));
|
mp_raise_type(&mp_type_IndexError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
|
||||||
|
@ -141,21 +141,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
|
||||||
|
|
||||||
// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
|
// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
|
||||||
STATIC mp_float_t yasmarang_float(void) {
|
STATIC mp_float_t yasmarang_float(void) {
|
||||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
mp_float_union_t u;
|
||||||
typedef uint64_t mp_float_int_t;
|
|
||||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
|
||||||
typedef uint32_t mp_float_int_t;
|
|
||||||
#endif
|
|
||||||
union {
|
|
||||||
mp_float_t f;
|
|
||||||
#if MP_ENDIANNESS_LITTLE
|
|
||||||
struct { mp_float_int_t frc : MP_FLOAT_FRAC_BITS, exp : MP_FLOAT_EXP_BITS, sgn : 1;
|
|
||||||
} p;
|
|
||||||
#else
|
|
||||||
struct { mp_float_int_t sgn : 1, exp : MP_FLOAT_EXP_BITS, frc : MP_FLOAT_FRAC_BITS;
|
|
||||||
} p;
|
|
||||||
#endif
|
|
||||||
} u;
|
|
||||||
u.p.sgn = 0;
|
u.p.sgn = 0;
|
||||||
u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
|
u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
|
||||||
if (MP_FLOAT_FRAC_BITS <= 32) {
|
if (MP_FLOAT_FRAC_BITS <= 32) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "re1.5/re1.5.h"
|
#include "re1.5/re1.5.h"
|
||||||
|
|
||||||
#if CIRCUITPY_RE_DEBUG
|
#if MICROPY_PY_URE_DEBUG
|
||||||
#define FLAG_DEBUG 0x1000
|
#define FLAG_DEBUG 0x1000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,6 +34,10 @@ typedef struct _mp_obj_match_t {
|
||||||
const char *caps[0];
|
const char *caps[0];
|
||||||
} mp_obj_match_t;
|
} mp_obj_match_t;
|
||||||
|
|
||||||
|
STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args);
|
||||||
|
#if !MICROPY_ENABLE_DYNRUNTIME
|
||||||
|
STATIC const mp_obj_type_t re_type;
|
||||||
|
#endif
|
||||||
|
|
||||||
STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
(void)kind;
|
(void)kind;
|
||||||
|
@ -156,7 +160,12 @@ STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
|
||||||
|
|
||||||
STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||||
(void)n_args;
|
(void)n_args;
|
||||||
mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
|
mp_obj_re_t *self;
|
||||||
|
if (mp_obj_is_type(args[0], &re_type)) {
|
||||||
|
self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
} else {
|
||||||
|
self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
|
||||||
|
}
|
||||||
Subject subj;
|
Subject subj;
|
||||||
size_t len;
|
size_t len;
|
||||||
subj.begin = mp_obj_str_get_data(args[1], &len);
|
subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||||
|
@ -245,7 +254,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
|
mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
|
||||||
mp_obj_list_append(retval, s);
|
mp_obj_list_append(retval, s);
|
||||||
if (self->re.sub > 0) {
|
if (self->re.sub > 0) {
|
||||||
mp_raise_NotImplementedError(translate("Splitting with sub-captures"));
|
mp_raise_NotImplementedError(MP_ERROR_TEXT("Splitting with sub-captures"));
|
||||||
}
|
}
|
||||||
subj.begin = caps[1];
|
subj.begin = caps[1];
|
||||||
if (maxsplit > 0 && --maxsplit == 0) {
|
if (maxsplit > 0 && --maxsplit == 0) {
|
||||||
|
@ -408,7 +417,7 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||||
}
|
}
|
||||||
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
|
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
|
||||||
o->base.type = &re_type;
|
o->base.type = &re_type;
|
||||||
#if CIRCUITPY_RE_DEBUG
|
#if MICROPY_PY_URE_DEBUG
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (n_args > 1) {
|
if (n_args > 1) {
|
||||||
flags = mp_obj_get_int(args[1]);
|
flags = mp_obj_get_int(args[1]);
|
||||||
|
@ -419,9 +428,9 @@ STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||||
int error = re1_5_compilecode(&o->re, re_str);
|
int error = re1_5_compilecode(&o->re, re_str);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
error:
|
error:
|
||||||
mp_raise_ValueError(translate("Error in regex"));
|
mp_raise_ValueError(MP_ERROR_TEXT("Error in regex"));
|
||||||
}
|
}
|
||||||
#if CIRCUITPY_RE_DEBUG
|
#if MICROPY_PY_URE_DEBUG
|
||||||
if (flags & FLAG_DEBUG) {
|
if (flags & FLAG_DEBUG) {
|
||||||
re1_5_dumpcode(&o->re);
|
re1_5_dumpcode(&o->re);
|
||||||
}
|
}
|
||||||
|
@ -452,7 +461,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);
|
||||||
#if MICROPY_PY_URE_SUB
|
#if MICROPY_PY_URE_SUB
|
||||||
STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mod_re_sub(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_t self = mod_re_compile(1, args);
|
mp_obj_t self = mod_re_compile(1, args);
|
||||||
return re_sub_helper(self, n_args, args);
|
return re_sub_helper(MP_OBJ_TO_PTR(self), n_args, args);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_sub_obj, 3, 5, mod_re_sub);
|
||||||
#endif
|
#endif
|
||||||
|
@ -470,7 +479,7 @@ STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
|
||||||
#if MICROPY_PY_URE_SUB
|
#if MICROPY_PY_URE_SUB
|
||||||
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&mod_re_sub_obj) },
|
||||||
#endif
|
#endif
|
||||||
#if CIRCUITPY_RE_DEBUG
|
#if MICROPY_PY_URE_DEBUG
|
||||||
{ MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
|
{ MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -488,7 +497,7 @@ const mp_obj_module_t mp_module_ure = {
|
||||||
|
|
||||||
#define re1_5_fatal(x) assert(!x)
|
#define re1_5_fatal(x) assert(!x)
|
||||||
#include "re1.5/compilecode.c"
|
#include "re1.5/compilecode.c"
|
||||||
#if CIRCUITPY_RE_DEBUG
|
#if MICROPY_PY_URE_DEBUG
|
||||||
#include "re1.5/dumpcode.c"
|
#include "re1.5/dumpcode.c"
|
||||||
#endif
|
#endif
|
||||||
#include "re1.5/recursiveloop.c"
|
#include "re1.5/recursiveloop.c"
|
||||||
|
|
|
@ -105,7 +105,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||||
if (n_args == 4) {
|
if (n_args == 4) {
|
||||||
if (args[3] != mp_const_none) {
|
if (args[3] != mp_const_none) {
|
||||||
#if MICROPY_PY_BUILTINS_FLOAT
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
float timeout_f = mp_obj_get_float(args[3]);
|
float timeout_f = mp_obj_get_float_to_f(args[3]);
|
||||||
if (timeout_f >= 0) {
|
if (timeout_f >= 0) {
|
||||||
timeout = (mp_uint_t)(timeout_f * 1000);
|
timeout = (mp_uint_t)(timeout_f * 1000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_t heap_in = args[0];
|
mp_obj_t heap_in = args[0];
|
||||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||||
if (heap->len == heap->alloc) {
|
if (heap->len == heap->alloc) {
|
||||||
mp_raise_IndexError(translate("queue overflow"));
|
mp_raise_IndexError(MP_ERROR_TEXT("queue overflow"));
|
||||||
}
|
}
|
||||||
mp_uint_t l = heap->len;
|
mp_uint_t l = heap->len;
|
||||||
heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);
|
||||||
|
@ -123,7 +123,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_ut
|
||||||
STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
|
STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
|
||||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||||
if (heap->len == 0) {
|
if (heap->len == 0) {
|
||||||
mp_raise_IndexError(translate("empty heap"));
|
mp_raise_IndexError(MP_ERROR_TEXT("empty heap"));
|
||||||
}
|
}
|
||||||
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
|
mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
|
||||||
if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
|
if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
|
||||||
|
@ -148,7 +148,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
|
||||||
STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
|
STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
|
||||||
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
|
||||||
if (heap->len == 0) {
|
if (heap->len == 0) {
|
||||||
mp_raise_IndexError(translate("empty heap"));
|
mp_raise_IndexError(MP_ERROR_TEXT("empty heap"));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct qentry *item = &heap->items[0];
|
struct qentry *item = &heap->items[0];
|
||||||
|
|
|
@ -43,7 +43,7 @@ STATIC int read_src_stream(TINF_DATA *data) {
|
||||||
mp_raise_OSError(err);
|
mp_raise_OSError(err);
|
||||||
}
|
}
|
||||||
if (out_sz == 0) {
|
if (out_sz == 0) {
|
||||||
nlr_raise(mp_obj_new_exception(&mp_type_EOFError));
|
mp_raise_type(&mp_type_EOFError);
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, cons
|
||||||
dict_opt = uzlib_zlib_parse_header(&o->decomp);
|
dict_opt = uzlib_zlib_parse_header(&o->decomp);
|
||||||
if (dict_opt < 0) {
|
if (dict_opt < 0) {
|
||||||
header_error:
|
header_error:
|
||||||
mp_raise_ValueError(translate("compression header"));
|
mp_raise_ValueError(MP_ERROR_TEXT("compression header"));
|
||||||
}
|
}
|
||||||
dict_sz = 1 << dict_opt;
|
dict_sz = 1 << dict_opt;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -87,6 +87,9 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
|
||||||
PC++; // Skip # of pair byte
|
PC++; // Skip # of pair byte
|
||||||
prog->len++;
|
prog->len++;
|
||||||
for (cnt = 0; *re != ']'; re++, cnt++) {
|
for (cnt = 0; *re != ']'; re++, cnt++) {
|
||||||
|
if (*re == '\\') {
|
||||||
|
++re;
|
||||||
|
}
|
||||||
if (!*re) return NULL;
|
if (!*re) return NULL;
|
||||||
const char *b = re;
|
const char *b = re;
|
||||||
if (*re == '\\') {
|
if (*re == '\\') {
|
||||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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,
|
||||||
|
)
|
|
@ -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?
|
|
@ -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) {
|
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
enum { ARG_readonly, ARG_mkfs };
|
enum { ARG_readonly, ARG_mkfs };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
|
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} },
|
||||||
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
|
{ MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} },
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse args
|
// parse args
|
||||||
|
@ -277,10 +277,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount);
|
||||||
mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
enum { ARG_file, ARG_mode, ARG_encoding };
|
enum { ARG_file, ARG_mode, ARG_encoding };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
|
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
|
||||||
{ MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} },
|
{ MP_QSTR_buffering, MP_ARG_INT, {.u_int = -1} },
|
||||||
{ MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_encoding, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse args
|
// parse args
|
||||||
|
@ -302,7 +302,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open);
|
||||||
mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
|
mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
|
||||||
mp_obj_t path_out;
|
mp_obj_t path_out;
|
||||||
mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);
|
mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out);
|
||||||
MP_STATE_VM(vfs_cur) = vfs;
|
|
||||||
if (vfs == MP_VFS_ROOT) {
|
if (vfs == MP_VFS_ROOT) {
|
||||||
// If we change to the root dir and a VFS is mounted at the root then
|
// If we change to the root dir and a VFS is mounted at the root then
|
||||||
// we must change that VFS's current dir to the root dir so that any
|
// we must change that VFS's current dir to the root dir so that any
|
||||||
|
@ -314,9 +313,11 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vfs = MP_VFS_ROOT;
|
||||||
} else {
|
} else {
|
||||||
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out);
|
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out);
|
||||||
}
|
}
|
||||||
|
MP_STATE_VM(vfs_cur) = vfs;
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir);
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir);
|
||||||
|
@ -493,4 +494,25 @@ mp_obj_t mp_vfs_statvfs(mp_obj_t path_in) {
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs);
|
MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs);
|
||||||
|
|
||||||
|
// This is a C-level helper function for ports to use if needed.
|
||||||
|
int mp_vfs_mount_and_chdir_protected(mp_obj_t bdev, mp_obj_t mount_point) {
|
||||||
|
nlr_buf_t nlr;
|
||||||
|
mp_int_t ret = -MP_EIO;
|
||||||
|
if (nlr_push(&nlr) == 0) {
|
||||||
|
mp_obj_t args[] = { bdev, mount_point };
|
||||||
|
mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map);
|
||||||
|
mp_vfs_chdir(mount_point);
|
||||||
|
ret = 0; // success
|
||||||
|
nlr_pop();
|
||||||
|
} else {
|
||||||
|
mp_obj_base_t *exc = nlr.ret_val;
|
||||||
|
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_OSError))) {
|
||||||
|
mp_obj_t v = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
|
||||||
|
mp_obj_get_int_maybe(v, &ret); // get errno value
|
||||||
|
ret = -ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MICROPY_VFS
|
#endif // MICROPY_VFS
|
||||||
|
|
|
@ -101,6 +101,7 @@ mp_obj_t mp_vfs_rmdir(mp_obj_t path_in);
|
||||||
mp_obj_t mp_vfs_stat(mp_obj_t path_in);
|
mp_obj_t mp_vfs_stat(mp_obj_t path_in);
|
||||||
mp_obj_t mp_vfs_statvfs(mp_obj_t path_in);
|
mp_obj_t mp_vfs_statvfs(mp_obj_t path_in);
|
||||||
|
|
||||||
|
int mp_vfs_mount_and_chdir_protected(mp_obj_t bdev, mp_obj_t mount_point);
|
||||||
mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in);
|
mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in);
|
||||||
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj);
|
MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "py/obj.h"
|
||||||
#include "py/objproperty.h"
|
#include "py/objproperty.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
|
@ -440,7 +441,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
|
||||||
.base.type = &mp_type_property,
|
.base.type = &mp_type_property,
|
||||||
.proxy = {(mp_obj_t)&fat_vfs_getlabel_obj,
|
.proxy = {(mp_obj_t)&fat_vfs_getlabel_obj,
|
||||||
(mp_obj_t)&fat_vfs_setlabel_obj,
|
(mp_obj_t)&fat_vfs_setlabel_obj,
|
||||||
(mp_obj_t)&mp_const_none_obj},
|
MP_ROM_NONE},
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -130,9 +130,9 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
|
||||||
// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
|
// Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
|
||||||
// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor
|
// but by adding it here we can use one single mp_arg_t array for open() and FileIO's constructor
|
||||||
STATIC const mp_arg_t file_open_args[] = {
|
STATIC const mp_arg_t file_open_args[] = {
|
||||||
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },
|
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_r)} },
|
||||||
{ MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_encoding, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
};
|
};
|
||||||
#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)
|
#define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 Damien P. George
|
* Copyright (c) 2019-2020 Damien P. George
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -25,18 +25,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
#include "py/mphal.h"
|
||||||
#include "extmod/vfs.h"
|
#include "extmod/vfs.h"
|
||||||
#include "extmod/vfs_lfs.h"
|
#include "extmod/vfs_lfs.h"
|
||||||
|
|
||||||
#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
|
#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
|
||||||
|
|
||||||
enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead };
|
enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime };
|
||||||
|
|
||||||
static const mp_arg_t lfs_make_allowed_args[] = {
|
static const mp_arg_t lfs_make_allowed_args[] = {
|
||||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
{ MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
{ MP_QSTR_readsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
||||||
{ MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
{ MP_QSTR_progsize, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
||||||
{ MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
{ MP_QSTR_lookahead, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 32} },
|
||||||
|
{ MP_QSTR_mtime, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
|
||||||
};
|
};
|
||||||
|
|
||||||
#if MICROPY_VFS_LFS1
|
#if MICROPY_VFS_LFS1
|
||||||
|
@ -98,9 +100,13 @@ mp_obj_t mp_vfs_lfs1_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode
|
||||||
#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2
|
#define MP_TYPE_VFS_LFSx mp_type_vfs_lfs2
|
||||||
#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2##s
|
#define MP_TYPE_VFS_LFSx_(s) mp_type_vfs_lfs2##s
|
||||||
|
|
||||||
|
// Attribute ids for lfs2_attr.type.
|
||||||
|
#define LFS_ATTR_MTIME (1) // 64-bit little endian, nanoseconds since 1970/1/1
|
||||||
|
|
||||||
typedef struct _mp_obj_vfs_lfs2_t {
|
typedef struct _mp_obj_vfs_lfs2_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_vfs_blockdev_t blockdev;
|
mp_vfs_blockdev_t blockdev;
|
||||||
|
bool enable_mtime;
|
||||||
vstr_t cur_dir;
|
vstr_t cur_dir;
|
||||||
struct lfs2_config config;
|
struct lfs2_config config;
|
||||||
lfs2_t lfs;
|
lfs2_t lfs;
|
||||||
|
@ -109,14 +115,25 @@ typedef struct _mp_obj_vfs_lfs2_t {
|
||||||
typedef struct _mp_obj_vfs_lfs2_file_t {
|
typedef struct _mp_obj_vfs_lfs2_file_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_obj_vfs_lfs2_t *vfs;
|
mp_obj_vfs_lfs2_t *vfs;
|
||||||
|
uint8_t mtime[8];
|
||||||
lfs2_file_t file;
|
lfs2_file_t file;
|
||||||
struct lfs2_file_config cfg;
|
struct lfs2_file_config cfg;
|
||||||
|
struct lfs2_attr attrs[1];
|
||||||
uint8_t file_buffer[0];
|
uint8_t file_buffer[0];
|
||||||
} mp_obj_vfs_lfs2_file_t;
|
} mp_obj_vfs_lfs2_file_t;
|
||||||
|
|
||||||
const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in);
|
const char *mp_vfs_lfs2_make_path(mp_obj_vfs_lfs2_t *self, mp_obj_t path_in);
|
||||||
mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in);
|
mp_obj_t mp_vfs_lfs2_file_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in);
|
||||||
|
|
||||||
|
STATIC void lfs_get_mtime(uint8_t buf[8]) {
|
||||||
|
uint64_t ns = mp_hal_time_ns();
|
||||||
|
// Store "ns" to "buf" in little-endian format (essentially htole64).
|
||||||
|
for (size_t i = 0; i < 8; ++i) {
|
||||||
|
buf[i] = ns;
|
||||||
|
ns >>= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "extmod/vfs_lfsx.c"
|
#include "extmod/vfs_lfsx.c"
|
||||||
#include "extmod/vfs_lfsx_file.c"
|
#include "extmod/vfs_lfsx_file.c"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 Damien P. George
|
* Copyright (c) 2019-2020 Damien P. George
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -31,8 +31,10 @@
|
||||||
#include "py/stream.h"
|
#include "py/stream.h"
|
||||||
#include "py/binary.h"
|
#include "py/binary.h"
|
||||||
#include "py/objarray.h"
|
#include "py/objarray.h"
|
||||||
|
#include "py/objstr.h"
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
#include "extmod/vfs.h"
|
#include "extmod/vfs.h"
|
||||||
|
#include "lib/timeutils/timeutils.h"
|
||||||
|
|
||||||
STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
|
STATIC int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
|
||||||
mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
|
mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
|
||||||
|
@ -119,6 +121,9 @@ STATIC mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t * type, size_t n_args,
|
||||||
self->base.type = type;
|
self->base.type = type;
|
||||||
vstr_init(&self->cur_dir, 16);
|
vstr_init(&self->cur_dir, 16);
|
||||||
vstr_add_byte(&self->cur_dir, '/');
|
vstr_add_byte(&self->cur_dir, '/');
|
||||||
|
#if LFS_BUILD_VERSION == 2
|
||||||
|
self->enable_mtime = args[LFS_MAKE_ARG_mtime].u_bool;
|
||||||
|
#endif
|
||||||
MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
|
MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
|
||||||
args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
|
args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
|
||||||
int ret = LFSx_API(mount)(&self->lfs, &self->config);
|
int ret = LFSx_API(mount)(&self->lfs, &self->config);
|
||||||
|
@ -236,10 +241,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(rmdir_obj), MP_VFS_LFSx(rmdir));
|
||||||
STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) {
|
STATIC mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) {
|
||||||
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
|
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
|
||||||
const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in);
|
const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in);
|
||||||
|
const char *path = mp_obj_str_get_str(path_new_in);
|
||||||
vstr_t path_new;
|
vstr_t path_new;
|
||||||
vstr_init(&path_new, vstr_len(&self->cur_dir));
|
vstr_init(&path_new, vstr_len(&self->cur_dir));
|
||||||
|
if (path[0] != '/') {
|
||||||
vstr_add_strn(&path_new, vstr_str(&self->cur_dir), 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));
|
}
|
||||||
|
vstr_add_str(&path_new, path);
|
||||||
int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new));
|
int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new));
|
||||||
vstr_clear(&path_new);
|
vstr_clear(&path_new);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -283,8 +291,45 @@ STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not at root add trailing / to make it easy to build paths
|
// If not at root add trailing / to make it easy to build paths
|
||||||
|
// and then normalise the path
|
||||||
if (vstr_len(&self->cur_dir) != 1) {
|
if (vstr_len(&self->cur_dir) != 1) {
|
||||||
vstr_add_byte(&self->cur_dir, '/');
|
vstr_add_byte(&self->cur_dir, '/');
|
||||||
|
|
||||||
|
#define CWD_LEN (vstr_len(&self->cur_dir))
|
||||||
|
size_t to = 1;
|
||||||
|
size_t from = 1;
|
||||||
|
char *cwd = vstr_str(&self->cur_dir);
|
||||||
|
while (from < CWD_LEN) {
|
||||||
|
for (; cwd[from] == '/' && from < CWD_LEN; ++from) {
|
||||||
|
// Scan for the start
|
||||||
|
}
|
||||||
|
if (from > to) {
|
||||||
|
// Found excessive slash chars, squeeze them out
|
||||||
|
vstr_cut_out_bytes(&self->cur_dir, to, from - to);
|
||||||
|
from = to;
|
||||||
|
}
|
||||||
|
for (; cwd[from] != '/' && from < CWD_LEN; ++from) {
|
||||||
|
// Scan for the next /
|
||||||
|
}
|
||||||
|
if ((from - to) == 1 && cwd[to] == '.') {
|
||||||
|
// './', ignore
|
||||||
|
vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
|
||||||
|
from = to;
|
||||||
|
} else if ((from - to) == 2 && cwd[to] == '.' && cwd[to + 1] == '.') {
|
||||||
|
// '../', skip back
|
||||||
|
if (to > 1) {
|
||||||
|
// Only skip back if not at the tip
|
||||||
|
for (--to; to > 1 && cwd[to - 1] != '/'; --to) {
|
||||||
|
// Skip back
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
|
||||||
|
from = to;
|
||||||
|
} else {
|
||||||
|
// Normal element, keep it and just move the offset
|
||||||
|
to = ++from;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
|
@ -304,13 +349,29 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(getcwd_obj), MP_VFS_LFSx(getcwd));
|
||||||
|
|
||||||
STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
|
STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
|
MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
|
||||||
const char *path = mp_obj_str_get_str(path_in);
|
const char *path = MP_VFS_LFSx(make_path)(self, path_in);
|
||||||
struct LFSx_API (info) info;
|
struct LFSx_API (info) info;
|
||||||
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
mp_raise_OSError(-ret);
|
mp_raise_OSError(-ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_uint_t mtime = 0;
|
||||||
|
#if LFS_BUILD_VERSION == 2
|
||||||
|
uint8_t mtime_buf[8];
|
||||||
|
lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
|
||||||
|
if (sz == sizeof(mtime_buf)) {
|
||||||
|
uint64_t ns = 0;
|
||||||
|
for (size_t i = sizeof(mtime_buf); i > 0; --i) {
|
||||||
|
ns = ns << 8 | mtime_buf[i - 1];
|
||||||
|
}
|
||||||
|
mtime = timeutils_seconds_since_2000_from_nanoseconds_since_1970(ns);
|
||||||
|
#if MICROPY_EPOCH_IS_1970
|
||||||
|
mtime += TIMEUTILS_SECONDS_1970_TO_2000;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode
|
t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode
|
||||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
|
t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
|
||||||
|
@ -319,9 +380,9 @@ STATIC mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||||
t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
|
t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
|
||||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime
|
t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
|
||||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime
|
t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
|
||||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime
|
t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
|
||||||
|
|
||||||
return MP_OBJ_FROM_PTR(t);
|
return MP_OBJ_FROM_PTR(t);
|
||||||
}
|
}
|
||||||
|
@ -400,6 +461,8 @@ STATIC MP_DEFINE_CONST_DICT(MP_VFS_LFSx(locals_dict), MP_VFS_LFSx(locals_dict_ta
|
||||||
STATIC mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) {
|
STATIC mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) {
|
||||||
MP_OBJ_VFS_LFSx *self = self_in;
|
MP_OBJ_VFS_LFSx *self = self_in;
|
||||||
struct LFSx_API (info) info;
|
struct LFSx_API (info) info;
|
||||||
|
mp_obj_str_t path_obj = { { &mp_type_str }, 0, 0, (const byte *)path };
|
||||||
|
path = MP_VFS_LFSx(make_path)(self, MP_OBJ_FROM_PTR(&path_obj));
|
||||||
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (info.type == LFSx_MACRO(_TYPE_REG)) {
|
if (info.type == LFSx_MACRO(_TYPE_REG)) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019 Damien P. George
|
* Copyright (c) 2019-2020 Damien P. George
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -101,6 +101,17 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod
|
||||||
#endif
|
#endif
|
||||||
o->cfg.buffer = &o->file_buffer[0];
|
o->cfg.buffer = &o->file_buffer[0];
|
||||||
|
|
||||||
|
#if LFS_BUILD_VERSION == 2
|
||||||
|
if (self->enable_mtime) {
|
||||||
|
lfs_get_mtime(&o->mtime[0]);
|
||||||
|
o->attrs[0].type = LFS_ATTR_MTIME;
|
||||||
|
o->attrs[0].buffer = &o->mtime[0];
|
||||||
|
o->attrs[0].size = sizeof(o->mtime);
|
||||||
|
o->cfg.attrs = &o->attrs[0];
|
||||||
|
o->cfg.attr_count = MP_ARRAY_SIZE(o->attrs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *path = MP_VFS_LFSx(make_path)(self, path_in);
|
const char *path = MP_VFS_LFSx(make_path)(self, path_in);
|
||||||
int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg);
|
int ret = LFSx_API(file_opencfg)(&self->lfs, &o->file, path, flags, &o->cfg);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -131,6 +142,11 @@ STATIC mp_uint_t MP_VFS_LFSx(file_read)(mp_obj_t self_in, void *buf, mp_uint_t s
|
||||||
STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
STATIC mp_uint_t MP_VFS_LFSx(file_write)(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||||
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
|
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
|
||||||
MP_VFS_LFSx(check_open)(self);
|
MP_VFS_LFSx(check_open)(self);
|
||||||
|
#if LFS_BUILD_VERSION == 2
|
||||||
|
if (self->vfs->enable_mtime) {
|
||||||
|
lfs_get_mtime(&self->mtime[0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size);
|
LFSx_API(ssize_t) sz = LFSx_API(file_write)(&self->vfs->lfs, &self->file, buf, size);
|
||||||
if (sz < 0) {
|
if (sz < 0) {
|
||||||
*errcode = -sz;
|
*errcode = -sz;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
|
#include "py/mphal.h"
|
||||||
|
#include "py/mpthread.h"
|
||||||
#include "extmod/vfs.h"
|
#include "extmod/vfs.h"
|
||||||
#include "extmod/vfs_posix.h"
|
#include "extmod/vfs_posix.h"
|
||||||
|
|
||||||
|
@ -149,12 +151,15 @@ STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
struct dirent *dirent = readdir(self->dir);
|
struct dirent *dirent = readdir(self->dir);
|
||||||
if (dirent == NULL) {
|
if (dirent == NULL) {
|
||||||
closedir(self->dir);
|
closedir(self->dir);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
self->dir = NULL;
|
self->dir = NULL;
|
||||||
return MP_OBJ_STOP_ITERATION;
|
return MP_OBJ_STOP_ITERATION;
|
||||||
}
|
}
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
const char *fn = dirent->d_name;
|
const char *fn = dirent->d_name;
|
||||||
|
|
||||||
if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
|
if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
|
||||||
|
@ -208,7 +213,9 @@ STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
if (path[0] == '\0') {
|
if (path[0] == '\0') {
|
||||||
path = ".";
|
path = ".";
|
||||||
}
|
}
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
iter->dir = opendir(path);
|
iter->dir = opendir(path);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
if (iter->dir == NULL) {
|
if (iter->dir == NULL) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
}
|
}
|
||||||
|
@ -224,7 +231,10 @@ typedef struct _mp_obj_listdir_t {
|
||||||
|
|
||||||
STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
|
STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777);
|
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
|
int ret = mkdir(path, 0777);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
}
|
}
|
||||||
|
@ -241,7 +251,9 @@ STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_
|
||||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
|
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
|
||||||
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
|
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
int ret = rename(old_path, new_path);
|
int ret = rename(old_path, new_path);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
mp_raise_OSError(errno);
|
mp_raise_OSError(errno);
|
||||||
}
|
}
|
||||||
|
@ -257,21 +269,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);
|
||||||
STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
|
STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int ret = stat(vfs_posix_get_path_str(self, path_in), &sb);
|
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||||
if (ret != 0) {
|
int ret;
|
||||||
mp_raise_OSError(errno);
|
MP_HAL_RETRY_SYSCALL(ret, stat(path, &sb), mp_raise_OSError(err));
|
||||||
}
|
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
|
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
|
||||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);
|
t->items[1] = mp_obj_new_int_from_uint(sb.st_ino);
|
||||||
t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev);
|
t->items[2] = mp_obj_new_int_from_uint(sb.st_dev);
|
||||||
t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink);
|
t->items[3] = mp_obj_new_int_from_uint(sb.st_nlink);
|
||||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid);
|
t->items[4] = mp_obj_new_int_from_uint(sb.st_uid);
|
||||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid);
|
t->items[5] = mp_obj_new_int_from_uint(sb.st_gid);
|
||||||
t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size);
|
t->items[6] = mp_obj_new_int_from_uint(sb.st_size);
|
||||||
t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime);
|
t->items[7] = mp_obj_new_int_from_uint(sb.st_atime);
|
||||||
t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime);
|
t->items[8] = mp_obj_new_int_from_uint(sb.st_mtime);
|
||||||
t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime);
|
t->items[9] = mp_obj_new_int_from_uint(sb.st_ctime);
|
||||||
return MP_OBJ_FROM_PTR(t);
|
return MP_OBJ_FROM_PTR(t);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
|
||||||
|
@ -300,10 +311,8 @@ STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
|
||||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
STRUCT_STATVFS sb;
|
STRUCT_STATVFS sb;
|
||||||
const char *path = vfs_posix_get_path_str(self, path_in);
|
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||||
int ret = STATVFS(path, &sb);
|
int ret;
|
||||||
if (ret != 0) {
|
MP_HAL_RETRY_SYSCALL(ret, STATVFS(path, &sb), mp_raise_OSError(err));
|
||||||
mp_raise_OSError(errno);
|
|
||||||
}
|
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
|
||||||
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
|
t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
|
||||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);
|
t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);
|
||||||
|
|
|
@ -3,14 +3,17 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
#include "py/mpthread.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/stream.h"
|
#include "py/stream.h"
|
||||||
#include "extmod/vfs_posix.h"
|
#include "extmod/vfs_posix.h"
|
||||||
#include "supervisor/shared/translate.h"
|
#include "supervisor/shared/translate.h"
|
||||||
|
|
||||||
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX
|
#if defined(MICROPY_VFS_POSIX) && MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define fsync _commit
|
#define fsync _commit
|
||||||
|
@ -24,7 +27,7 @@ typedef struct _mp_obj_vfs_posix_file_t {
|
||||||
#ifdef MICROPY_CPYTHON_COMPAT
|
#ifdef MICROPY_CPYTHON_COMPAT
|
||||||
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
|
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
|
||||||
if (o->fd < 0) {
|
if (o->fd < 0) {
|
||||||
mp_raise_ValueError(translate("I/O operation on closed file"));
|
mp_raise_ValueError(MP_ERROR_TEXT("I/O operation on closed file"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -80,17 +83,15 @@ mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *fname = mp_obj_str_get_str(fid);
|
const char *fname = mp_obj_str_get_str(fid);
|
||||||
int fd = open(fname, mode_x | mode_rw, 0644);
|
int fd;
|
||||||
if (fd == -1) {
|
MP_HAL_RETRY_SYSCALL(fd, open(fname, mode_x | mode_rw, 0644), mp_raise_OSError(err));
|
||||||
mp_raise_OSError(errno);
|
|
||||||
}
|
|
||||||
o->fd = fd;
|
o->fd = fd;
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
|
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,46 +116,49 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vf
|
||||||
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
|
||||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||||
check_fd_is_open(o);
|
check_fd_is_open(o);
|
||||||
mp_int_t r = read(o->fd, buf, size);
|
ssize_t r;
|
||||||
if (r == -1) {
|
MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
|
||||||
*errcode = errno;
|
*errcode = err;
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
}
|
});
|
||||||
return r;
|
return (mp_uint_t)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||||
check_fd_is_open(o);
|
check_fd_is_open(o);
|
||||||
mp_int_t r = write(o->fd, buf, size);
|
ssize_t r;
|
||||||
while (r == -1 && errno == EINTR) {
|
MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
|
||||||
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
|
*errcode = err;
|
||||||
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
|
|
||||||
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
|
|
||||||
nlr_raise(obj);
|
|
||||||
}
|
|
||||||
r = write(o->fd, buf, size);
|
|
||||||
}
|
|
||||||
if (r == -1) {
|
|
||||||
*errcode = errno;
|
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
}
|
});
|
||||||
return r;
|
return (mp_uint_t)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||||
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
|
||||||
check_fd_is_open(o);
|
check_fd_is_open(o);
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case MP_STREAM_FLUSH:
|
case MP_STREAM_FLUSH: {
|
||||||
if (fsync(o->fd) < 0) {
|
int ret;
|
||||||
*errcode = errno;
|
MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), {
|
||||||
return MP_STREAM_ERROR;
|
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;
|
return 0;
|
||||||
|
}
|
||||||
|
*errcode = err;
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case MP_STREAM_SEEK: {
|
case MP_STREAM_SEEK: {
|
||||||
struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
|
struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
off_t off = lseek(o->fd, s->offset, s->whence);
|
off_t off = lseek(o->fd, s->offset, s->whence);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
if (off == (off_t)-1) {
|
if (off == (off_t)-1) {
|
||||||
*errcode = errno;
|
*errcode = errno;
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
|
@ -163,11 +167,15 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case MP_STREAM_CLOSE:
|
case MP_STREAM_CLOSE:
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
close(o->fd);
|
close(o->fd);
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
#ifdef MICROPY_CPYTHON_COMPAT
|
#ifdef MICROPY_CPYTHON_COMPAT
|
||||||
o->fd = -1;
|
o->fd = -1;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
case MP_STREAM_GET_FILENO:
|
||||||
|
return o->fd;
|
||||||
default:
|
default:
|
||||||
*errcode = EINVAL;
|
*errcode = EINVAL;
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
|
@ -234,4 +242,4 @@ const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILEN
|
||||||
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
|
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
|
||||||
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
|
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
|
||||||
|
|
||||||
#endif // MICROPY_VFS_POSIX
|
#endif // MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE
|
||||||
|
|
|
@ -50,8 +50,11 @@ STATIC void mp_reader_vfs_close(void *data) {
|
||||||
|
|
||||||
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
|
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
|
||||||
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
|
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
|
||||||
mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));
|
mp_obj_t args[2] = {
|
||||||
rf->file = mp_vfs_open(1, &arg, (mp_map_t *)&mp_const_empty_map);
|
mp_obj_new_str(filename, strlen(filename)),
|
||||||
|
MP_OBJ_NEW_QSTR(MP_QSTR_rb),
|
||||||
|
};
|
||||||
|
rf->file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map);
|
||||||
int errcode;
|
int errcode;
|
||||||
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);
|
||||||
if (errcode != 0) {
|
if (errcode != 0) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
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;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Public Domain implementation of strncpy from:
|
||||||
|
// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strncpy_function
|
||||||
|
char *strncpy(char *s1, const char *s2, size_t n) {
|
||||||
|
char *dst = s1;
|
||||||
|
const char *src = s2;
|
||||||
|
/* Copy bytes, one at a time. */
|
||||||
|
while (n > 0) {
|
||||||
|
n--;
|
||||||
|
if ((*dst++ = *src++) == '\0') {
|
||||||
|
/* If we get here, we found a null character at the end
|
||||||
|
of s2, so use memset to put null bytes at the end of
|
||||||
|
s1. */
|
||||||
|
memset(dst, '\0', n);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
// needed because gcc optimises strcpy + strcat to this
|
// needed because gcc optimises strcpy + strcat to this
|
||||||
char *stpcpy(char *dest, const char *src) {
|
char *stpcpy(char *dest, const char *src) {
|
||||||
while (*src) {
|
while (*src) {
|
||||||
|
|
|
@ -23,15 +23,15 @@
|
||||||
|
|
||||||
// dpgeorge: pio2 was double in original implementation of asinf
|
// dpgeorge: pio2 was double in original implementation of asinf
|
||||||
static const float
|
static const float
|
||||||
pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */
|
pio2_hi = 1.5707962513e+00f, /* 0x3fc90fda */
|
||||||
pio2_lo = 7.5497894159e-08; /* 0x33a22168 */
|
pio2_lo = 7.5497894159e-08f; /* 0x33a22168 */
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
/* coefficients for R(x^2) */
|
/* coefficients for R(x^2) */
|
||||||
pS0 = 1.6666586697e-01,
|
pS0 = 1.6666586697e-01f,
|
||||||
pS1 = -4.2743422091e-02,
|
pS1 = -4.2743422091e-02f,
|
||||||
pS2 = -8.6563630030e-03,
|
pS2 = -8.6563630030e-03f,
|
||||||
qS1 = -7.0662963390e-01;
|
qS1 = -7.0662963390e-01f;
|
||||||
|
|
||||||
static float R(float z)
|
static float R(float z)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include "libm.h"
|
#include "libm.h"
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
pi = 3.1415927410e+00, /* 0x40490fdb */
|
pi = 3.1415927410e+00f, /* 0x40490fdb */
|
||||||
pi_lo = -8.7422776573e-08; /* 0xb3bbbd2e */
|
pi_lo = -8.7422776573e-08f; /* 0xb3bbbd2e */
|
||||||
|
|
||||||
float atan2f(float y, float x)
|
float atan2f(float y, float x)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,25 +23,25 @@
|
||||||
#include "libm.h"
|
#include "libm.h"
|
||||||
|
|
||||||
static const float atanhi[] = {
|
static const float atanhi[] = {
|
||||||
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
|
4.6364760399e-01f, /* atan(0.5)hi 0x3eed6338 */
|
||||||
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
|
7.8539812565e-01f, /* atan(1.0)hi 0x3f490fda */
|
||||||
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
|
9.8279368877e-01f, /* atan(1.5)hi 0x3f7b985e */
|
||||||
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
|
1.5707962513e+00f, /* atan(inf)hi 0x3fc90fda */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const float atanlo[] = {
|
static const float atanlo[] = {
|
||||||
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
|
5.0121582440e-09f, /* atan(0.5)lo 0x31ac3769 */
|
||||||
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
|
3.7748947079e-08f, /* atan(1.0)lo 0x33222168 */
|
||||||
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
|
3.4473217170e-08f, /* atan(1.5)lo 0x33140fb4 */
|
||||||
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
|
7.5497894159e-08f, /* atan(inf)lo 0x33a22168 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const float aT[] = {
|
static const float aT[] = {
|
||||||
3.3333328366e-01,
|
3.3333328366e-01f,
|
||||||
-1.9999158382e-01,
|
-1.9999158382e-01f,
|
||||||
1.4253635705e-01,
|
1.4253635705e-01f,
|
||||||
-1.0648017377e-01,
|
-1.0648017377e-01f,
|
||||||
6.1687607318e-02,
|
6.1687607318e-02f,
|
||||||
};
|
};
|
||||||
|
|
||||||
float atanf(float x)
|
float atanf(float x)
|
||||||
|
|
|
@ -93,16 +93,16 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
zero = 0.0000000000e+00, /* 0x00000000 */
|
zero = 0.0000000000e+00f, /* 0x00000000 */
|
||||||
half = 5.0000000000e-01, /* 0x3f000000 */
|
half = 5.0000000000e-01f, /* 0x3f000000 */
|
||||||
two8 = 2.5600000000e+02, /* 0x43800000 */
|
two8 = 2.5600000000e+02f, /* 0x43800000 */
|
||||||
invpio2 = 6.3661980629e-01, /* 0x3f22f984 */
|
invpio2 = 6.3661980629e-01f, /* 0x3f22f984 */
|
||||||
pio2_1 = 1.5707855225e+00, /* 0x3fc90f80 */
|
pio2_1 = 1.5707855225e+00f, /* 0x3fc90f80 */
|
||||||
pio2_1t = 1.0804334124e-05, /* 0x37354443 */
|
pio2_1t = 1.0804334124e-05f, /* 0x37354443 */
|
||||||
pio2_2 = 1.0804273188e-05, /* 0x37354400 */
|
pio2_2 = 1.0804273188e-05f, /* 0x37354400 */
|
||||||
pio2_2t = 6.0770999344e-11, /* 0x2e85a308 */
|
pio2_2t = 6.0770999344e-11f, /* 0x2e85a308 */
|
||||||
pio2_3 = 6.0770943833e-11, /* 0x2e85a300 */
|
pio2_3 = 6.0770943833e-11f, /* 0x2e85a300 */
|
||||||
pio2_3t = 6.1232342629e-17; /* 0x248d3132 */
|
pio2_3t = 6.1232342629e-17f; /* 0x248d3132 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
__int32_t __ieee754_rem_pio2f(float x, float *y)
|
__int32_t __ieee754_rem_pio2f(float x, float *y)
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include "fdlibm.h"
|
#include "fdlibm.h"
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
static const float one = 1.0, tiny=1.0e-30;
|
static const float one = 1.0f, tiny=1.0e-30f;
|
||||||
#else
|
#else
|
||||||
static float one = 1.0, tiny=1.0e-30;
|
static float one = 1.0f, tiny=1.0e-30f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined
|
// sqrtf is exactly __ieee754_sqrtf when _IEEE_LIBM defined
|
||||||
|
|
|
@ -33,77 +33,77 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
two23= 8.3886080000e+06, /* 0x4b000000 */
|
two23= 8.3886080000e+06f, /* 0x4b000000 */
|
||||||
half= 5.0000000000e-01, /* 0x3f000000 */
|
half= 5.0000000000e-01f, /* 0x3f000000 */
|
||||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||||
pi = 3.1415927410e+00, /* 0x40490fdb */
|
pi = 3.1415927410e+00f, /* 0x40490fdb */
|
||||||
a0 = 7.7215664089e-02, /* 0x3d9e233f */
|
a0 = 7.7215664089e-02f, /* 0x3d9e233f */
|
||||||
a1 = 3.2246702909e-01, /* 0x3ea51a66 */
|
a1 = 3.2246702909e-01f, /* 0x3ea51a66 */
|
||||||
a2 = 6.7352302372e-02, /* 0x3d89f001 */
|
a2 = 6.7352302372e-02f, /* 0x3d89f001 */
|
||||||
a3 = 2.0580807701e-02, /* 0x3ca89915 */
|
a3 = 2.0580807701e-02f, /* 0x3ca89915 */
|
||||||
a4 = 7.3855509982e-03, /* 0x3bf2027e */
|
a4 = 7.3855509982e-03f, /* 0x3bf2027e */
|
||||||
a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
|
a5 = 2.8905137442e-03f, /* 0x3b3d6ec6 */
|
||||||
a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
|
a6 = 1.1927076848e-03f, /* 0x3a9c54a1 */
|
||||||
a7 = 5.1006977446e-04, /* 0x3a05b634 */
|
a7 = 5.1006977446e-04f, /* 0x3a05b634 */
|
||||||
a8 = 2.2086278477e-04, /* 0x39679767 */
|
a8 = 2.2086278477e-04f, /* 0x39679767 */
|
||||||
a9 = 1.0801156895e-04, /* 0x38e28445 */
|
a9 = 1.0801156895e-04f, /* 0x38e28445 */
|
||||||
a10 = 2.5214456400e-05, /* 0x37d383a2 */
|
a10 = 2.5214456400e-05f, /* 0x37d383a2 */
|
||||||
a11 = 4.4864096708e-05, /* 0x383c2c75 */
|
a11 = 4.4864096708e-05f, /* 0x383c2c75 */
|
||||||
tc = 1.4616321325e+00, /* 0x3fbb16c3 */
|
tc = 1.4616321325e+00f, /* 0x3fbb16c3 */
|
||||||
tf = -1.2148628384e-01, /* 0xbdf8cdcd */
|
tf = -1.2148628384e-01f, /* 0xbdf8cdcd */
|
||||||
/* tt = -(tail of tf) */
|
/* tt = -(tail of tf) */
|
||||||
tt = 6.6971006518e-09, /* 0x31e61c52 */
|
tt = 6.6971006518e-09f, /* 0x31e61c52 */
|
||||||
t0 = 4.8383611441e-01, /* 0x3ef7b95e */
|
t0 = 4.8383611441e-01f, /* 0x3ef7b95e */
|
||||||
t1 = -1.4758771658e-01, /* 0xbe17213c */
|
t1 = -1.4758771658e-01f, /* 0xbe17213c */
|
||||||
t2 = 6.4624942839e-02, /* 0x3d845a15 */
|
t2 = 6.4624942839e-02f, /* 0x3d845a15 */
|
||||||
t3 = -3.2788541168e-02, /* 0xbd064d47 */
|
t3 = -3.2788541168e-02f, /* 0xbd064d47 */
|
||||||
t4 = 1.7970675603e-02, /* 0x3c93373d */
|
t4 = 1.7970675603e-02f, /* 0x3c93373d */
|
||||||
t5 = -1.0314224288e-02, /* 0xbc28fcfe */
|
t5 = -1.0314224288e-02f, /* 0xbc28fcfe */
|
||||||
t6 = 6.1005386524e-03, /* 0x3bc7e707 */
|
t6 = 6.1005386524e-03f, /* 0x3bc7e707 */
|
||||||
t7 = -3.6845202558e-03, /* 0xbb7177fe */
|
t7 = -3.6845202558e-03f, /* 0xbb7177fe */
|
||||||
t8 = 2.2596477065e-03, /* 0x3b141699 */
|
t8 = 2.2596477065e-03f, /* 0x3b141699 */
|
||||||
t9 = -1.4034647029e-03, /* 0xbab7f476 */
|
t9 = -1.4034647029e-03f, /* 0xbab7f476 */
|
||||||
t10 = 8.8108185446e-04, /* 0x3a66f867 */
|
t10 = 8.8108185446e-04f, /* 0x3a66f867 */
|
||||||
t11 = -5.3859531181e-04, /* 0xba0d3085 */
|
t11 = -5.3859531181e-04f, /* 0xba0d3085 */
|
||||||
t12 = 3.1563205994e-04, /* 0x39a57b6b */
|
t12 = 3.1563205994e-04f, /* 0x39a57b6b */
|
||||||
t13 = -3.1275415677e-04, /* 0xb9a3f927 */
|
t13 = -3.1275415677e-04f, /* 0xb9a3f927 */
|
||||||
t14 = 3.3552918467e-04, /* 0x39afe9f7 */
|
t14 = 3.3552918467e-04f, /* 0x39afe9f7 */
|
||||||
u0 = -7.7215664089e-02, /* 0xbd9e233f */
|
u0 = -7.7215664089e-02f, /* 0xbd9e233f */
|
||||||
u1 = 6.3282704353e-01, /* 0x3f2200f4 */
|
u1 = 6.3282704353e-01f, /* 0x3f2200f4 */
|
||||||
u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
|
u2 = 1.4549225569e+00f, /* 0x3fba3ae7 */
|
||||||
u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
|
u3 = 9.7771751881e-01f, /* 0x3f7a4bb2 */
|
||||||
u4 = 2.2896373272e-01, /* 0x3e6a7578 */
|
u4 = 2.2896373272e-01f, /* 0x3e6a7578 */
|
||||||
u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
|
u5 = 1.3381091878e-02f, /* 0x3c5b3c5e */
|
||||||
v1 = 2.4559779167e+00, /* 0x401d2ebe */
|
v1 = 2.4559779167e+00f, /* 0x401d2ebe */
|
||||||
v2 = 2.1284897327e+00, /* 0x4008392d */
|
v2 = 2.1284897327e+00f, /* 0x4008392d */
|
||||||
v3 = 7.6928514242e-01, /* 0x3f44efdf */
|
v3 = 7.6928514242e-01f, /* 0x3f44efdf */
|
||||||
v4 = 1.0422264785e-01, /* 0x3dd572af */
|
v4 = 1.0422264785e-01f, /* 0x3dd572af */
|
||||||
v5 = 3.2170924824e-03, /* 0x3b52d5db */
|
v5 = 3.2170924824e-03f, /* 0x3b52d5db */
|
||||||
s0 = -7.7215664089e-02, /* 0xbd9e233f */
|
s0 = -7.7215664089e-02f, /* 0xbd9e233f */
|
||||||
s1 = 2.1498242021e-01, /* 0x3e5c245a */
|
s1 = 2.1498242021e-01f, /* 0x3e5c245a */
|
||||||
s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
|
s2 = 3.2577878237e-01f, /* 0x3ea6cc7a */
|
||||||
s3 = 1.4635047317e-01, /* 0x3e15dce6 */
|
s3 = 1.4635047317e-01f, /* 0x3e15dce6 */
|
||||||
s4 = 2.6642270386e-02, /* 0x3cda40e4 */
|
s4 = 2.6642270386e-02f, /* 0x3cda40e4 */
|
||||||
s5 = 1.8402845599e-03, /* 0x3af135b4 */
|
s5 = 1.8402845599e-03f, /* 0x3af135b4 */
|
||||||
s6 = 3.1947532989e-05, /* 0x3805ff67 */
|
s6 = 3.1947532989e-05f, /* 0x3805ff67 */
|
||||||
r1 = 1.3920053244e+00, /* 0x3fb22d3b */
|
r1 = 1.3920053244e+00f, /* 0x3fb22d3b */
|
||||||
r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
|
r2 = 7.2193557024e-01f, /* 0x3f38d0c5 */
|
||||||
r3 = 1.7193385959e-01, /* 0x3e300f6e */
|
r3 = 1.7193385959e-01f, /* 0x3e300f6e */
|
||||||
r4 = 1.8645919859e-02, /* 0x3c98bf54 */
|
r4 = 1.8645919859e-02f, /* 0x3c98bf54 */
|
||||||
r5 = 7.7794247773e-04, /* 0x3a4beed6 */
|
r5 = 7.7794247773e-04f, /* 0x3a4beed6 */
|
||||||
r6 = 7.3266842264e-06, /* 0x36f5d7bd */
|
r6 = 7.3266842264e-06f, /* 0x36f5d7bd */
|
||||||
w0 = 4.1893854737e-01, /* 0x3ed67f1d */
|
w0 = 4.1893854737e-01f, /* 0x3ed67f1d */
|
||||||
w1 = 8.3333335817e-02, /* 0x3daaaaab */
|
w1 = 8.3333335817e-02f, /* 0x3daaaaab */
|
||||||
w2 = -2.7777778450e-03, /* 0xbb360b61 */
|
w2 = -2.7777778450e-03f, /* 0xbb360b61 */
|
||||||
w3 = 7.9365057172e-04, /* 0x3a500cfd */
|
w3 = 7.9365057172e-04f, /* 0x3a500cfd */
|
||||||
w4 = -5.9518753551e-04, /* 0xba1c065c */
|
w4 = -5.9518753551e-04f, /* 0xba1c065c */
|
||||||
w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
|
w5 = 8.3633989561e-04f, /* 0x3a5b3dd2 */
|
||||||
w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
|
w6 = -1.6309292987e-03f; /* 0xbad5c4e8 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
static const float zero= 0.0000000000e+00;
|
static const float zero= 0.0000000000e+00f;
|
||||||
#else
|
#else
|
||||||
static float zero= 0.0000000000e+00;
|
static float zero= 0.0000000000e+00f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
|
|
|
@ -29,13 +29,13 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||||
C1 = 4.1666667908e-02, /* 0x3d2aaaab */
|
C1 = 4.1666667908e-02f, /* 0x3d2aaaab */
|
||||||
C2 = -1.3888889225e-03, /* 0xbab60b61 */
|
C2 = -1.3888889225e-03f, /* 0xbab60b61 */
|
||||||
C3 = 2.4801587642e-05, /* 0x37d00d01 */
|
C3 = 2.4801587642e-05f, /* 0x37d00d01 */
|
||||||
C4 = -2.7557314297e-07, /* 0xb493f27c */
|
C4 = -2.7557314297e-07f, /* 0xb493f27c */
|
||||||
C5 = 2.0875723372e-09, /* 0x310f74f6 */
|
C5 = 2.0875723372e-09f, /* 0x310f74f6 */
|
||||||
C6 = -1.1359647598e-11; /* 0xad47d74e */
|
C6 = -1.1359647598e-11f; /* 0xad47d74e */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float __kernel_cosf(float x, float y)
|
float __kernel_cosf(float x, float y)
|
||||||
|
|
|
@ -38,17 +38,17 @@ static const float PIo2[] = {
|
||||||
#else
|
#else
|
||||||
static float PIo2[] = {
|
static float PIo2[] = {
|
||||||
#endif
|
#endif
|
||||||
1.5703125000e+00, /* 0x3fc90000 */
|
1.5703125000e+00f, /* 0x3fc90000 */
|
||||||
4.5776367188e-04, /* 0x39f00000 */
|
4.5776367188e-04f, /* 0x39f00000 */
|
||||||
2.5987625122e-05, /* 0x37da0000 */
|
2.5987625122e-05f, /* 0x37da0000 */
|
||||||
7.5437128544e-08, /* 0x33a20000 */
|
7.5437128544e-08f, /* 0x33a20000 */
|
||||||
6.0026650317e-11, /* 0x2e840000 */
|
6.0026650317e-11f, /* 0x2e840000 */
|
||||||
7.3896444519e-13, /* 0x2b500000 */
|
7.3896444519e-13f, /* 0x2b500000 */
|
||||||
5.3845816694e-15, /* 0x27c20000 */
|
5.3845816694e-15f, /* 0x27c20000 */
|
||||||
5.6378512969e-18, /* 0x22d00000 */
|
5.6378512969e-18f, /* 0x22d00000 */
|
||||||
8.3009228831e-20, /* 0x1fc40000 */
|
8.3009228831e-20f, /* 0x1fc40000 */
|
||||||
3.2756352257e-22, /* 0x1bc60000 */
|
3.2756352257e-22f, /* 0x1bc60000 */
|
||||||
6.3331015649e-25, /* 0x17440000 */
|
6.3331015649e-25f, /* 0x17440000 */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
|
@ -56,10 +56,10 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
zero = 0.0,
|
zero = 0.0f,
|
||||||
one = 1.0,
|
one = 1.0f,
|
||||||
two8 = 2.5600000000e+02, /* 0x43800000 */
|
two8 = 2.5600000000e+02f, /* 0x43800000 */
|
||||||
twon8 = 3.9062500000e-03; /* 0x3b800000 */
|
twon8 = 3.9062500000e-03f; /* 0x3b800000 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __uint8_t *ipio2)
|
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const __uint8_t *ipio2)
|
||||||
|
|
|
@ -29,13 +29,13 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
half = 5.0000000000e-01,/* 0x3f000000 */
|
half = 5.0000000000e-01f,/* 0x3f000000 */
|
||||||
S1 = -1.6666667163e-01, /* 0xbe2aaaab */
|
S1 = -1.6666667163e-01f, /* 0xbe2aaaab */
|
||||||
S2 = 8.3333337680e-03, /* 0x3c088889 */
|
S2 = 8.3333337680e-03f, /* 0x3c088889 */
|
||||||
S3 = -1.9841270114e-04, /* 0xb9500d01 */
|
S3 = -1.9841270114e-04f, /* 0xb9500d01 */
|
||||||
S4 = 2.7557314297e-06, /* 0x3638ef1b */
|
S4 = 2.7557314297e-06f, /* 0x3638ef1b */
|
||||||
S5 = -2.5050759689e-08, /* 0xb2d72f34 */
|
S5 = -2.5050759689e-08f, /* 0xb2d72f34 */
|
||||||
S6 = 1.5896910177e-10; /* 0x2f2ec9d3 */
|
S6 = 1.5896910177e-10f; /* 0x2f2ec9d3 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float __kernel_sinf(float x, float y, int iy)
|
float __kernel_sinf(float x, float y, int iy)
|
||||||
|
|
|
@ -28,23 +28,23 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
one = 1.0000000000e+00, /* 0x3f800000 */
|
one = 1.0000000000e+00f, /* 0x3f800000 */
|
||||||
pio4 = 7.8539812565e-01, /* 0x3f490fda */
|
pio4 = 7.8539812565e-01f, /* 0x3f490fda */
|
||||||
pio4lo= 3.7748947079e-08, /* 0x33222168 */
|
pio4lo= 3.7748947079e-08f, /* 0x33222168 */
|
||||||
T[] = {
|
T[] = {
|
||||||
3.3333334327e-01, /* 0x3eaaaaab */
|
3.3333334327e-01f, /* 0x3eaaaaab */
|
||||||
1.3333334029e-01, /* 0x3e088889 */
|
1.3333334029e-01f, /* 0x3e088889 */
|
||||||
5.3968254477e-02, /* 0x3d5d0dd1 */
|
5.3968254477e-02f, /* 0x3d5d0dd1 */
|
||||||
2.1869488060e-02, /* 0x3cb327a4 */
|
2.1869488060e-02f, /* 0x3cb327a4 */
|
||||||
8.8632395491e-03, /* 0x3c11371f */
|
8.8632395491e-03f, /* 0x3c11371f */
|
||||||
3.5920790397e-03, /* 0x3b6b6916 */
|
3.5920790397e-03f, /* 0x3b6b6916 */
|
||||||
1.4562094584e-03, /* 0x3abede48 */
|
1.4562094584e-03f, /* 0x3abede48 */
|
||||||
5.8804126456e-04, /* 0x3a1a26c8 */
|
5.8804126456e-04f, /* 0x3a1a26c8 */
|
||||||
2.4646313977e-04, /* 0x398137b9 */
|
2.4646313977e-04f, /* 0x398137b9 */
|
||||||
7.8179444245e-05, /* 0x38a3f445 */
|
7.8179444245e-05f, /* 0x38a3f445 */
|
||||||
7.1407252108e-05, /* 0x3895c07a */
|
7.1407252108e-05f, /* 0x3895c07a */
|
||||||
-1.8558637748e-05, /* 0xb79bae5f */
|
-1.8558637748e-05f, /* 0xb79bae5f */
|
||||||
2.5907305826e-05, /* 0x37d95384 */
|
2.5907305826e-05f, /* 0x37d95384 */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
|
ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
|
||||||
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
|
ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
|
||||||
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
|
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
|
||||||
Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */
|
Lg1 = 0xaaaaaa.0p-24f, /* 0.66666662693 */
|
||||||
Lg2 = 0xccce13.0p-25, /* 0.40000972152 */
|
Lg2 = 0xccce13.0p-25f, /* 0.40000972152 */
|
||||||
Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */
|
Lg3 = 0x91e9ee.0p-25f, /* 0.28498786688 */
|
||||||
Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */
|
Lg4 = 0xf89e26.0p-26f; /* 0.24279078841 */
|
||||||
|
|
||||||
float log1pf(float x)
|
float log1pf(float x)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ float copysignf(float x, float y) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const float _M_LN10 = 2.30258509299404; // 0x40135d8e
|
static const float _M_LN10 = 2.30258509299404f; // 0x40135d8e
|
||||||
float log10f(float x) { return logf(x) / (float)_M_LN10; }
|
float log10f(float x) { return logf(x) / (float)_M_LN10; }
|
||||||
#undef _M_LN2
|
#undef _M_LN2
|
||||||
static const float _M_LN2 = 0.6931472;
|
static const float _M_LN2 = 0.6931472;
|
||||||
|
@ -142,34 +142,34 @@ float scalbnf(float x, int n)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
bp[] = {1.0, 1.5,},
|
bp[] = {1.0f, 1.5f,},
|
||||||
dp_h[] = { 0.0, 5.84960938e-01,}, /* 0x3f15c000 */
|
dp_h[] = { 0.0f, 5.84960938e-01f,}, /* 0x3f15c000 */
|
||||||
dp_l[] = { 0.0, 1.56322085e-06,}, /* 0x35d1cfdc */
|
dp_l[] = { 0.0f, 1.56322085e-06f,}, /* 0x35d1cfdc */
|
||||||
two24 = 16777216.0, /* 0x4b800000 */
|
two24 = 16777216.0f, /* 0x4b800000 */
|
||||||
huge = 1.0e30,
|
huge = 1.0e30f,
|
||||||
tiny = 1.0e-30,
|
tiny = 1.0e-30f,
|
||||||
/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
|
/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
|
||||||
L1 = 6.0000002384e-01, /* 0x3f19999a */
|
L1 = 6.0000002384e-01f, /* 0x3f19999a */
|
||||||
L2 = 4.2857143283e-01, /* 0x3edb6db7 */
|
L2 = 4.2857143283e-01f, /* 0x3edb6db7 */
|
||||||
L3 = 3.3333334327e-01, /* 0x3eaaaaab */
|
L3 = 3.3333334327e-01f, /* 0x3eaaaaab */
|
||||||
L4 = 2.7272811532e-01, /* 0x3e8ba305 */
|
L4 = 2.7272811532e-01f, /* 0x3e8ba305 */
|
||||||
L5 = 2.3066075146e-01, /* 0x3e6c3255 */
|
L5 = 2.3066075146e-01f, /* 0x3e6c3255 */
|
||||||
L6 = 2.0697501302e-01, /* 0x3e53f142 */
|
L6 = 2.0697501302e-01f, /* 0x3e53f142 */
|
||||||
P1 = 1.6666667163e-01, /* 0x3e2aaaab */
|
P1 = 1.6666667163e-01f, /* 0x3e2aaaab */
|
||||||
P2 = -2.7777778450e-03, /* 0xbb360b61 */
|
P2 = -2.7777778450e-03f, /* 0xbb360b61 */
|
||||||
P3 = 6.6137559770e-05, /* 0x388ab355 */
|
P3 = 6.6137559770e-05f, /* 0x388ab355 */
|
||||||
P4 = -1.6533901999e-06, /* 0xb5ddea0e */
|
P4 = -1.6533901999e-06f, /* 0xb5ddea0e */
|
||||||
P5 = 4.1381369442e-08, /* 0x3331bb4c */
|
P5 = 4.1381369442e-08f, /* 0x3331bb4c */
|
||||||
lg2 = 6.9314718246e-01, /* 0x3f317218 */
|
lg2 = 6.9314718246e-01f, /* 0x3f317218 */
|
||||||
lg2_h = 6.93145752e-01, /* 0x3f317200 */
|
lg2_h = 6.93145752e-01f, /* 0x3f317200 */
|
||||||
lg2_l = 1.42860654e-06, /* 0x35bfbe8c */
|
lg2_l = 1.42860654e-06f, /* 0x35bfbe8c */
|
||||||
ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */
|
ovt = 4.2995665694e-08f, /* -(128-log2(ovfl+.5ulp)) */
|
||||||
cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */
|
cp = 9.6179670095e-01f, /* 0x3f76384f =2/(3ln2) */
|
||||||
cp_h = 9.6191406250e-01, /* 0x3f764000 =12b cp */
|
cp_h = 9.6191406250e-01f, /* 0x3f764000 =12b cp */
|
||||||
cp_l = -1.1736857402e-04, /* 0xb8f623c6 =tail of cp_h */
|
cp_l = -1.1736857402e-04f, /* 0xb8f623c6 =tail of cp_h */
|
||||||
ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */
|
ivln2 = 1.4426950216e+00f, /* 0x3fb8aa3b =1/ln2 */
|
||||||
ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/
|
ivln2_h = 1.4426879883e+00f, /* 0x3fb8aa00 =16b 1/ln2*/
|
||||||
ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/
|
ivln2_l = 7.0526075433e-06f; /* 0x36eca570 =1/ln2 tail*/
|
||||||
|
|
||||||
float powf(float x, float y)
|
float powf(float x, float y)
|
||||||
{
|
{
|
||||||
|
@ -406,7 +406,7 @@ float powf(float x, float y)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
half[2] = {0.5,-0.5},
|
half[2] = {0.5f,-0.5f},
|
||||||
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
|
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
|
||||||
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
|
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
|
||||||
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
|
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
|
||||||
|
@ -445,7 +445,7 @@ float expf(float x)
|
||||||
/* argument reduction */
|
/* argument reduction */
|
||||||
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
|
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
|
||||||
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
|
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
|
||||||
k = invln2*x + half[sign];
|
k = (int)(invln2*x + half[sign]);
|
||||||
else
|
else
|
||||||
k = 1 - sign - sign;
|
k = 1 - sign - sign;
|
||||||
hi = x - k*ln2hi; /* k*ln2hi is exact here */
|
hi = x - k*ln2hi; /* k*ln2hi is exact here */
|
||||||
|
@ -492,17 +492,17 @@ float expf(float x)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const float
|
static const float
|
||||||
o_threshold = 8.8721679688e+01, /* 0x42b17180 */
|
o_threshold = 8.8721679688e+01f, /* 0x42b17180 */
|
||||||
ln2_hi = 6.9313812256e-01, /* 0x3f317180 */
|
ln2_hi = 6.9313812256e-01f, /* 0x3f317180 */
|
||||||
ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */
|
ln2_lo = 9.0580006145e-06f, /* 0x3717f7d1 */
|
||||||
//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
|
//invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */
|
||||||
/*
|
/*
|
||||||
* Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
|
* Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
|
||||||
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
|
* |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
|
||||||
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
|
* Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
|
||||||
*/
|
*/
|
||||||
Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
|
Q1 = -3.3333212137e-2f, /* -0x888868.0p-28 */
|
||||||
Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */
|
Q2 = 1.5807170421e-3f; /* 0xcf3010.0p-33 */
|
||||||
|
|
||||||
float expm1f(float x)
|
float expm1f(float x)
|
||||||
{
|
{
|
||||||
|
@ -536,7 +536,7 @@ float expm1f(float x)
|
||||||
k = -1;
|
k = -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
k = invln2*x + (sign ? -0.5f : 0.5f);
|
k = (int)(invln2*x + (sign ? -0.5f : 0.5f));
|
||||||
t = k;
|
t = k;
|
||||||
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
|
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
|
||||||
lo = t*ln2_lo;
|
lo = t*ln2_lo;
|
||||||
|
|
|
@ -35,79 +35,79 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
tiny = 1e-30,
|
tiny = 1e-30f,
|
||||||
half= 5.0000000000e-01, /* 0x3F000000 */
|
half= 5.0000000000e-01f, /* 0x3F000000 */
|
||||||
one = 1.0000000000e+00, /* 0x3F800000 */
|
one = 1.0000000000e+00f, /* 0x3F800000 */
|
||||||
two = 2.0000000000e+00, /* 0x40000000 */
|
two = 2.0000000000e+00f, /* 0x40000000 */
|
||||||
/* c = (subfloat)0.84506291151 */
|
/* c = (subfloat)0.84506291151 */
|
||||||
erx = 8.4506291151e-01, /* 0x3f58560b */
|
erx = 8.4506291151e-01f, /* 0x3f58560b */
|
||||||
/*
|
/*
|
||||||
* Coefficients for approximation to erf on [0,0.84375]
|
* Coefficients for approximation to erf on [0,0.84375]
|
||||||
*/
|
*/
|
||||||
efx = 1.2837916613e-01, /* 0x3e0375d4 */
|
efx = 1.2837916613e-01f, /* 0x3e0375d4 */
|
||||||
efx8= 1.0270333290e+00, /* 0x3f8375d4 */
|
efx8= 1.0270333290e+00f, /* 0x3f8375d4 */
|
||||||
pp0 = 1.2837916613e-01, /* 0x3e0375d4 */
|
pp0 = 1.2837916613e-01f, /* 0x3e0375d4 */
|
||||||
pp1 = -3.2504209876e-01, /* 0xbea66beb */
|
pp1 = -3.2504209876e-01f, /* 0xbea66beb */
|
||||||
pp2 = -2.8481749818e-02, /* 0xbce9528f */
|
pp2 = -2.8481749818e-02f, /* 0xbce9528f */
|
||||||
pp3 = -5.7702702470e-03, /* 0xbbbd1489 */
|
pp3 = -5.7702702470e-03f, /* 0xbbbd1489 */
|
||||||
pp4 = -2.3763017452e-05, /* 0xb7c756b1 */
|
pp4 = -2.3763017452e-05f, /* 0xb7c756b1 */
|
||||||
qq1 = 3.9791721106e-01, /* 0x3ecbbbce */
|
qq1 = 3.9791721106e-01f, /* 0x3ecbbbce */
|
||||||
qq2 = 6.5022252500e-02, /* 0x3d852a63 */
|
qq2 = 6.5022252500e-02f, /* 0x3d852a63 */
|
||||||
qq3 = 5.0813062117e-03, /* 0x3ba68116 */
|
qq3 = 5.0813062117e-03f, /* 0x3ba68116 */
|
||||||
qq4 = 1.3249473704e-04, /* 0x390aee49 */
|
qq4 = 1.3249473704e-04f, /* 0x390aee49 */
|
||||||
qq5 = -3.9602282413e-06, /* 0xb684e21a */
|
qq5 = -3.9602282413e-06f, /* 0xb684e21a */
|
||||||
/*
|
/*
|
||||||
* Coefficients for approximation to erf in [0.84375,1.25]
|
* Coefficients for approximation to erf in [0.84375,1.25]
|
||||||
*/
|
*/
|
||||||
pa0 = -2.3621185683e-03, /* 0xbb1acdc6 */
|
pa0 = -2.3621185683e-03f, /* 0xbb1acdc6 */
|
||||||
pa1 = 4.1485610604e-01, /* 0x3ed46805 */
|
pa1 = 4.1485610604e-01f, /* 0x3ed46805 */
|
||||||
pa2 = -3.7220788002e-01, /* 0xbebe9208 */
|
pa2 = -3.7220788002e-01f, /* 0xbebe9208 */
|
||||||
pa3 = 3.1834661961e-01, /* 0x3ea2fe54 */
|
pa3 = 3.1834661961e-01f, /* 0x3ea2fe54 */
|
||||||
pa4 = -1.1089469492e-01, /* 0xbde31cc2 */
|
pa4 = -1.1089469492e-01f, /* 0xbde31cc2 */
|
||||||
pa5 = 3.5478305072e-02, /* 0x3d1151b3 */
|
pa5 = 3.5478305072e-02f, /* 0x3d1151b3 */
|
||||||
pa6 = -2.1663755178e-03, /* 0xbb0df9c0 */
|
pa6 = -2.1663755178e-03f, /* 0xbb0df9c0 */
|
||||||
qa1 = 1.0642088205e-01, /* 0x3dd9f331 */
|
qa1 = 1.0642088205e-01f, /* 0x3dd9f331 */
|
||||||
qa2 = 5.4039794207e-01, /* 0x3f0a5785 */
|
qa2 = 5.4039794207e-01f, /* 0x3f0a5785 */
|
||||||
qa3 = 7.1828655899e-02, /* 0x3d931ae7 */
|
qa3 = 7.1828655899e-02f, /* 0x3d931ae7 */
|
||||||
qa4 = 1.2617121637e-01, /* 0x3e013307 */
|
qa4 = 1.2617121637e-01f, /* 0x3e013307 */
|
||||||
qa5 = 1.3637083583e-02, /* 0x3c5f6e13 */
|
qa5 = 1.3637083583e-02f, /* 0x3c5f6e13 */
|
||||||
qa6 = 1.1984500103e-02, /* 0x3c445aa3 */
|
qa6 = 1.1984500103e-02f, /* 0x3c445aa3 */
|
||||||
/*
|
/*
|
||||||
* Coefficients for approximation to erfc in [1.25,1/0.35]
|
* Coefficients for approximation to erfc in [1.25,1/0.35]
|
||||||
*/
|
*/
|
||||||
ra0 = -9.8649440333e-03, /* 0xbc21a093 */
|
ra0 = -9.8649440333e-03f, /* 0xbc21a093 */
|
||||||
ra1 = -6.9385856390e-01, /* 0xbf31a0b7 */
|
ra1 = -6.9385856390e-01f, /* 0xbf31a0b7 */
|
||||||
ra2 = -1.0558626175e+01, /* 0xc128f022 */
|
ra2 = -1.0558626175e+01f, /* 0xc128f022 */
|
||||||
ra3 = -6.2375331879e+01, /* 0xc2798057 */
|
ra3 = -6.2375331879e+01f, /* 0xc2798057 */
|
||||||
ra4 = -1.6239666748e+02, /* 0xc322658c */
|
ra4 = -1.6239666748e+02f, /* 0xc322658c */
|
||||||
ra5 = -1.8460508728e+02, /* 0xc3389ae7 */
|
ra5 = -1.8460508728e+02f, /* 0xc3389ae7 */
|
||||||
ra6 = -8.1287437439e+01, /* 0xc2a2932b */
|
ra6 = -8.1287437439e+01f, /* 0xc2a2932b */
|
||||||
ra7 = -9.8143291473e+00, /* 0xc11d077e */
|
ra7 = -9.8143291473e+00f, /* 0xc11d077e */
|
||||||
sa1 = 1.9651271820e+01, /* 0x419d35ce */
|
sa1 = 1.9651271820e+01f, /* 0x419d35ce */
|
||||||
sa2 = 1.3765776062e+02, /* 0x4309a863 */
|
sa2 = 1.3765776062e+02f, /* 0x4309a863 */
|
||||||
sa3 = 4.3456588745e+02, /* 0x43d9486f */
|
sa3 = 4.3456588745e+02f, /* 0x43d9486f */
|
||||||
sa4 = 6.4538726807e+02, /* 0x442158c9 */
|
sa4 = 6.4538726807e+02f, /* 0x442158c9 */
|
||||||
sa5 = 4.2900814819e+02, /* 0x43d6810b */
|
sa5 = 4.2900814819e+02f, /* 0x43d6810b */
|
||||||
sa6 = 1.0863500214e+02, /* 0x42d9451f */
|
sa6 = 1.0863500214e+02f, /* 0x42d9451f */
|
||||||
sa7 = 6.5702495575e+00, /* 0x40d23f7c */
|
sa7 = 6.5702495575e+00f, /* 0x40d23f7c */
|
||||||
sa8 = -6.0424413532e-02, /* 0xbd777f97 */
|
sa8 = -6.0424413532e-02f, /* 0xbd777f97 */
|
||||||
/*
|
/*
|
||||||
* Coefficients for approximation to erfc in [1/.35,28]
|
* Coefficients for approximation to erfc in [1/.35,28]
|
||||||
*/
|
*/
|
||||||
rb0 = -9.8649431020e-03, /* 0xbc21a092 */
|
rb0 = -9.8649431020e-03f, /* 0xbc21a092 */
|
||||||
rb1 = -7.9928326607e-01, /* 0xbf4c9dd4 */
|
rb1 = -7.9928326607e-01f, /* 0xbf4c9dd4 */
|
||||||
rb2 = -1.7757955551e+01, /* 0xc18e104b */
|
rb2 = -1.7757955551e+01f, /* 0xc18e104b */
|
||||||
rb3 = -1.6063638306e+02, /* 0xc320a2ea */
|
rb3 = -1.6063638306e+02f, /* 0xc320a2ea */
|
||||||
rb4 = -6.3756646729e+02, /* 0xc41f6441 */
|
rb4 = -6.3756646729e+02f, /* 0xc41f6441 */
|
||||||
rb5 = -1.0250950928e+03, /* 0xc480230b */
|
rb5 = -1.0250950928e+03f, /* 0xc480230b */
|
||||||
rb6 = -4.8351919556e+02, /* 0xc3f1c275 */
|
rb6 = -4.8351919556e+02f, /* 0xc3f1c275 */
|
||||||
sb1 = 3.0338060379e+01, /* 0x41f2b459 */
|
sb1 = 3.0338060379e+01f, /* 0x41f2b459 */
|
||||||
sb2 = 3.2579251099e+02, /* 0x43a2e571 */
|
sb2 = 3.2579251099e+02f, /* 0x43a2e571 */
|
||||||
sb3 = 1.5367296143e+03, /* 0x44c01759 */
|
sb3 = 1.5367296143e+03f, /* 0x44c01759 */
|
||||||
sb4 = 3.1998581543e+03, /* 0x4547fdbb */
|
sb4 = 3.1998581543e+03f, /* 0x4547fdbb */
|
||||||
sb5 = 2.5530502930e+03, /* 0x451f90ce */
|
sb5 = 2.5530502930e+03f, /* 0x451f90ce */
|
||||||
sb6 = 4.7452853394e+02, /* 0x43ed43a7 */
|
sb6 = 4.7452853394e+02f, /* 0x43ed43a7 */
|
||||||
sb7 = -2.2440952301e+01; /* 0xc1b38712 */
|
sb7 = -2.2440952301e+01f; /* 0xc1b38712 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float erff(float x)
|
float erff(float x)
|
||||||
|
|
|
@ -29,7 +29,7 @@ static const float
|
||||||
#else
|
#else
|
||||||
static float
|
static float
|
||||||
#endif
|
#endif
|
||||||
two25 = 3.3554432000e+07; /* 0x4c000000 */
|
two25 = 3.3554432000e+07f; /* 0x4c000000 */
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float frexpf(float x, int *eptr)
|
float frexpf(float x, int *eptr)
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fdlibm.h"
|
#include "fdlibm.h"
|
||||||
//#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float ldexpf(float value, int exp)
|
float ldexpf(float value, int exp)
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include "fdlibm.h"
|
#include "fdlibm.h"
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
static const float one = 1.0;
|
static const float one = 1.0f;
|
||||||
#else
|
#else
|
||||||
static float one = 1.0;
|
static float one = 1.0f;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
|
|
||||||
#include "fdlibm.h"
|
#include "fdlibm.h"
|
||||||
#define _IEEE_LIBM 1
|
#define _IEEE_LIBM 1
|
||||||
//#include <reent.h>
|
|
||||||
//#include <errno.h>
|
|
||||||
|
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
float lgammaf(float x)
|
float lgammaf(float x)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//#include <fenv.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
/* nearbyint is the same as rint, but it must not raise the inexact exception */
|
/* nearbyint is the same as rint, but it must not raise the inexact exception */
|
||||||
|
|
|
@ -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
|
// Software library version
|
||||||
// Major (top-nibble), incremented on backwards incompatible changes
|
// Major (top-nibble), incremented on backwards incompatible changes
|
||||||
// Minor (bottom-nibble), incremented on feature additions
|
// Minor (bottom-nibble), incremented on feature additions
|
||||||
#define LFS2_VERSION 0x00020001
|
#define LFS2_VERSION 0x00020002
|
||||||
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
|
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
|
||||||
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
|
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
|
||||||
|
|
||||||
|
@ -355,6 +355,11 @@ typedef struct lfs2_superblock {
|
||||||
lfs2_size_t attr_max;
|
lfs2_size_t attr_max;
|
||||||
} lfs2_superblock_t;
|
} lfs2_superblock_t;
|
||||||
|
|
||||||
|
typedef struct lfs2_gstate {
|
||||||
|
uint32_t tag;
|
||||||
|
lfs2_block_t pair[2];
|
||||||
|
} lfs2_gstate_t;
|
||||||
|
|
||||||
// The littlefs filesystem type
|
// The littlefs filesystem type
|
||||||
typedef struct lfs2 {
|
typedef struct lfs2 {
|
||||||
lfs2_cache_t rcache;
|
lfs2_cache_t rcache;
|
||||||
|
@ -369,10 +374,9 @@ typedef struct lfs2 {
|
||||||
} *mlist;
|
} *mlist;
|
||||||
uint32_t seed;
|
uint32_t seed;
|
||||||
|
|
||||||
struct lfs2_gstate {
|
lfs2_gstate_t gstate;
|
||||||
uint32_t tag;
|
lfs2_gstate_t gdisk;
|
||||||
lfs2_block_t pair[2];
|
lfs2_gstate_t gdelta;
|
||||||
} gstate, gpending, gdelta;
|
|
||||||
|
|
||||||
struct lfs2_free {
|
struct lfs2_free {
|
||||||
lfs2_block_t off;
|
lfs2_block_t off;
|
||||||
|
|
|
@ -50,31 +50,35 @@ extern "C"
|
||||||
|
|
||||||
// Logging functions
|
// Logging functions
|
||||||
#ifdef LFS2_YES_TRACE
|
#ifdef LFS2_YES_TRACE
|
||||||
#define LFS2_TRACE(fmt, ...) \
|
#define LFS2_TRACE_(fmt, ...) \
|
||||||
printf("lfs2_trace:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define LFS2_TRACE(...) LFS2_TRACE_(__VA_ARGS__, "")
|
||||||
#else
|
#else
|
||||||
#define LFS2_TRACE(fmt, ...)
|
#define LFS2_TRACE(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS2_NO_DEBUG
|
#ifndef LFS2_NO_DEBUG
|
||||||
#define LFS2_DEBUG(fmt, ...) \
|
#define LFS2_DEBUG_(fmt, ...) \
|
||||||
printf("lfs2_debug:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define LFS2_DEBUG(...) LFS2_DEBUG_(__VA_ARGS__, "")
|
||||||
#else
|
#else
|
||||||
#define LFS2_DEBUG(fmt, ...)
|
#define LFS2_DEBUG(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS2_NO_WARN
|
#ifndef LFS2_NO_WARN
|
||||||
#define LFS2_WARN(fmt, ...) \
|
#define LFS2_WARN_(fmt, ...) \
|
||||||
printf("lfs2_warn:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define LFS2_WARN(...) LFS2_WARN_(__VA_ARGS__, "")
|
||||||
#else
|
#else
|
||||||
#define LFS2_WARN(fmt, ...)
|
#define LFS2_WARN(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS2_NO_ERROR
|
#ifndef LFS2_NO_ERROR
|
||||||
#define LFS2_ERROR(fmt, ...) \
|
#define LFS2_ERROR_(fmt, ...) \
|
||||||
printf("lfs2_error:%d: " fmt "\n", __LINE__, __VA_ARGS__)
|
printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define LFS2_ERROR(...) LFS2_ERROR_(__VA_ARGS__, "")
|
||||||
#else
|
#else
|
||||||
#define LFS2_ERROR(fmt, ...)
|
#define LFS2_ERROR(...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Runtime assertions
|
// Runtime assertions
|
||||||
|
@ -107,7 +111,7 @@ static inline uint32_t lfs2_alignup(uint32_t a, uint32_t alignment) {
|
||||||
return lfs2_aligndown(a + alignment-1, alignment);
|
return lfs2_aligndown(a + alignment-1, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the next smallest power of 2 less than or equal to a
|
// Find the smallest power of 2 greater than or equal to a
|
||||||
static inline uint32_t lfs2_npw2(uint32_t a) {
|
static inline uint32_t lfs2_npw2(uint32_t a) {
|
||||||
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
#if !defined(LFS2_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||||
return 32 - __builtin_clz(a-1);
|
return 32 - __builtin_clz(a-1);
|
||||||
|
|
|
@ -84,6 +84,7 @@ STATIC void mp_hal_move_cursor_back(uint pos) {
|
||||||
// snprintf needs space for the terminating null character
|
// snprintf needs space for the terminating null character
|
||||||
int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos);
|
int n = snprintf(&vt100_command[0], sizeof(vt100_command), "\x1b[%u", pos);
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
|
assert((unsigned)n < sizeof(vt100_command));
|
||||||
vt100_command[n] = 'D'; // replace null char
|
vt100_command[n] = 'D'; // replace null char
|
||||||
mp_hal_stdout_tx_strn(vt100_command, n + 1);
|
mp_hal_stdout_tx_strn(vt100_command, n + 1);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +110,35 @@ typedef struct _readline_t {
|
||||||
|
|
||||||
STATIC readline_t rl;
|
STATIC readline_t rl;
|
||||||
|
|
||||||
|
#if MICROPY_REPL_EMACS_WORDS_MOVE
|
||||||
|
STATIC size_t cursor_count_word(int forward) {
|
||||||
|
const char *line_buf = vstr_str(rl.line);
|
||||||
|
size_t pos = rl.cursor_pos;
|
||||||
|
bool in_word = false;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// if moving backwards and we've reached 0... break
|
||||||
|
if (!forward && pos == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// or if moving forwards and we've reached to the end of line... break
|
||||||
|
else if (forward && pos == vstr_len(rl.line)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unichar_isalnum(line_buf[pos + (forward - 1)])) {
|
||||||
|
in_word = true;
|
||||||
|
} else if (in_word) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += forward ? forward : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return forward ? pos - rl.cursor_pos : rl.cursor_pos - pos;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int readline_process_char(int c) {
|
int readline_process_char(int c) {
|
||||||
size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len);
|
size_t last_line_len = utf8_charlen((byte *)rl.line->buf, rl.line->len);
|
||||||
int cont_chars = 0;
|
int cont_chars = 0;
|
||||||
|
@ -161,6 +191,10 @@ int readline_process_char(int c) {
|
||||||
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
redraw_step_back = rl.cursor_pos - rl.orig_line_len;
|
||||||
redraw_from_cursor = true;
|
redraw_from_cursor = true;
|
||||||
#endif
|
#endif
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
} else if (c == CHAR_CTRL_W) {
|
||||||
|
goto backward_kill_word;
|
||||||
|
#endif
|
||||||
} else if (c == '\r') {
|
} else if (c == '\r') {
|
||||||
// newline
|
// newline
|
||||||
mp_hal_stdout_tx_str("\r\n");
|
mp_hal_stdout_tx_str("\r\n");
|
||||||
|
@ -255,9 +289,40 @@ int readline_process_char(int c) {
|
||||||
case 'O':
|
case 'O':
|
||||||
rl.escape_seq = ESEQ_ESC_O;
|
rl.escape_seq = ESEQ_ESC_O;
|
||||||
break;
|
break;
|
||||||
|
#if MICROPY_REPL_EMACS_WORDS_MOVE
|
||||||
|
case 'b':
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
backward_word:
|
||||||
|
#endif
|
||||||
|
redraw_step_back = cursor_count_word(0);
|
||||||
|
rl.escape_seq = ESEQ_NONE;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
forward_word:
|
||||||
|
#endif
|
||||||
|
redraw_step_forward = cursor_count_word(1);
|
||||||
|
rl.escape_seq = ESEQ_NONE;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
vstr_cut_out_bytes(rl.line, rl.cursor_pos, cursor_count_word(1));
|
||||||
|
redraw_from_cursor = true;
|
||||||
|
rl.escape_seq = ESEQ_NONE;
|
||||||
|
break;
|
||||||
|
case 127:
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
backward_kill_word:
|
||||||
|
#endif
|
||||||
|
redraw_step_back = cursor_count_word(0);
|
||||||
|
vstr_cut_out_bytes(rl.line, rl.cursor_pos - redraw_step_back, redraw_step_back);
|
||||||
|
redraw_from_cursor = true;
|
||||||
|
rl.escape_seq = ESEQ_NONE;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
DEBUG_printf("(ESC %d)", c);
|
DEBUG_printf("(ESC %d)", c);
|
||||||
rl.escape_seq = ESEQ_NONE;
|
rl.escape_seq = ESEQ_NONE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
|
} else if (rl.escape_seq == ESEQ_ESC_BRACKET) {
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
|
@ -365,6 +430,24 @@ delete_key:
|
||||||
} else {
|
} else {
|
||||||
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
||||||
}
|
}
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
} else if (c == ';' && rl.escape_seq_buf[0] == '1') {
|
||||||
|
// ';' is used to separate parameters. so first parameter was '1',
|
||||||
|
// that's used for sequences like ctrl+left, which we will try to parse.
|
||||||
|
// escape_seq state is reset back to ESEQ_ESC_BRACKET, as if we've just received
|
||||||
|
// the opening bracket, because more parameters are to come.
|
||||||
|
// we don't track the parameters themselves to keep low on logic and code size. that
|
||||||
|
// might be required in the future if more complex sequences are added.
|
||||||
|
rl.escape_seq = ESEQ_ESC_BRACKET;
|
||||||
|
// goto away from the state-machine, as rl.escape_seq will be overridden.
|
||||||
|
goto redraw;
|
||||||
|
} else if (rl.escape_seq_buf[0] == '5' && c == 'C') {
|
||||||
|
// ctrl+right
|
||||||
|
goto forward_word;
|
||||||
|
} else if (rl.escape_seq_buf[0] == '5' && c == 'D') {
|
||||||
|
// ctrl+left
|
||||||
|
goto backward_word;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
DEBUG_printf("(ESC [ %c %d)", rl.escape_seq_buf[0], c);
|
||||||
}
|
}
|
||||||
|
@ -383,6 +466,10 @@ delete_key:
|
||||||
rl.escape_seq = ESEQ_NONE;
|
rl.escape_seq = ESEQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_REPL_EMACS_EXTRA_WORDS_MOVE
|
||||||
|
redraw:
|
||||||
|
#endif
|
||||||
|
|
||||||
// redraw command prompt, efficiently
|
// redraw command prompt, efficiently
|
||||||
if (redraw_step_back > 0) {
|
if (redraw_step_back > 0) {
|
||||||
mp_hal_move_cursor_back(redraw_step_back-cont_chars);
|
mp_hal_move_cursor_back(redraw_step_back-cont_chars);
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#define CHAR_CTRL_N (14)
|
#define CHAR_CTRL_N (14)
|
||||||
#define CHAR_CTRL_P (16)
|
#define CHAR_CTRL_P (16)
|
||||||
#define CHAR_CTRL_U (21)
|
#define CHAR_CTRL_U (21)
|
||||||
|
#define CHAR_CTRL_W (23)
|
||||||
|
|
||||||
void readline_init0(void);
|
void readline_init0(void);
|
||||||
int readline(vstr_t *line, const char *prompt);
|
int readline(vstr_t *line, const char *prompt);
|
||||||
|
|
|
@ -80,7 +80,7 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian
|
||||||
} else if (i > 0 && s < s_top && *s == '.') {
|
} else if (i > 0 && s < s_top && *s == '.') {
|
||||||
s++;
|
s++;
|
||||||
} else {
|
} else {
|
||||||
mp_raise_ValueError(translate("invalid arguments"));
|
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,14 +159,14 @@ mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month,
|
||||||
}
|
}
|
||||||
|
|
||||||
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
|
void timeutils_seconds_since_epoch_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) {
|
||||||
t -= EPOCH1970_EPOCH2000_DIFF_SECS;
|
t -= TIMEUTILS_SECONDS_1970_TO_2000;
|
||||||
timeutils_seconds_since_2000_to_struct_time(t, tm);
|
timeutils_seconds_since_2000_to_struct_time(t, tm);
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date,
|
mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date,
|
||||||
mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
|
mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
|
||||||
mp_uint_t t = timeutils_seconds_since_2000(year, month, date, hour, minute, second);
|
mp_uint_t t = timeutils_seconds_since_2000(year, month, date, hour, minute, second);
|
||||||
return t + EPOCH1970_EPOCH2000_DIFF_SECS;
|
return t + TIMEUTILS_SECONDS_1970_TO_2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
|
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
#ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
#ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
||||||
#define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
#define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
||||||
|
|
||||||
#define EPOCH1970_EPOCH2000_DIFF_SECS 946684800
|
// The number of seconds between 1970/1/1 and 2000/1/1 is calculated using:
|
||||||
|
// time.mktime((2000,1,1,0,0,0,0,0,0)) - time.mktime((1970,1,1,0,0,0,0,0,0))
|
||||||
|
#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800ULL)
|
||||||
|
|
||||||
typedef struct _timeutils_struct_time_t {
|
typedef struct _timeutils_struct_time_t {
|
||||||
uint16_t tm_year; // i.e. 2014
|
uint16_t tm_year; // i.e. 2014
|
||||||
|
@ -40,6 +42,14 @@ typedef struct _timeutils_struct_time_t {
|
||||||
uint16_t tm_yday; // 1..366
|
uint16_t tm_yday; // 1..366
|
||||||
} timeutils_struct_time_t;
|
} timeutils_struct_time_t;
|
||||||
|
|
||||||
|
static inline uint64_t timeutils_seconds_since_2000_to_nanoseconds_since_1970(mp_uint_t s) {
|
||||||
|
return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mp_uint_t timeutils_seconds_since_2000_from_nanoseconds_since_1970(uint64_t ns) {
|
||||||
|
return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000;
|
||||||
|
}
|
||||||
|
|
||||||
bool timeutils_is_leap_year(mp_uint_t year);
|
bool timeutils_is_leap_year(mp_uint_t year);
|
||||||
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
|
mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month);
|
||||||
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
|
mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date);
|
||||||
|
@ -58,4 +68,10 @@ mp_uint_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint
|
||||||
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
|
mp_uint_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday,
|
||||||
mp_int_t hours, mp_int_t minutes, mp_int_t seconds);
|
mp_int_t hours, mp_int_t minutes, mp_int_t seconds);
|
||||||
|
|
||||||
|
static inline uint64_t timeutils_nanoseconds_since_1970(mp_uint_t year, mp_uint_t month,
|
||||||
|
mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) {
|
||||||
|
return timeutils_seconds_since_2000_to_nanoseconds_since_1970(
|
||||||
|
timeutils_seconds_since_2000(year, month, date, hour, minute, second));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
#endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H
|
||||||
|
|
|
@ -28,7 +28,21 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uintptr_t gc_helper_get_sp(void);
|
#if MICROPY_GCREGS_SETJMP
|
||||||
uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs);
|
#include <setjmp.h>
|
||||||
|
typedef jmp_buf gc_helper_regs_t;
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
typedef uintptr_t gc_helper_regs_t[6];
|
||||||
|
#elif defined(__i386__)
|
||||||
|
typedef uintptr_t gc_helper_regs_t[4];
|
||||||
|
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
|
||||||
|
typedef uintptr_t gc_helper_regs_t[10];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gc_helper_collect_regs_and_stack(void);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H
|
#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H
|
||||||
|
|
|
@ -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
|
.section .text
|
||||||
.align 2
|
.align 2
|
||||||
|
|
||||||
.global gc_helper_get_sp
|
|
||||||
.type gc_helper_get_sp, %function
|
|
||||||
|
|
||||||
@ uint gc_helper_get_sp(void)
|
|
||||||
gc_helper_get_sp:
|
|
||||||
@ return the sp
|
|
||||||
mov r0, sp
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.size gc_helper_get_sp, .-gc_helper_get_sp
|
|
||||||
|
|
||||||
|
|
||||||
.global gc_helper_get_regs_and_sp
|
.global gc_helper_get_regs_and_sp
|
||||||
.type gc_helper_get_regs_and_sp, %function
|
.type gc_helper_get_regs_and_sp, %function
|
||||||
|
|
||||||
|
|
|
@ -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,9 +32,6 @@
|
||||||
int mp_interrupt_char = -1;
|
int mp_interrupt_char = -1;
|
||||||
|
|
||||||
void mp_hal_set_interrupt_char(int c) {
|
void mp_hal_set_interrupt_char(int c) {
|
||||||
if (c != -1) {
|
|
||||||
mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
|
|
||||||
}
|
|
||||||
mp_interrupt_char = c;
|
mp_interrupt_char = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,14 @@
|
||||||
#include "py/gc.h"
|
#include "py/gc.h"
|
||||||
#include "lib/utils/mpirq.h"
|
#include "lib/utils/mpirq.h"
|
||||||
|
|
||||||
|
#if MICROPY_ENABLE_SCHEDULER
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
DECLARE PUBLIC DATA
|
DECLARE PUBLIC DATA
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
const mp_arg_t mp_irq_init_args[] = {
|
const mp_arg_t mp_irq_init_args[] = {
|
||||||
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} },
|
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} },
|
||||||
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||||
};
|
};
|
||||||
|
@ -62,8 +64,10 @@ mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) {
|
||||||
void mp_irq_handler(mp_irq_obj_t *self) {
|
void mp_irq_handler(mp_irq_obj_t *self) {
|
||||||
if (self->handler != mp_const_none) {
|
if (self->handler != mp_const_none) {
|
||||||
if (self->ishard) {
|
if (self->ishard) {
|
||||||
// When executing code within a handler we must lock the GC to prevent
|
// When executing code within a handler we must lock the scheduler to
|
||||||
// any memory allocations.
|
// prevent any scheduled callbacks from running, and lock the GC to
|
||||||
|
// prevent any memory allocations.
|
||||||
|
mp_sched_lock();
|
||||||
gc_lock();
|
gc_lock();
|
||||||
nlr_buf_t nlr;
|
nlr_buf_t nlr;
|
||||||
if (nlr_push(&nlr) == 0) {
|
if (nlr_push(&nlr) == 0) {
|
||||||
|
@ -77,6 +81,7 @@ void mp_irq_handler(mp_irq_obj_t *self) {
|
||||||
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
|
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
|
||||||
}
|
}
|
||||||
gc_unlock();
|
gc_unlock();
|
||||||
|
mp_sched_unlock();
|
||||||
} else {
|
} else {
|
||||||
// Schedule call to user function
|
// Schedule call to user function
|
||||||
mp_sched_schedule(self->handler, self->parent);
|
mp_sched_schedule(self->handler, self->parent);
|
||||||
|
@ -122,3 +127,5 @@ const mp_obj_type_t mp_irq_type = {
|
||||||
.call = mp_irq_call,
|
.call = mp_irq_call,
|
||||||
.locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict,
|
.locals_dict = (mp_obj_dict_t *)&mp_irq_locals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // MICROPY_ENABLE_SCHEDULER
|
||||||
|
|
|
@ -46,7 +46,10 @@
|
||||||
|
|
||||||
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL;
|
||||||
int pyexec_system_exit = 0;
|
int pyexec_system_exit = 0;
|
||||||
|
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
STATIC bool repl_display_debugging_info = 0;
|
STATIC bool repl_display_debugging_info = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EXEC_FLAG_PRINT_EOF (1)
|
#define EXEC_FLAG_PRINT_EOF (1)
|
||||||
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
|
#define EXEC_FLAG_ALLOW_DEBUGGING (2)
|
||||||
|
@ -62,7 +65,9 @@ STATIC bool repl_display_debugging_info = 0;
|
||||||
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
|
// EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile)
|
||||||
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
|
STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
uint32_t start = 0;
|
uint32_t start = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
// by default a SystemExit exception returns 0
|
// by default a SystemExit exception returns 0
|
||||||
pyexec_system_exit = 0;
|
pyexec_system_exit = 0;
|
||||||
|
@ -97,7 +102,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
// Clear the parse tree because it has a heap pointer we don't need anymore.
|
// Clear the parse tree because it has a heap pointer we don't need anymore.
|
||||||
*((uint32_t volatile *)&parse_tree.chunk) = 0;
|
*((uint32_t volatile *)&parse_tree.chunk) = 0;
|
||||||
#else
|
#else
|
||||||
mp_raise_msg(&mp_type_RuntimeError, translate("script compilation not supported"));
|
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,11 +115,12 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
|
|
||||||
// execute code
|
// execute code
|
||||||
mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
|
mp_hal_set_interrupt_char(CHAR_CTRL_C); // allow ctrl-C to interrupt us
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
start = mp_hal_ticks_ms();
|
start = mp_hal_ticks_ms();
|
||||||
|
#endif
|
||||||
mp_call_function_0(module_fun);
|
mp_call_function_0(module_fun);
|
||||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||||
// Handle any ctrl-c interrupt that arrived just in time
|
mp_handle_pending(true); // handle any pending exceptions (and any callbacks)
|
||||||
mp_handle_pending();
|
|
||||||
nlr_pop();
|
nlr_pop();
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||||
|
@ -122,8 +128,8 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// uncaught exception
|
// uncaught exception
|
||||||
// FIXME it could be that an interrupt happens just before we disable it here
|
|
||||||
mp_hal_set_interrupt_char(-1); // disable interrupt
|
mp_hal_set_interrupt_char(-1); // disable interrupt
|
||||||
|
mp_handle_pending(false); // clear any pending exceptions (and run any callbacks)
|
||||||
// print EOF after normal output
|
// print EOF after normal output
|
||||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||||
mp_hal_stdout_tx_strn("\x04", 1);
|
mp_hal_stdout_tx_strn("\x04", 1);
|
||||||
|
@ -160,6 +166,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
// display debugging info if wanted
|
// display debugging info if wanted
|
||||||
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
|
if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) {
|
||||||
mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly
|
mp_uint_t ticks = mp_hal_ticks_ms() - start; // TODO implement a function that does this properly
|
||||||
|
@ -179,6 +186,7 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
|
||||||
gc_dump_info();
|
gc_dump_info();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
if (exec_flags & EXEC_FLAG_PRINT_EOF) {
|
||||||
mp_hal_stdout_tx_strn("\x04", 1);
|
mp_hal_stdout_tx_strn("\x04", 1);
|
||||||
|
@ -362,7 +370,7 @@ STATIC int pyexec_friendly_repl_process_char(int c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exec:;
|
exec:;
|
||||||
int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR, NULL);
|
int ret = parse_compile_execute(MP_STATE_VM(repl_line), MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR);
|
||||||
if (ret & PYEXEC_FORCED_EXIT) {
|
if (ret & PYEXEC_FORCED_EXIT) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -612,9 +620,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
|
||||||
repl_display_debugging_info = mp_obj_get_int(o_value);
|
repl_display_debugging_info = mp_obj_get_int(o_value);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
|
MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
|
||||||
|
#endif
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PYEXEC_MODE_RAW_REPL,
|
|
||||||
PYEXEC_MODE_FRIENDLY_REPL,
|
PYEXEC_MODE_FRIENDLY_REPL,
|
||||||
|
PYEXEC_MODE_RAW_REPL,
|
||||||
} pyexec_mode_kind_t;
|
} pyexec_mode_kind_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -59,8 +59,10 @@ int pyexec_frozen_module(const char *name, pyexec_result_t *result);
|
||||||
void pyexec_event_repl_init(void);
|
void pyexec_event_repl_init(void);
|
||||||
int pyexec_event_repl_process_char(int c);
|
int pyexec_event_repl_process_char(int c);
|
||||||
extern uint8_t pyexec_repl_active;
|
extern uint8_t pyexec_repl_active;
|
||||||
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
|
|
||||||
|
|
||||||
|
#if MICROPY_REPL_INFO
|
||||||
|
mp_obj_t pyb_set_repl_info(mp_obj_t o_value);
|
||||||
MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);
|
MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
|
#endif // MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H
|
||||||
|
|
|
@ -86,13 +86,8 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size,
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
STATIC mp_uint_t stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||||
sys_stdio_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
(void)self_in;
|
||||||
(void)self;
|
if (request == MP_STREAM_POLL) {
|
||||||
|
|
||||||
// For now, pretend we actually flush the stdio stream.
|
|
||||||
if (request == MP_STREAM_FLUSH) {
|
|
||||||
return 0;
|
|
||||||
} else if (request == MP_STREAM_POLL) {
|
|
||||||
return mp_hal_stdio_poll(arg);
|
return mp_hal_stdio_poll(arg);
|
||||||
} else {
|
} else {
|
||||||
*errcode = MP_EINVAL;
|
*errcode = MP_EINVAL;
|
||||||
|
|
|
@ -70,7 +70,7 @@ msgstr ""
|
||||||
msgid "%q in use"
|
msgid "%q in use"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/moductypes.c ports/atmel-samd/common-hal/pulseio/PulseIn.c
|
#: ports/atmel-samd/common-hal/pulseio/PulseIn.c
|
||||||
#: ports/cxd56/common-hal/pulseio/PulseIn.c
|
#: ports/cxd56/common-hal/pulseio/PulseIn.c
|
||||||
#: ports/nrf/common-hal/pulseio/PulseIn.c
|
#: ports/nrf/common-hal/pulseio/PulseIn.c
|
||||||
#: ports/raspberrypi/common-hal/pulseio/PulseIn.c
|
#: ports/raspberrypi/common-hal/pulseio/PulseIn.c
|
||||||
|
@ -80,7 +80,7 @@ msgid "%q index out of range"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "%q indices must be integers, not %q"
|
msgid "%q indices must be integers, not %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: shared-bindings/vectorio/Polygon.c
|
#: shared-bindings/vectorio/Polygon.c
|
||||||
|
@ -129,26 +129,10 @@ msgstr ""
|
||||||
msgid "'%q' argument required"
|
msgid "'%q' argument required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/runtime.c
|
|
||||||
msgid "'%q' object cannot assign attribute '%q'"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/proto.c
|
#: py/proto.c
|
||||||
msgid "'%q' object does not support '%q'"
|
msgid "'%q' object does not support '%q'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
|
||||||
msgid "'%q' object does not support item assignment"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/obj.c
|
|
||||||
msgid "'%q' object does not support item deletion"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/runtime.c
|
|
||||||
msgid "'%q' object has no attribute '%q'"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/runtime.c
|
||||||
msgid "'%q' object is not an iterator"
|
msgid "'%q' object is not an iterator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -161,10 +145,6 @@ msgstr ""
|
||||||
msgid "'%q' object is not iterable"
|
msgid "'%q' object is not iterable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
|
||||||
msgid "'%q' object is not subscriptable"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/emitinlinethumb.c py/emitinlinextensa.c
|
#: py/emitinlinethumb.c py/emitinlinextensa.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "'%s' expects a label"
|
msgid "'%s' expects a label"
|
||||||
|
@ -207,12 +187,31 @@ msgstr ""
|
||||||
|
|
||||||
#: py/emitinlinextensa.c
|
#: py/emitinlinextensa.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "'%s' integer %d is not within range %d..%d"
|
msgid "'%s' integer %d isn't within range %d..%d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/emitinlinethumb.c
|
#: py/emitinlinethumb.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "'%s' integer 0x%x does not fit in mask 0x%x"
|
msgid "'%s' integer 0x%x doesn't fit in mask 0x%x"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
#, c-format
|
||||||
|
msgid "'%s' object doesn't support item assignment"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
#, c-format
|
||||||
|
msgid "'%s' object doesn't support item deletion"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/runtime.c
|
||||||
|
msgid "'%s' object has no attribute '%q'"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
#, c-format
|
||||||
|
msgid "'%s' object isn't subscriptable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objstr.c
|
#: py/objstr.c
|
||||||
|
@ -664,18 +663,10 @@ msgstr ""
|
||||||
msgid "Cannot specify RTS or CTS in RS485 mode"
|
msgid "Cannot specify RTS or CTS in RS485 mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objslice.c
|
|
||||||
msgid "Cannot subclass slice"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: shared-module/bitbangio/SPI.c
|
#: shared-module/bitbangio/SPI.c
|
||||||
msgid "Cannot transfer without MOSI and MISO pins."
|
msgid "Cannot transfer without MOSI and MISO pins."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/moductypes.c
|
|
||||||
msgid "Cannot unambiguously get sizeof scalar"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: shared-bindings/pwmio/PWMOut.c
|
#: shared-bindings/pwmio/PWMOut.c
|
||||||
msgid "Cannot vary frequency on a timer that is already in use"
|
msgid "Cannot vary frequency on a timer that is already in use"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1382,14 +1373,6 @@ msgstr ""
|
||||||
msgid "Layer must be a Group or TileGrid subclass."
|
msgid "Layer must be a Group or TileGrid subclass."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objslice.c
|
|
||||||
msgid "Length must be an int"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/objslice.c
|
|
||||||
msgid "Length must be non-negative"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c
|
#: ports/esp32s2/bindings/espidf/__init__.c ports/esp32s2/esp_error.c
|
||||||
msgid "MAC address was invalid"
|
msgid "MAC address was invalid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2404,6 +2387,10 @@ msgstr ""
|
||||||
msgid "arg is an empty sequence"
|
msgid "arg is an empty sequence"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objobject.c
|
||||||
|
msgid "arg must be user-type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/ulab/code/numpy/numerical/numerical.c
|
#: extmod/ulab/code/numpy/numerical/numerical.c
|
||||||
msgid "argsort argument must be an ndarray"
|
msgid "argsort argument must be an ndarray"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2416,6 +2403,10 @@ msgstr ""
|
||||||
msgid "argument has wrong type"
|
msgid "argument has wrong type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/compile.c
|
||||||
|
msgid "argument name reused"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/argcheck.c shared-bindings/_stage/__init__.c
|
#: py/argcheck.c shared-bindings/_stage/__init__.c
|
||||||
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c
|
#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/gamepad/GamePad.c
|
||||||
msgid "argument num/types mismatch"
|
msgid "argument num/types mismatch"
|
||||||
|
@ -2569,6 +2560,10 @@ msgstr ""
|
||||||
msgid "can't assign to expression"
|
msgid "can't assign to expression"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: extmod/moduasyncio.c
|
||||||
|
msgid "can't cancel self"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c
|
#: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c
|
||||||
#: shared-module/_pixelbuf/PixelBuf.c
|
#: shared-module/_pixelbuf/PixelBuf.c
|
||||||
msgid "can't convert %q to %q"
|
msgid "can't convert %q to %q"
|
||||||
|
@ -2578,6 +2573,11 @@ msgstr ""
|
||||||
msgid "can't convert %q to int"
|
msgid "can't convert %q to int"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
#, c-format
|
||||||
|
msgid "can't convert %s to complex"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/objstr.c
|
#: py/objstr.c
|
||||||
msgid "can't convert '%q' object to %q implicitly"
|
msgid "can't convert '%q' object to %q implicitly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2586,6 +2586,10 @@ msgstr ""
|
||||||
msgid "can't convert to %q"
|
msgid "can't convert to %q"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/obj.c
|
||||||
|
msgid "can't convert to complex"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/runtime.c
|
||||||
msgid "can't convert to int"
|
msgid "can't convert to int"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2684,6 +2688,10 @@ msgstr ""
|
||||||
msgid "cannot perform relative import"
|
msgid "cannot perform relative import"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: extmod/moductypes.c
|
||||||
|
msgid "cannot unambiguously get sizeof scalar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/emitnative.c
|
#: py/emitnative.c
|
||||||
msgid "casting"
|
msgid "casting"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2732,6 +2740,10 @@ msgstr ""
|
||||||
msgid "color should be an int"
|
msgid "color should be an int"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/emitnative.c
|
||||||
|
msgid "comparison of int and uint"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: py/objcomplex.c
|
#: py/objcomplex.c
|
||||||
msgid "complex division by zero"
|
msgid "complex division by zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2834,7 +2846,15 @@ msgstr ""
|
||||||
msgid "dimensions do not match"
|
msgid "dimensions do not match"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/modmath.c py/objfloat.c py/objint_longlong.c py/objint_mpz.c py/runtime.c
|
#: py/emitnative.c
|
||||||
|
msgid "div/mod not implemented for uint"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/objfloat.c py/objint_mpz.c
|
||||||
|
msgid "divide by zero"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/modmath.c py/objint_longlong.c py/runtime.c
|
||||||
#: shared-bindings/math/__init__.c
|
#: shared-bindings/math/__init__.c
|
||||||
msgid "division by zero"
|
msgid "division by zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2843,7 +2863,7 @@ msgstr ""
|
||||||
msgid "empty"
|
msgid "empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/moduheapq.c extmod/modutimeq.c
|
#: extmod/moduasyncio.c extmod/moduheapq.c extmod/modutimeq.c
|
||||||
msgid "empty heap"
|
msgid "empty heap"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3077,10 +3097,6 @@ msgstr ""
|
||||||
msgid "import * not at module level"
|
msgid "import * not at module level"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/persistentcode.c
|
|
||||||
msgid "incompatible .mpy file"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/persistentcode.c
|
#: py/persistentcode.c
|
||||||
msgid "incompatible native .mpy architecture"
|
msgid "incompatible native .mpy architecture"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3217,10 +3233,6 @@ msgstr ""
|
||||||
msgid "invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32"
|
msgid "invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/compile.c
|
|
||||||
msgid "invalid decorator"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: shared-bindings/bitmaptools/__init__.c
|
#: shared-bindings/bitmaptools/__init__.c
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "invalid element size %d for bits_per_pixel %d\n"
|
msgid "invalid element size %d for bits_per_pixel %d\n"
|
||||||
|
@ -3427,10 +3439,6 @@ msgstr ""
|
||||||
msgid "name not defined"
|
msgid "name not defined"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/compile.c
|
|
||||||
msgid "name reused for argument"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: py/emitnative.c
|
#: py/emitnative.c
|
||||||
msgid "native yield"
|
msgid "native yield"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3485,7 +3493,7 @@ msgstr ""
|
||||||
msgid "no response from SD card"
|
msgid "no response from SD card"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/objobject.c py/runtime.c
|
||||||
msgid "no such attribute"
|
msgid "no such attribute"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3538,15 +3546,16 @@ msgid "object "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "object '%q' is not a tuple or list"
|
#, c-format
|
||||||
|
msgid "object '%s' isn't a tuple or list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "object does not support item assignment"
|
msgid "object doesn't support item assignment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "object does not support item deletion"
|
msgid "object doesn't support item deletion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
|
@ -3554,7 +3563,7 @@ msgid "object has no len"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "object is not subscriptable"
|
msgid "object isn't subscriptable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/runtime.c
|
#: py/runtime.c
|
||||||
|
@ -3574,7 +3583,8 @@ msgid "object not iterable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
msgid "object of type '%q' has no len()"
|
#, c-format
|
||||||
|
msgid "object of type '%s' has no len()"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/obj.c
|
#: py/obj.c
|
||||||
|
@ -3844,6 +3854,10 @@ msgstr ""
|
||||||
msgid "script compilation not supported"
|
msgid "script compilation not supported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: py/nativeglue.c
|
||||||
|
msgid "set unsupported"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/ulab/code/ndarray.c
|
#: extmod/ulab/code/ndarray.c
|
||||||
msgid "shape must be a tuple"
|
msgid "shape must be a tuple"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3872,12 +3886,12 @@ msgstr ""
|
||||||
msgid "sleep length must be non-negative"
|
msgid "sleep length must be non-negative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/ulab/code/ndarray.c
|
#: extmod/ulab/code/ndarray.c py/objslice.c
|
||||||
msgid "slice step can't be zero"
|
msgid "slice step can't be zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objslice.c py/sequence.c
|
#: py/nativeglue.c
|
||||||
msgid "slice step cannot be zero"
|
msgid "slice unsupported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: py/objint.c py/sequence.c
|
#: py/objint.c py/sequence.c
|
||||||
|
@ -3941,7 +3955,11 @@ msgid "string not supported; use bytes or bytearray"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/moductypes.c
|
#: extmod/moductypes.c
|
||||||
msgid "struct: cannot index"
|
msgid "struct: can't index"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: extmod/moductypes.c
|
||||||
|
msgid "struct: index out of range"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: extmod/moductypes.c
|
#: extmod/moductypes.c
|
||||||
|
|
|
@ -8,120 +8,13 @@
|
||||||
#include "py/mpstate.h"
|
#include "py/mpstate.h"
|
||||||
#include "py/gc.h"
|
#include "py/gc.h"
|
||||||
|
|
||||||
|
#include "lib/utils/gchelper.h"
|
||||||
|
|
||||||
#if MICROPY_ENABLE_GC
|
#if MICROPY_ENABLE_GC
|
||||||
|
|
||||||
// Even if we have specific support for an architecture, it is
|
|
||||||
// possible to force use of setjmp-based implementation.
|
|
||||||
#if !MICROPY_GCREGS_SETJMP
|
|
||||||
|
|
||||||
// We capture here callee-save registers, i.e. ones which may contain
|
|
||||||
// interesting values held there by our callers. It doesn't make sense
|
|
||||||
// to capture caller-saved registers, because they, well, put on the
|
|
||||||
// stack already by the caller.
|
|
||||||
#if defined(__x86_64__)
|
|
||||||
typedef mp_uint_t regs_t[6];
|
|
||||||
|
|
||||||
STATIC void gc_helper_get_regs(regs_t arr) {
|
|
||||||
register long rbx asm ("rbx");
|
|
||||||
register long rbp asm ("rbp");
|
|
||||||
register long r12 asm ("r12");
|
|
||||||
register long r13 asm ("r13");
|
|
||||||
register long r14 asm ("r14");
|
|
||||||
register long r15 asm ("r15");
|
|
||||||
#ifdef __clang__
|
|
||||||
// TODO:
|
|
||||||
// This is dirty workaround for Clang. It tries to get around
|
|
||||||
// uncompliant (wrt to GCC) behavior of handling register variables.
|
|
||||||
// Application of this patch here is random, and done only to unbreak
|
|
||||||
// MacOS build. Better, cross-arch ways to deal with Clang issues should
|
|
||||||
// be found.
|
|
||||||
asm ("" : "=r" (rbx));
|
|
||||||
asm ("" : "=r" (rbp));
|
|
||||||
asm ("" : "=r" (r12));
|
|
||||||
asm ("" : "=r" (r13));
|
|
||||||
asm ("" : "=r" (r14));
|
|
||||||
asm ("" : "=r" (r15));
|
|
||||||
#endif
|
|
||||||
arr[0] = rbx;
|
|
||||||
arr[1] = rbp;
|
|
||||||
arr[2] = r12;
|
|
||||||
arr[3] = r13;
|
|
||||||
arr[4] = r14;
|
|
||||||
arr[5] = r15;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(__i386__)
|
|
||||||
|
|
||||||
typedef mp_uint_t regs_t[4];
|
|
||||||
|
|
||||||
STATIC void gc_helper_get_regs(regs_t arr) {
|
|
||||||
register long ebx asm ("ebx");
|
|
||||||
register long esi asm ("esi");
|
|
||||||
register long edi asm ("edi");
|
|
||||||
register long ebp asm ("ebp");
|
|
||||||
arr[0] = ebx;
|
|
||||||
arr[1] = esi;
|
|
||||||
arr[2] = edi;
|
|
||||||
arr[3] = ebp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
|
|
||||||
|
|
||||||
typedef mp_uint_t regs_t[10];
|
|
||||||
|
|
||||||
STATIC void gc_helper_get_regs(regs_t arr) {
|
|
||||||
register long r4 asm ("r4");
|
|
||||||
register long r5 asm ("r5");
|
|
||||||
register long r6 asm ("r6");
|
|
||||||
register long r7 asm ("r7");
|
|
||||||
register long r8 asm ("r8");
|
|
||||||
register long r9 asm ("r9");
|
|
||||||
register long r10 asm ("r10");
|
|
||||||
register long r11 asm ("r11");
|
|
||||||
register long r12 asm ("r12");
|
|
||||||
register long r13 asm ("r13");
|
|
||||||
arr[0] = r4;
|
|
||||||
arr[1] = r5;
|
|
||||||
arr[2] = r6;
|
|
||||||
arr[3] = r7;
|
|
||||||
arr[4] = r8;
|
|
||||||
arr[5] = r9;
|
|
||||||
arr[6] = r10;
|
|
||||||
arr[7] = r11;
|
|
||||||
arr[8] = r12;
|
|
||||||
arr[9] = r13;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
// If we don't have architecture-specific optimized support,
|
|
||||||
// just fall back to setjmp-based implementation.
|
|
||||||
#undef MICROPY_GCREGS_SETJMP
|
|
||||||
#define MICROPY_GCREGS_SETJMP (1)
|
|
||||||
|
|
||||||
#endif // Arch-specific selection
|
|
||||||
#endif // !MICROPY_GCREGS_SETJMP
|
|
||||||
|
|
||||||
// If MICROPY_GCREGS_SETJMP was requested explicitly, or if
|
|
||||||
// we enabled it as a fallback above.
|
|
||||||
#if MICROPY_GCREGS_SETJMP
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
typedef jmp_buf regs_t;
|
|
||||||
|
|
||||||
STATIC void gc_helper_get_regs(regs_t arr) {
|
|
||||||
setjmp(arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MICROPY_GCREGS_SETJMP
|
|
||||||
|
|
||||||
void gc_collect(void) {
|
void gc_collect(void) {
|
||||||
gc_collect_start();
|
gc_collect_start();
|
||||||
regs_t regs;
|
gc_helper_collect_regs_and_stack();
|
||||||
gc_helper_get_regs(regs);
|
|
||||||
// GC stack (and regs because we captured them)
|
|
||||||
void **regs_ptr = (void **)(void *)®s;
|
|
||||||
gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)®s) / sizeof(mp_uint_t));
|
|
||||||
gc_collect_end();
|
gc_collect_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ mp_uint_t mp_verbose_flag = 0;
|
||||||
// Make it larger on a 64 bit machine, because pointers are larger.
|
// Make it larger on a 64 bit machine, because pointers are larger.
|
||||||
long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
|
long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
|
||||||
|
|
||||||
STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) {
|
STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
|
||||||
(void)env;
|
(void)env;
|
||||||
ssize_t dummy = write(STDERR_FILENO, str, len);
|
ssize_t dummy = write(STDERR_FILENO, str, len);
|
||||||
(void)dummy;
|
(void)dummy;
|
||||||
|
@ -324,7 +324,7 @@ uint mp_import_stat(const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nlr_jump_fail(void *val) {
|
void nlr_jump_fail(void *val) {
|
||||||
printf("FATAL: uncaught NLR %p\n", val);
|
fprintf(stderr, "FATAL: uncaught NLR %p\n", val);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,14 +48,9 @@
|
||||||
|
|
||||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||||
|
|
||||||
// Define to 1 to use undertested inefficient GC helper implementation
|
#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
|
||||||
// (if more efficient arch-specific one is not available).
|
// Fall back to setjmp() implementation for discovery of GC pointers in registers.
|
||||||
#ifndef MICROPY_GCREGS_SETJMP
|
|
||||||
#ifdef __mips__
|
|
||||||
#define MICROPY_GCREGS_SETJMP (1)
|
#define MICROPY_GCREGS_SETJMP (1)
|
||||||
#else
|
|
||||||
#define MICROPY_GCREGS_SETJMP (0)
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MICROPY_PY___FILE__ (0)
|
#define MICROPY_PY___FILE__ (0)
|
||||||
|
|
|
@ -69,6 +69,7 @@ endif
|
||||||
SRC_C += \
|
SRC_C += \
|
||||||
main.c \
|
main.c \
|
||||||
gccollect.c \
|
gccollect.c \
|
||||||
|
lib/utils/gchelper_generic.c \
|
||||||
supervisor/stub/safe_mode.c \
|
supervisor/stub/safe_mode.c \
|
||||||
supervisor/stub/stack.c \
|
supervisor/stub/stack.c \
|
||||||
supervisor/shared/translate.c
|
supervisor/shared/translate.c
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue