Compare commits
193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff8d0e071c | ||
|
|
0e3722137f | ||
|
|
8e701604d5 | ||
|
|
bc0bc764fc | ||
|
|
183ac71dc8 | ||
|
|
1e3fde0a10 | ||
|
|
72165c01f0 | ||
|
|
ff319dffad | ||
|
|
0344fa1ddf | ||
|
|
2cd79fa924 | ||
|
|
bfd11a35db | ||
|
|
f6e825b42e | ||
|
|
6e6dfdc56b | ||
|
|
1060baa2c2 | ||
|
|
38bd762121 | ||
|
|
039887a0ac | ||
|
|
a58713a899 | ||
|
|
c7da7838ba | ||
|
|
109c1de015 | ||
|
|
4029f51842 | ||
|
|
1559a97810 | ||
|
|
fa73c9cb25 | ||
|
|
88d3054ac0 | ||
|
|
7c4445afe1 | ||
|
|
1a8573ed0e | ||
|
|
47f349e7de | ||
|
|
c92ef361c7 | ||
|
|
4ef67d30f1 | ||
|
|
9a41b32b3f | ||
|
|
efc49c5591 | ||
|
|
6a15ac80dc | ||
|
|
504636815e | ||
|
|
0e557facb9 | ||
|
|
e62a0fe367 | ||
|
|
31619cc589 | ||
|
|
11aa91615e | ||
|
|
8bb71f0b06 | ||
|
|
66d08eb4fe | ||
|
|
6d287a6a02 | ||
|
|
2559e13957 | ||
|
|
b1422de12f | ||
|
|
49c47da804 | ||
|
|
4e54c876a7 | ||
|
|
ccedf000ed | ||
|
|
429e3f077e | ||
|
|
8768f8ad4b | ||
|
|
e4e52f5370 | ||
|
|
e503512f83 | ||
|
|
bc1488a05f | ||
|
|
b2f19b8d34 | ||
|
|
480a7ce58f | ||
|
|
de3c806965 | ||
|
|
c76af32575 | ||
|
|
b0b0012fd8 | ||
|
|
91bd4e8a23 | ||
|
|
124df6f8d0 | ||
|
|
d7353fe6fe | ||
|
|
627852019b | ||
|
|
c9fc620723 | ||
|
|
e5a3759ff5 | ||
|
|
8becca7c82 | ||
|
|
8456cc017b | ||
|
|
1084b0f9c2 | ||
|
|
fcff4663dd | ||
|
|
8204db6831 | ||
|
|
21dfd207ca | ||
|
|
a64d5d67b5 | ||
|
|
0b13f3e026 | ||
|
|
564963a170 | ||
|
|
d00d8ac95c | ||
|
|
e294bee45b | ||
|
|
e5b1b7348a | ||
|
|
e2f8d98525 | ||
|
|
185cb0d943 | ||
|
|
e7bb0443cd | ||
|
|
dd4f4530ab | ||
|
|
3aa09f5784 | ||
|
|
37378f8a9d | ||
|
|
f5d69794a8 | ||
|
|
e72be1b999 | ||
|
|
5fc42a6c97 | ||
|
|
842210f53a | ||
|
|
e7a478204a | ||
|
|
efa04eafd3 | ||
|
|
d46a822262 | ||
|
|
3be6984b8f | ||
|
|
8d62bbd46a | ||
|
|
3e42570538 | ||
|
|
481d714bd5 | ||
|
|
20f59e182e | ||
|
|
b1e217222e | ||
|
|
a3efe04dce | ||
|
|
2fe4cf7761 | ||
|
|
abf0f07a5a | ||
|
|
072bd07f17 | ||
|
|
0c3955b506 | ||
|
|
21ca2d76a2 | ||
|
|
9c9db3a7a1 | ||
|
|
1a55b6a787 | ||
|
|
c92672d7f8 | ||
|
|
b7a4b0f86f | ||
|
|
297d8469b8 | ||
|
|
391db8669b | ||
|
|
235f9b33c8 | ||
|
|
9870fdd4b0 | ||
|
|
c30595eb1b | ||
|
|
090c9236e8 | ||
|
|
37ada236b3 | ||
|
|
923a8a8320 | ||
|
|
0c7b26c0f8 | ||
|
|
067ae1269d | ||
|
|
9b0b373e5e | ||
|
|
4859edb95b | ||
|
|
95908b0f50 | ||
|
|
d27c0bb3aa | ||
|
|
911c00bbc5 | ||
|
|
e6c5a63fab | ||
|
|
4b71c056ef | ||
|
|
29f5682621 | ||
|
|
bfb6af857a | ||
|
|
34162872b1 | ||
|
|
426bb58b23 | ||
|
|
50062587c7 | ||
|
|
136b5cbd76 | ||
|
|
0107e90328 | ||
|
|
c14a81662c | ||
|
|
3c34d4140d | ||
|
|
91cfd414c0 | ||
|
|
1ef2348df0 | ||
|
|
1606607bd4 | ||
|
|
457c0a606c | ||
|
|
fbf976c9aa | ||
|
|
37671c9a97 | ||
|
|
dd5ee9ff9c | ||
|
|
26fa3e30ec | ||
|
|
945df4e564 | ||
|
|
1ce916aefd | ||
|
|
c36c75c4dc | ||
|
|
6c2ab5c315 | ||
|
|
f7bcce0552 | ||
|
|
5edbadefc1 | ||
|
|
c71e045165 | ||
|
|
1c795445b3 | ||
|
|
9b6617ea8b | ||
|
|
cc5b4a2653 | ||
|
|
23b3b04072 | ||
|
|
a2d8f98a7e | ||
|
|
1e49b151a7 | ||
|
|
f0f964807e | ||
|
|
9bf5f2857d | ||
|
|
a8202762f0 | ||
|
|
40e4c777a1 | ||
|
|
7989b07637 | ||
|
|
4091445612 | ||
|
|
e20cbbec73 | ||
|
|
2090a98e80 | ||
|
|
3556e45711 | ||
|
|
67f25dfe6f | ||
|
|
5d328cbeb9 | ||
|
|
5dc8f9b28a | ||
|
|
9aeec0e3a3 | ||
|
|
f53c343363 | ||
|
|
9c6f7378f7 | ||
|
|
f32498fe04 | ||
|
|
fec70ad369 | ||
|
|
9336ee320a | ||
|
|
fcdb239815 | ||
|
|
a9bcd51dc7 | ||
|
|
5a04e2cca8 | ||
|
|
854c8c0153 | ||
|
|
d03c681608 | ||
|
|
c4d0868df1 | ||
|
|
a91ac2011f | ||
|
|
6dba992182 | ||
|
|
ba0383a8c7 | ||
|
|
55f68b3ce8 | ||
|
|
97ef94df83 | ||
|
|
c3ab90da46 | ||
|
|
d112cbfd7c | ||
|
|
dc1ea1156a | ||
|
|
a2f9c9445a | ||
|
|
24119176e7 | ||
|
|
c568a2b443 | ||
|
|
1f2558d647 | ||
|
|
e5268963c6 | ||
|
|
00be7a849a | ||
|
|
39dc145478 | ||
|
|
3eaa0c3833 | ||
|
|
42f3de924b | ||
|
|
877dba3e1a | ||
|
|
e535a61983 | ||
|
|
3550de4ebe | ||
|
|
5fc6aa8100 |
@@ -8,6 +8,8 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y python3.3 python3 gcc-4.7 gcc-arm-none-eabi qemu-system mingw32
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
|
||||
script:
|
||||
- make -C unix CC=gcc-4.7
|
||||
@@ -15,6 +17,7 @@ script:
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm
|
||||
- make -C stmhal
|
||||
- make -C stmhal -B MICROPY_PY_WIZNET5K=1 MICROPY_PY_CC3K=1
|
||||
- make -C stmhal BOARD=STM32F4DISC
|
||||
- make -C teensy
|
||||
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
|
||||
|
||||
15
README.md
@@ -49,23 +49,28 @@ The Unix version
|
||||
|
||||
The "unix" port requires a standard Unix environment with gcc and GNU make.
|
||||
x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well
|
||||
as ARMv7. Porting to other architectures require writing some assembly code
|
||||
for the exception handling.
|
||||
as ARM and MIPS. Making full-featured port to another architecture requires
|
||||
writing some assembly code for the exception handling and garbage collection.
|
||||
Alternatively, fallback implementation based on setjmp/longjmp can be used.
|
||||
|
||||
To build:
|
||||
|
||||
$ cd unix
|
||||
$ make
|
||||
|
||||
Then to test it:
|
||||
Then to give it a try:
|
||||
|
||||
$ ./micropython
|
||||
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])
|
||||
|
||||
Run complete testsuite:
|
||||
|
||||
$ make test
|
||||
|
||||
Debian/Ubuntu/Mint derivative Linux distros will require build-essentials and
|
||||
libreadline-dev packages installed. To build FFI (Foreign Function Interface)
|
||||
module, libffi-dev package is required. If you have problems with some
|
||||
dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
module, libffi-dev and pkg-config packages are required. If you have problems
|
||||
with some dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
|
||||
The STM version
|
||||
---------------
|
||||
|
||||
@@ -36,8 +36,9 @@ void do_str(const char *src) {
|
||||
mp_lexer_free(lex);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
if (mp_obj_is_exception_instance(module_fun)) {
|
||||
// compile error
|
||||
mp_obj_print_exception(module_fun);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,10 +70,10 @@ mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_open_obj, 1, 2, mp_builtin_open);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define MICROPY_HELPER_LEXER_UNIX (0)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (0)
|
||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
||||
#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
|
||||
#define MICROPY_PY_BUILTINS_FROZENSET (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
||||
|
||||
10
docs/conf.py
@@ -60,7 +60,7 @@ copyright = '2014, Damien P. George'
|
||||
# The short X.Y version.
|
||||
version = '1.3'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.3.1'
|
||||
release = '1.3.6'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -113,7 +113,7 @@ html_theme = 'default'
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
html_theme_path = ['.']
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
@@ -124,7 +124,7 @@ html_theme = 'default'
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
#html_logo = '../logo/trans-logo.png'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
@@ -143,7 +143,7 @@ html_theme = 'default'
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
html_last_updated_fmt = '%d %b %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
@@ -154,7 +154,7 @@ html_theme = 'default'
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
html_additional_pages = {"index":"topindex.html"}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
11
docs/contents.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
Micro Python documentation contents
|
||||
===================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
quickref.rst
|
||||
general.rst
|
||||
tutorial/index.rst
|
||||
library/index.rst
|
||||
hardware/index.rst
|
||||
license.rst
|
||||
20
docs/hardware/index.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
The pyboard hardware
|
||||
====================
|
||||
|
||||
* `PYBv1.0 schematics and layout <http://micropython.org/resources/PYBv10b.pdf>`_ (2.4MiB PDF)
|
||||
* `PYBv1.0 metric dimensions <http://micropython.org/resources/PYBv10b-metric-dimensions.pdf>`_ (360KiB PDF)
|
||||
* `PYBv1.0 imperial dimensions <http://micropython.org/resources/PYBv10b-imperial-dimensions.pdf>`_ (360KiB PDF)
|
||||
|
||||
Datasheets for the components on the pyboard
|
||||
============================================
|
||||
|
||||
* The microcontroller: `STM32F405RGT6 <http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN1035/PF252144>`_ (link to manufacturer's site)
|
||||
* The accelerometer: `Freescale MMA7660 <http://micropython.org/resources/datasheets/MMA7660FC.pdf>`_ (800kiB PDF)
|
||||
* The LDO voltage regulator: `Microchip MCP1802 <http://micropython.org/resources/datasheets/MCP1802-22053C.pdf>`_ (400kiB PDF)
|
||||
|
||||
Datasheets for other components
|
||||
===============================
|
||||
|
||||
* The LCD display on the LCD touch-sensor skin: `Newhaven Display NHD-C12832A1Z-FSW-FBW-3V3 <http://micropython.org/resources/datasheets/NHD-C12832A1Z-FSW-FBW-3V3.pdf>`_ (460KiB PDF)
|
||||
* The touch sensor chip on the LCD touch-sensor skin: `Freescale MPR121 <http://micropython.org/resources/datasheets/MPR121.pdf>`_ (280KiB PDF)
|
||||
* The digital potentiometer on the audio skin: `Microchip MCP4541 <http://micropython.org/resources/datasheets/MCP4541-22107B.pdf>`_ (2.7MiB PDF)
|
||||
@@ -1,38 +1,15 @@
|
||||
.. Micro Python documentation master file
|
||||
|
||||
Micro Python documentation and references
|
||||
=========================================
|
||||
|
||||
Here you can find documentation for Micro Python and the pyboard.
|
||||
|
||||
Software
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
quickref.rst
|
||||
general.rst
|
||||
tutorial/index.rst
|
||||
|
||||
..
|
||||
.. - Reference for the [pyb module](module/pyb/ "pyb module").
|
||||
.. - Reference for [all modules](module/ "all modules").
|
||||
.. - [Guide for setting up the pyboard on Windows](/static/doc/Micro-Python-Windows-setup.pdf), including DFU programming (PDF).
|
||||
|
||||
The pyboard hardware
|
||||
--------------------
|
||||
|
||||
.. - PYBv1.0 [schematics and layout](/static/doc/PYBv10b.pdf "PYBv1.0") (2.4MiB PDF).
|
||||
.. - PYBv1.0 [metric dimensions](/static/doc/PYBv10b-metric-dimensions.pdf "metric dimensions") (360KiB PDF).
|
||||
.. - PYBv1.0 [imperial dimensions](/static/doc/PYBv10b-imperial-dimensions.pdf "imperial dimensions") (360KiB PDF).
|
||||
|
||||
Datasheets for the components on the pyboard
|
||||
--------------------------------------------
|
||||
|
||||
.. - The microcontroller: [STM32F405RGT6](http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1577/LN1035/PF252144) (external link).
|
||||
.. - The accelerometer: [Freescale MMA7660](/static/doc/MMA7660FC.pdf) (800kiB PDF).
|
||||
.. - The LDO voltage regulator: [Microchip MCP1802](/static/doc/MCP1802-22053C.pdf) (400kiB PDF).
|
||||
|
||||
library/index.rst
|
||||
hardware/index.rst
|
||||
license.rst
|
||||
contents.rst
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
@@ -40,4 +17,3 @@ Indices and tables
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
||||
58
docs/library/cmath.rst
Normal file
@@ -0,0 +1,58 @@
|
||||
:mod:`cmath` -- mathematical functions for complex numbers
|
||||
==========================================================
|
||||
|
||||
.. module:: cmath
|
||||
:synopsis: mathematical functions for complex numbers
|
||||
|
||||
The ``cmath`` module provides some basic mathematical funtions for
|
||||
working with complex numbers.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: cos(z)
|
||||
|
||||
Return the cosine of ``z``.
|
||||
|
||||
.. function:: exp(z)
|
||||
|
||||
Return the exponential of ``z``.
|
||||
|
||||
.. function:: log(z)
|
||||
|
||||
Return the natural logarithm of ``z``. The branch cut is along the negative real axis.
|
||||
|
||||
.. function:: log10(z)
|
||||
|
||||
Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis.
|
||||
|
||||
.. function:: phase(z)
|
||||
|
||||
Returns the phase of the number ``z``, in the range (-pi, +pi].
|
||||
|
||||
.. function:: polar(z)
|
||||
|
||||
Returns, as a tuple, the polar form of ``z``.
|
||||
|
||||
.. function:: rect(r, phi)
|
||||
|
||||
Returns the complex number with modulus ``r`` and phase ``phi``.
|
||||
|
||||
.. function:: sin(z)
|
||||
|
||||
Return the sine of ``z``.
|
||||
|
||||
.. function:: sqrt(z)
|
||||
|
||||
Return the square-root of ``z``.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: e
|
||||
|
||||
base of the natural logarithm
|
||||
|
||||
.. data:: pi
|
||||
|
||||
the ratio of a circle's circumference to its diameter
|
||||
29
docs/library/gc.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
:mod:`gc` -- control the garbage collector
|
||||
==========================================
|
||||
|
||||
.. module:: gc
|
||||
:synopsis: control the garbage collector
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: enable()
|
||||
|
||||
Enable automatic garbage collection.
|
||||
|
||||
.. function:: disable()
|
||||
|
||||
Disable automatic garbage collection. Heap memory can still be allocated,
|
||||
and garbage collection can still be initiated manually using :meth:`gc.collect`.
|
||||
|
||||
.. function:: collect()
|
||||
|
||||
Run a garbage collection.
|
||||
|
||||
.. function:: mem_alloc()
|
||||
|
||||
Return the number of bytes of heap RAM that are allocated.
|
||||
|
||||
.. function:: mem_free()
|
||||
|
||||
Return the number of bytes of available heap RAM.
|
||||
54
docs/library/index.rst
Normal file
@@ -0,0 +1,54 @@
|
||||
Micro Python libraries
|
||||
======================
|
||||
|
||||
Python standard libraries
|
||||
-------------------------
|
||||
|
||||
The following standard Python libraries are built in to Micro Python.
|
||||
|
||||
For additional libraries, please download them from the `micropython-lib repository
|
||||
<https://github.com/micropython/micropython-lib>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cmath.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
os.rst
|
||||
select.rst
|
||||
struct.rst
|
||||
sys.rst
|
||||
time.rst
|
||||
|
||||
Python micro-libraries
|
||||
----------------------
|
||||
|
||||
The following standard Python libraries have been "micro-ified" to fit in with
|
||||
the philosophy of Micro Python. They provide the core functionality of that
|
||||
module and are intended to be a drop-in replacement for the standard Python
|
||||
library.
|
||||
|
||||
The modules are available by their u-name, and also by their non-u-name. The
|
||||
non-u-name can be overridden by a file of that name in your package path.
|
||||
For example, ``import json`` will first search for a file ``json.py`` or
|
||||
directory ``json`` and load that package if it is found. If nothing is found,
|
||||
it will fallback to loading the built-in ``ujson`` module.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
usocket.rst
|
||||
uheapq.rst
|
||||
ujson.rst
|
||||
|
||||
Libraries specific to the pyboard
|
||||
---------------------------------
|
||||
|
||||
The following libraries are specific to the pyboard.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
pyb.rst
|
||||
network.rst
|
||||
177
docs/library/math.rst
Normal file
@@ -0,0 +1,177 @@
|
||||
:mod:`math` -- mathematical functions
|
||||
=====================================
|
||||
|
||||
.. module:: math
|
||||
:synopsis: mathematical functions
|
||||
|
||||
The ``math`` module provides some basic mathematical funtions for
|
||||
working with floating-point numbers.
|
||||
|
||||
*Note:* On the pyboard, floating-point numbers have 32-bit precision.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: acos(x)
|
||||
|
||||
Return the inverse cosine of ``x``.
|
||||
|
||||
.. function:: acosh(x)
|
||||
|
||||
Return the inverse hyperbolic cosine of ``x``.
|
||||
|
||||
.. function:: asin(x)
|
||||
|
||||
Return the inverse sine of ``x``.
|
||||
|
||||
.. function:: asinh(x)
|
||||
|
||||
Return the inverse hyperbolic sine of ``x``.
|
||||
|
||||
.. function:: atan(x)
|
||||
|
||||
Return the inverse tangent of ``x``.
|
||||
|
||||
.. function:: atan2(y, x)
|
||||
|
||||
Return the principal value of the inverse tangent of ``y/x``.
|
||||
|
||||
.. function:: atanh(x)
|
||||
|
||||
Return the inverse hyperbolic tangent of ``x``.
|
||||
|
||||
.. function:: ceil(x)
|
||||
|
||||
Return an integer, being ``x`` rounded towards positive infinity.
|
||||
|
||||
.. function:: copysign(x, y)
|
||||
|
||||
Return ``x`` with the sign of ``y``.
|
||||
|
||||
.. function:: cos(x)
|
||||
|
||||
Return the cosine of ``x``.
|
||||
|
||||
.. function:: cosh(x)
|
||||
|
||||
Return the hyperbolic cosine of ``x``.
|
||||
|
||||
.. function:: degrees(x)
|
||||
|
||||
Return radians ``x`` converted to degrees.
|
||||
|
||||
.. function:: erf(x)
|
||||
|
||||
Return the error function of ``x``.
|
||||
|
||||
.. function:: erfc(x)
|
||||
|
||||
Return the complementary error function of ``x``.
|
||||
|
||||
.. function:: exp(x)
|
||||
|
||||
Return the exponential of ``x``.
|
||||
|
||||
.. function:: expm1(x)
|
||||
|
||||
Return ``exp(x) - 1``.
|
||||
|
||||
.. function:: fabs(x)
|
||||
|
||||
Return the absolute value of ``x``.
|
||||
|
||||
.. function:: floor(x)
|
||||
|
||||
Return an integer, being ``x`` rounded towards negative infinity.
|
||||
|
||||
.. function:: fmod(x, y)
|
||||
|
||||
Return the remainder of ``x/y``.
|
||||
|
||||
.. function:: frexp(x)
|
||||
|
||||
Converts a floating-point number to fractional and integral components.
|
||||
|
||||
.. function:: gamma(x)
|
||||
|
||||
Return the gamma function of ``x``.
|
||||
|
||||
.. function:: isfinite(x)
|
||||
|
||||
Return ``True`` if ``x`` is finite.
|
||||
|
||||
.. function:: isinf(x)
|
||||
|
||||
Return ``True`` if ``x`` is infinite.
|
||||
|
||||
.. function:: isnan(x)
|
||||
|
||||
Return ``True`` if ``x`` is not-a-number
|
||||
|
||||
.. function:: ldexp(x, exp)
|
||||
|
||||
Return ``x * (2**exp)``.
|
||||
|
||||
.. function:: lgamma(x)
|
||||
|
||||
Return the natural logarithm of the gamma function of ``x``.
|
||||
|
||||
.. function:: log(x)
|
||||
|
||||
Return the natural logarithm of ``x``.
|
||||
|
||||
.. function:: log10(x)
|
||||
|
||||
Return the base-10 logarithm of ``x``.
|
||||
|
||||
.. function:: log2(x)
|
||||
|
||||
Return the base-2 logarithm of ``x``.
|
||||
|
||||
.. function:: modf(x)
|
||||
|
||||
Return a tuple of two floats, being the fractional and integral parts of
|
||||
``x``. Both return values have the same sign as ``x``.
|
||||
|
||||
.. function:: pow(x, y)
|
||||
|
||||
Returns ``x`` to the power of ``y``.
|
||||
|
||||
.. function:: radians(x)
|
||||
|
||||
Return degrees ``x`` converted to radians.
|
||||
|
||||
.. function:: sin(x)
|
||||
|
||||
Return the sine of ``x``.
|
||||
|
||||
.. function:: sinh(x)
|
||||
|
||||
Return the hyperbolic sine of ``x``.
|
||||
|
||||
.. function:: sqrt(x)
|
||||
|
||||
Return the square root of ``x``.
|
||||
|
||||
.. function:: tan(x)
|
||||
|
||||
Return the tangent of ``x``.
|
||||
|
||||
.. function:: tanh(x)
|
||||
|
||||
Return the hyperbolic tangent of ``x``.
|
||||
|
||||
.. function:: trunc(x)
|
||||
|
||||
Return an integer, being ``x`` rounded towards 0.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: e
|
||||
|
||||
base of the natural logarithm
|
||||
|
||||
.. data:: pi
|
||||
|
||||
the ratio of a circle's circumference to its diameter
|
||||
63
docs/library/network.rst
Normal file
@@ -0,0 +1,63 @@
|
||||
****************************************
|
||||
:mod:`network` --- network configuration
|
||||
****************************************
|
||||
|
||||
.. module:: network
|
||||
:synopsis: network configuration
|
||||
|
||||
This module provides network drivers and routing configuration.
|
||||
|
||||
|
||||
class CC3k
|
||||
==========
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: CC3k(spi, pin_cs, pin_en, pin_irq)
|
||||
|
||||
Initialise the CC3000 using the given SPI bus and pins and return a CC3k object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: cc3k.connect(ssid, key=None, \*, security=WPA2, bssid=None)
|
||||
|
||||
|
||||
class WIZnet5k
|
||||
==============
|
||||
|
||||
This class allows you to control WIZnet5x00 Ethernet adaptors based on
|
||||
the W5200 and W5500 chipsets (only W5200 tested).
|
||||
|
||||
Example usage::
|
||||
|
||||
import wiznet5k
|
||||
w = wiznet5k.WIZnet5k()
|
||||
print(w.ipaddr())
|
||||
w.gethostbyname('micropython.org')
|
||||
s = w.socket()
|
||||
s.connect(('192.168.0.2', 8080))
|
||||
s.send('hello')
|
||||
print(s.recv(10))
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WIZnet5k(spi, pin_cs, pin_rst)
|
||||
|
||||
Create and return a WIZnet5k object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: wiznet5k.ipaddr([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP address, subnet mask, gateway and DNS.
|
||||
|
||||
.. method:: wiznet5k.regs()
|
||||
|
||||
Dump WIZnet5k registers.
|
||||
67
docs/library/os.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
:mod:`os` -- basic "operating system" services
|
||||
==============================================
|
||||
|
||||
.. module:: os
|
||||
:synopsis: basic "operating system" services
|
||||
|
||||
The ``os`` module contains functions for filesystem access and ``urandom``.
|
||||
|
||||
Pyboard specifics
|
||||
-----------------
|
||||
|
||||
The filesystem on the pyboard has ``/`` as the root directory and the
|
||||
available physical drives are accessible from here. They are currently:
|
||||
|
||||
``/flash`` -- the internal flash filesystem
|
||||
|
||||
``/sd`` -- the SD card (if it exists)
|
||||
|
||||
On boot up, the current directory is ``/flash`` if no SD card is inserted,
|
||||
otherwise it is ``/sd``.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: chdir(path)
|
||||
|
||||
Change current directory.
|
||||
|
||||
.. function:: getcwd()
|
||||
|
||||
Get the current directory.
|
||||
|
||||
.. function:: listdir([dir])
|
||||
|
||||
With no argument, list the current directory. Otherwise list the given directory.
|
||||
|
||||
.. function:: mkdir(path)
|
||||
|
||||
Create a new directory.
|
||||
|
||||
.. function:: remove(path)
|
||||
|
||||
Remove a file.
|
||||
|
||||
.. function:: rmdir(path)
|
||||
|
||||
Remove a directory.
|
||||
|
||||
.. function:: stat(path)
|
||||
|
||||
Get the status of a file or directory.
|
||||
|
||||
.. function:: sync()
|
||||
|
||||
Sync all filesystems.
|
||||
|
||||
.. function:: urandom(n)
|
||||
|
||||
Return a bytes object with n random bytes, generated by the hardware
|
||||
random number generator.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: sep
|
||||
|
||||
separation character used in paths
|
||||
52
docs/library/pyb.ADC.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
.. _pyb.ADC:
|
||||
|
||||
class ADC -- analog to digital conversion: read analog values on a pin
|
||||
======================================================================
|
||||
|
||||
Usage::
|
||||
|
||||
import pyb
|
||||
|
||||
adc = pyb.ADC(pin) # create an analog object from a pin
|
||||
val = adc.read() # read an analog value
|
||||
|
||||
adc = pyb.ADCAll(resolution) # creale an ADCAll object
|
||||
val = adc.read_channel(channel) # read the given channel
|
||||
val = adc.read_core_temp() # read MCU temperature
|
||||
val = adc.read_core_vbat() # read MCU VBAT
|
||||
val = adc.read_core_vref() # read MCU VREF
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.ADC(pin)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: adc.read()
|
||||
|
||||
Read the value on the analog pin and return it. The returned value
|
||||
will be between 0 and 4095.
|
||||
|
||||
.. method:: adc.read_timed(buf, freq)
|
||||
|
||||
Read analog values into the given buffer at the given frequency. Buffer
|
||||
can be bytearray or array.array for example. If a buffer with 8-bit elements
|
||||
is used, sample resolution will be reduced to 8 bits.
|
||||
|
||||
Example::
|
||||
|
||||
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
||||
buf = bytearray(100) # create a buffer of 100 bytes
|
||||
adc.read_timed(buf, 10) # read analog values into buf at 10Hz
|
||||
# this will take 10 seconds to finish
|
||||
for val in buf: # loop over all values
|
||||
print(val) # print the value out
|
||||
|
||||
This function does not allocate any memory.
|
||||
51
docs/library/pyb.Accel.rst
Normal file
@@ -0,0 +1,51 @@
|
||||
class Accel -- accelerometer control
|
||||
====================================
|
||||
|
||||
Accel is an object that controls the accelerometer. Example usage::
|
||||
|
||||
accel = pyb.Accel()
|
||||
for i in range(10):
|
||||
print(accel.x(), accel.y(), accel.z())
|
||||
|
||||
Raw values are between -32 and 31.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Accel()
|
||||
|
||||
Create and return an accelerometer object.
|
||||
|
||||
Note: if you read accelerometer values immediately after creating this object
|
||||
you will get 0. It takes around 20ms for the first sample to be ready, so,
|
||||
unless you have some other code between creating this object and reading its
|
||||
values, you should put a ``pyb.delay(20)`` after creating it. For example::
|
||||
|
||||
accel = pyb.Accel()
|
||||
pyb.delay(20)
|
||||
print(accel.x())
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: accel.filtered_xyz()
|
||||
|
||||
Get a 3-tuple of filtered x, y and z values.
|
||||
|
||||
.. method:: accel.tilt()
|
||||
|
||||
Get the tilt register.
|
||||
|
||||
.. method:: accel.x()
|
||||
|
||||
Get the x-axis value.
|
||||
|
||||
.. method:: accel.y()
|
||||
|
||||
Get the y-axis value.
|
||||
|
||||
.. method:: accel.z()
|
||||
|
||||
Get the z-axis value.
|
||||
87
docs/library/pyb.CAN.rst
Normal file
@@ -0,0 +1,87 @@
|
||||
class CAN -- controller area network communication bus
|
||||
======================================================
|
||||
|
||||
CAN implements the standard CAN communications protocol. At
|
||||
the physical level it consists of 2 lines: RX and TX. Note that
|
||||
to connect the pyboard to a CAN bus you must use a CAN transceiver
|
||||
to convert the CAN logic signals from the pyboard to the correct
|
||||
voltage levels on the bus.
|
||||
|
||||
Note that this driver does not yet support filter configuration
|
||||
(it defaults to a single filter that lets through all messages),
|
||||
or bus timing configuration (except for setting the prescaler).
|
||||
|
||||
Example usage (works without anything connected)::
|
||||
|
||||
from pyb import CAN
|
||||
can = pyb.CAN(1, pyb.CAN.LOOPBACK)
|
||||
can.send('message!', 123) # send message to id 123
|
||||
can.recv(0) # receive message on FIFO 0
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.CAN(bus, ...)
|
||||
|
||||
Construct a CAN object on the given bus. ``bus`` can be 1-2, or 'YA' or 'YB'.
|
||||
With no additional parameters, the CAN object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
The physical pins of the CAN busses are:
|
||||
|
||||
- ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)``
|
||||
- ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)``
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: can.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8)
|
||||
|
||||
Initialise the CAN bus with the given parameters:
|
||||
|
||||
- ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
|
||||
|
||||
If ``extframe`` is True then the bus uses extended identifiers in the frames (29 bits).
|
||||
Otherwise it uses standard 11 bit identifiers.
|
||||
|
||||
.. method:: can.deinit()
|
||||
|
||||
Turn off the CAN bus.
|
||||
|
||||
.. method:: can.any(fifo)
|
||||
|
||||
Return ``True`` if any message waiting on the FIFO, else ``False``.
|
||||
|
||||
.. method:: can.recv(fifo, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``fifo`` is an integer, which is the FIFO to receive on
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: buffer of data bytes.
|
||||
|
||||
.. method:: can.send(send, addr, \*, timeout=5000)
|
||||
|
||||
Send a message on the bus:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``addr`` is the address to send to
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send.
|
||||
|
||||
Return value: ``None``.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: CAN.NORMAL
|
||||
.. data:: CAN.LOOPBACK
|
||||
.. data:: CAN.SILENT
|
||||
.. data:: CAN.SILENT_LOOPBACK
|
||||
|
||||
the mode of the CAN bus
|
||||
69
docs/library/pyb.DAC.rst
Normal file
@@ -0,0 +1,69 @@
|
||||
.. _pyb.DAC:
|
||||
|
||||
class DAC -- digital to analog conversion
|
||||
=========================================
|
||||
|
||||
The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6.
|
||||
The voltage will be between 0 and 3.3V.
|
||||
|
||||
*This module will undergo changes to the API.*
|
||||
|
||||
Example usage::
|
||||
|
||||
from pyb import DAC
|
||||
|
||||
dac = DAC(1) # create DAC 1 on pin X5
|
||||
dac.write(128) # write a value to the DAC (makes X5 1.65V)
|
||||
|
||||
To output a continuous sine-wave::
|
||||
|
||||
import math
|
||||
from pyb import DAC
|
||||
|
||||
# create a buffer containing a sine-wave
|
||||
buf = bytearray(100)
|
||||
for i in range(len(buf)):
|
||||
buf[i] = 128 + int(127 \* math.sin(2 \* math.pi \* i / len(buf)))
|
||||
|
||||
# output the sine-wave at 400Hz
|
||||
dac = DAC(1)
|
||||
dac.write_timed(buf, 400 \* len(buf), mode=DAC.CIRCULAR)
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.DAC(port)
|
||||
|
||||
Construct a new DAC object.
|
||||
|
||||
``port`` can be a pin object, or an integer (1 or 2).
|
||||
DAC(1) is on pin X5 and DAC(2) is on pin X6.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: dac.noise(freq)
|
||||
|
||||
Generate a pseudo-random noise signal. A new random sample is written
|
||||
to the DAC output at the given frequency.
|
||||
|
||||
.. method:: dac.triangle(freq)
|
||||
|
||||
Generate a triangle wave. The value on the DAC output changes at
|
||||
the given frequency, and the frequence of the repeating triangle wave
|
||||
itself is 256 (or 1024, need to check) times smaller.
|
||||
|
||||
.. method:: dac.write(value)
|
||||
|
||||
Direct access to the DAC output (8 bit only at the moment).
|
||||
|
||||
.. method:: dac.write_timed(data, freq, \*, mode=DAC.NORMAL)
|
||||
|
||||
Initiates a burst of RAM to DAC using a DMA transfer.
|
||||
The input data is treated as an array of bytes (8 bit data).
|
||||
|
||||
``mode`` can be ``DAC.NORMAL`` or ``DAC.CIRCULAR``.
|
||||
|
||||
TIM6 is used to control the frequency of the transfer.
|
||||
113
docs/library/pyb.ExtInt.rst
Normal file
@@ -0,0 +1,113 @@
|
||||
.. _pyb.ExtInt:
|
||||
|
||||
class ExtInt -- configure I/O pins to interrupt on external events
|
||||
==================================================================
|
||||
|
||||
There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
|
||||
and the remaining 6 are from internal sources.
|
||||
|
||||
For lines 0 thru 15, a given line can map to the corresponding line from an
|
||||
arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
|
||||
line 1 can map to Px1 where x is A, B, C, ... ::
|
||||
|
||||
def callback(line):
|
||||
print("line =", line)
|
||||
|
||||
Note: ExtInt will automatically configure the gpio line as an input. ::
|
||||
|
||||
extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
|
||||
|
||||
Now every time a falling edge is seen on the X1 pin, the callback will be
|
||||
called. Caution: mechanical pushbuttons have "bounce" and pushing or
|
||||
releasing a switch will often generate multiple edges.
|
||||
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
|
||||
explanation, along with various techniques for debouncing.
|
||||
|
||||
Trying to register 2 callbacks onto the same pin will throw an exception.
|
||||
|
||||
If pin is passed as an integer, then it is assumed to map to one of the
|
||||
internal interrupt sources, and must be in the range 16 thru 22.
|
||||
|
||||
All other pin objects go through the pin mapper to come up with one of the
|
||||
gpio pins. ::
|
||||
|
||||
extint = pyb.ExtInt(pin, mode, pull, callback)
|
||||
|
||||
Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING,
|
||||
pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING,
|
||||
pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING.
|
||||
|
||||
Only the IRQ_xxx modes have been tested. The EVT_xxx modes have
|
||||
something to do with sleep mode and the WFE instruction.
|
||||
|
||||
Valid pull values are pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN, pyb.Pin.PULL_NONE.
|
||||
|
||||
There is also a C API, so that drivers which require EXTI interrupt lines
|
||||
can also use this code. See extint.h for the available functions and
|
||||
usrsw.h for an example of using this.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.ExtInt(pin, mode, pull, callback)
|
||||
|
||||
Create an ExtInt object:
|
||||
|
||||
- ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name).
|
||||
- ``mode`` can be one of:
|
||||
- ``ExtInt.IRQ_RISING`` - trigger on a rising edge;
|
||||
- ``ExtInt.IRQ_FALLING`` - trigger on a falling edge;
|
||||
- ``ExtInt.IRQ_RISING_FALLING`` - trigger on a rising or falling edge.
|
||||
- ``pull`` can be one of:
|
||||
- ``pyb.Pin.PULL_NONE`` - no pull up or down resistors;
|
||||
- ``pyb.Pin.PULL_UP`` - enable the pull-up resistor;
|
||||
- ``pyb.Pin.PULL_DOWN`` - enable the pull-down resistor.
|
||||
- ``callback`` is the function to call when the interrupt triggers. The
|
||||
callback function must accept exactly 1 argument, which is the line that
|
||||
triggered the interrupt.
|
||||
|
||||
|
||||
Class methods
|
||||
-------------
|
||||
|
||||
.. method:: ExtInt.regs()
|
||||
|
||||
Dump the values of the EXTI registers.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: extint.disable()
|
||||
|
||||
Disable the interrupt associated with the ExtInt object.
|
||||
This could be useful for debouncing.
|
||||
|
||||
.. method:: extint.enable()
|
||||
|
||||
Enable a disabled interrupt.
|
||||
|
||||
.. method:: extint.line()
|
||||
|
||||
Return the line number that the pin is mapped to.
|
||||
|
||||
.. method:: extint.swint()
|
||||
|
||||
Trigger the callback from software.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: ExtInt.IRQ_FALLING
|
||||
|
||||
interrupt on a falling edge
|
||||
|
||||
.. data:: ExtInt.IRQ_RISING
|
||||
|
||||
interrupt on a rising edge
|
||||
|
||||
.. data:: ExtInt.IRQ_RISING_FALLING
|
||||
|
||||
interrupt on a rising or falling edge
|
||||
153
docs/library/pyb.I2C.rst
Normal file
@@ -0,0 +1,153 @@
|
||||
.. _pyb.I2C:
|
||||
|
||||
class I2C -- a two-wire serial protocol
|
||||
=======================================
|
||||
|
||||
I2C is a two-wire protocol for communicating between devices. At the physical
|
||||
level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
|
||||
|
||||
I2C objects are created attached to a specific bus. They can be initialised
|
||||
when created, or initialised later on::
|
||||
|
||||
from pyb import I2C
|
||||
|
||||
i2c = I2C(1) # create on bus 1
|
||||
i2c = I2C(1, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
|
||||
i2c.deinit() # turn off the peripheral
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
|
||||
Basic methods for slave are send and recv::
|
||||
|
||||
i2c.send('abc') # send 3 bytes
|
||||
i2c.send(0x42) # send a single byte, given by the number
|
||||
data = i2c.recv(3) # receive 3 bytes
|
||||
|
||||
To receive inplace, first create a bytearray::
|
||||
|
||||
data = bytearray(3) # create a buffer
|
||||
i2c.recv(data) # receive 3 bytes, writing them into data
|
||||
|
||||
You can specify a timeout (in ms)::
|
||||
|
||||
i2c.send(b'123', timeout=2000) # timout after 2 seconds
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
|
||||
i2c.send(b'456', addr=0x42) # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
|
||||
i2c.is_ready(0x42) # check if slave 0x42 is ready
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.mem_write('abc', 0x42, 2, timeout=1000)
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.I2C(bus, ...)
|
||||
|
||||
Construct an I2C object on the given bus. ``bus`` can be 1 or 2.
|
||||
With no additional parameters, the I2C object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
The physical pins of the I2C busses are:
|
||||
|
||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: i2c.deinit()
|
||||
|
||||
Turn off the I2C bus.
|
||||
|
||||
.. method:: i2c.init(mode, \*, addr=0x12, baudrate=400000, gencall=False)
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
- ``mode`` must be either ``I2C.MASTER`` or ``I2C.SLAVE``
|
||||
- ``addr`` is the 7-bit address (only sensible for a slave)
|
||||
- ``baudrate`` is the SCL clock rate (only sensible for a master)
|
||||
- ``gencall`` is whether to support general call mode
|
||||
|
||||
.. method:: i2c.is_ready(addr)
|
||||
|
||||
Check if an I2C device responds to the given address. Only valid when in master mode.
|
||||
|
||||
.. method:: i2c.mem_read(data, addr, memaddr, timeout=5000, addr_size=8)
|
||||
|
||||
Read from the memory of an I2C device:
|
||||
|
||||
- ``data`` can be an integer or a buffer to read into
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the read
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
|
||||
Returns the read data.
|
||||
This is only valid in master mode.
|
||||
|
||||
.. method:: i2c.mem_write(data, addr, memaddr, timeout=5000, addr_size=8)
|
||||
|
||||
Write to the memory of an I2C device:
|
||||
|
||||
- ``data`` can be an integer or a buffer to write from
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the write
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
|
||||
Returns ``None``.
|
||||
This is only valid in master mode.
|
||||
|
||||
.. method:: i2c.recv(recv, addr=0x00, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``recv`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes
|
||||
- ``addr`` is the address to receive from (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive
|
||||
|
||||
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
|
||||
.. method:: i2c.scan()
|
||||
|
||||
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
|
||||
Only valid when in master mode.
|
||||
|
||||
.. method:: i2c.send(send, addr=0x00, timeout=5000)
|
||||
|
||||
Send data on the bus:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object)
|
||||
- ``addr`` is the address to send to (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send
|
||||
|
||||
Return value: ``None``.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: I2C.MASTER
|
||||
|
||||
for initialising the bus to master mode
|
||||
|
||||
.. data:: I2C.SLAVE
|
||||
|
||||
for initialising the bus to slave mode
|
||||
94
docs/library/pyb.LCD.rst
Normal file
@@ -0,0 +1,94 @@
|
||||
class LCD -- LCD control for the LCD touch-sensor pyskin
|
||||
========================================================
|
||||
|
||||
The LCD class is used to control the LCD on the LCD touch-sensor pyskin,
|
||||
LCD32MKv1.0. The LCD is a 128x32 pixel monochrome screen, part NHD-C12832A1Z.
|
||||
|
||||
The pyskin must be connected in either the X or Y positions, and then
|
||||
an LCD object is made using::
|
||||
|
||||
lcd = pyb.LCD('X') # if pyskin is in the X position
|
||||
lcd = pyb.LCD('Y') # if pyskin is in the Y position
|
||||
|
||||
Then you can use::
|
||||
|
||||
lcd.light(True) # turn the backlight on
|
||||
lcd.write('Hello world!\n') # print text to the screen
|
||||
|
||||
This driver implements a double buffer for setting/getting pixels.
|
||||
For example, to make a bouncing dot, try::
|
||||
|
||||
x = y = 0
|
||||
dx = dy = 1
|
||||
while True:
|
||||
# update the dot's position
|
||||
x += dx
|
||||
y += dy
|
||||
|
||||
# make the dot bounce of the edges of the screen
|
||||
if x <= 0 or x >= 127: dx = -dx
|
||||
if y <= 0 or y >= 31: dy = -dy
|
||||
|
||||
lcd.fill(0) # clear the buffer
|
||||
lcd.pixel(x, y, 1) # draw the dot
|
||||
lcd.show() # show the buffer
|
||||
pyb.delay(50) # pause for 50ms
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.LCD(skin_position)
|
||||
|
||||
Construct an LCD object in the given skin position. ``skin_position`` can be 'X' or 'Y', and
|
||||
should match the position where the LCD pyskin is plugged in.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: lcd.command(instr_data, buf)
|
||||
|
||||
Send an arbitrary command to the LCD. Pass 0 for ``instr_data`` to send an
|
||||
instruction, otherwise pass 1 to send data. ``buf`` is a buffer with the
|
||||
instructions/data to send.
|
||||
|
||||
.. method:: lcd.contrast(value)
|
||||
|
||||
Set the contrast of the LCD. Valid values are between 0 and 47.
|
||||
|
||||
.. method:: lcd.fill(colour)
|
||||
|
||||
Fill the screen with the given colour (0 or 1 for white or black).
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: lcd.get(x, y)
|
||||
|
||||
Get the pixel at the position ``(x, y)``. Returns 0 or 1.
|
||||
|
||||
This method reads from the visible buffer.
|
||||
|
||||
.. method:: lcd.light(value)
|
||||
|
||||
Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off.
|
||||
|
||||
.. method:: lcd.pixel(x, y, colour)
|
||||
|
||||
Set the pixel at ``(x, y)`` to the given colour (0 or 1).
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: lcd.show()
|
||||
|
||||
Show the hidden buffer on the screen.
|
||||
|
||||
.. method:: lcd.text(str, x, y, colour)
|
||||
|
||||
Draw the given text to the position ``(x, y)`` using the given colour (0 or 1).
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: lcd.write(str)
|
||||
|
||||
Write the string ``str`` to the screen. It will appear immediately.
|
||||
38
docs/library/pyb.LED.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
.. _pyb.LED:
|
||||
|
||||
class LED -- LED object
|
||||
=======================
|
||||
|
||||
The LED object controls an individual LED (Light Emitting Diode).
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.LED(id)
|
||||
|
||||
Create an LED object associated with the given LED:
|
||||
|
||||
- ``id`` is the LED number, 1-4.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: led.intensity([value])
|
||||
|
||||
Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on).
|
||||
If no argument is given, return the LED intensity.
|
||||
If an argument is given, set the LED intensity and return ``None``.
|
||||
|
||||
.. method:: led.off()
|
||||
|
||||
Turn the LED off.
|
||||
|
||||
.. method:: led.on()
|
||||
|
||||
Turn the LED on.
|
||||
|
||||
.. method:: led.toggle()
|
||||
|
||||
Toggle the LED between on and off.
|
||||
266
docs/library/pyb.Pin.rst
Normal file
@@ -0,0 +1,266 @@
|
||||
.. _pyb.Pin:
|
||||
|
||||
class Pin -- control I/O pins
|
||||
=============================
|
||||
|
||||
A pin is the basic object to control I/O pins. It has methods to set
|
||||
the mode of the pin (input, output, etc) and methods to get and set the
|
||||
digital logic level. For analog control of a pin, see the ADC class.
|
||||
|
||||
Usage Model:
|
||||
|
||||
All Board Pins are predefined as pyb.Pin.board.Name ::
|
||||
|
||||
x1_pin = pyb.Pin.board.X1
|
||||
|
||||
g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
|
||||
|
||||
CPU pins which correspond to the board pins are available
|
||||
as ``pyb.cpu.Name``. For the CPU pins, the names are the port letter
|
||||
followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and
|
||||
``pyb.Pin.cpu.B6`` are the same pin.
|
||||
|
||||
You can also use strings::
|
||||
|
||||
g = pyb.Pin('X1', pyb.Pin.OUT_PP)
|
||||
|
||||
Users can add their own names::
|
||||
|
||||
MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 }
|
||||
pyb.Pin.dict(MyMapperDict)
|
||||
g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
|
||||
|
||||
and can query mappings ::
|
||||
|
||||
pin = pyb.Pin("LeftMotorDir")
|
||||
|
||||
Users can also add their own mapping function::
|
||||
|
||||
def MyMapper(pin_name):
|
||||
if pin_name == "LeftMotorDir":
|
||||
return pyb.Pin.cpu.A0
|
||||
|
||||
pyb.Pin.mapper(MyMapper)
|
||||
|
||||
So, if you were to call: ``pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)``
|
||||
then ``"LeftMotorDir"`` is passed directly to the mapper function.
|
||||
|
||||
To summarise, the following order determines how things get mapped into
|
||||
an ordinal pin number:
|
||||
|
||||
1. Directly specify a pin object
|
||||
2. User supplied mapping function
|
||||
3. User supplied mapping (object must be usable as a dictionary key)
|
||||
4. Supply a string which matches a board pin
|
||||
5. Supply a string which matches a CPU port/pin
|
||||
|
||||
You can set ``pyb.Pin.debug(True)`` to get some debug information about
|
||||
how a particular object gets mapped to a pin.
|
||||
|
||||
When a pin has the ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` pull-mode enabled,
|
||||
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
|
||||
respectively (except pin Y5 which has 11k Ohm resistors).
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Pin(id, ...)
|
||||
|
||||
Create a new Pin object associated with the id. If additional arguments are given,
|
||||
they are used to initialise the pin. See :meth:`pin.init`.
|
||||
|
||||
|
||||
Class methods
|
||||
-------------
|
||||
|
||||
.. method:: Pin.af_list()
|
||||
|
||||
Returns an array of alternate functions available for this pin.
|
||||
|
||||
.. method:: Pin.debug([state])
|
||||
|
||||
Get or set the debugging state (``True`` or ``False`` for on or off).
|
||||
|
||||
.. method:: Pin.dict([dict])
|
||||
|
||||
Get or set the pin mapper dictionary.
|
||||
|
||||
.. method:: Pin.mapper([fun])
|
||||
|
||||
Get or set the pin mapper function.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: pin.init(mode, pull=Pin.PULL_NONE, af=-1)
|
||||
|
||||
Initialise the pin:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
- ``Pin.IN`` - configure the pin for input;
|
||||
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
|
||||
- ``Pin.OUT_OD`` - configure the pin for output, with open-drain control;
|
||||
- ``Pin.AF_PP`` - configure the pin for alternate function, pull-pull;
|
||||
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
|
||||
- ``Pin.ANALOG`` - configure the pin for analog.
|
||||
- ``pull`` can be one of:
|
||||
- ``Pin.PULL_NONE`` - no pull up or down resistors;
|
||||
- ``Pin.PULL_UP`` - enable the pull-up resistor;
|
||||
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
|
||||
- when mode is Pin.AF_PP or Pin.AF_OD, then af can be the index or name
|
||||
of one of the alternate functions associated with a pin.
|
||||
|
||||
Returns: ``None``.
|
||||
|
||||
.. method:: pin.high()
|
||||
|
||||
Set the pin to a high logic level.
|
||||
|
||||
.. method:: pin.low()
|
||||
|
||||
Set the pin to a low logic level.
|
||||
|
||||
.. method:: pin.value([value])
|
||||
|
||||
Get or set the digital logic level of the pin:
|
||||
|
||||
- With no argument, return 0 or 1 depending on the logic level of the pin.
|
||||
- With ``value`` given, set the logic level of the pin. ``value`` can be
|
||||
anything that converts to a boolean. If it converts to ``True``, the pin
|
||||
is set high, otherwise it is set low.
|
||||
|
||||
.. method:: pin.__str__()
|
||||
|
||||
Return a string describing the pin object.
|
||||
|
||||
.. method:: pin.af()
|
||||
|
||||
Returns the currently configured alternate-function of the pin. The
|
||||
integer returned will match one of the allowed constants for the af
|
||||
argument to the init function.
|
||||
|
||||
.. method:: pin.gpio()
|
||||
|
||||
Returns the base address of the GPIO block associated with this pin.
|
||||
|
||||
.. method:: pin.mode()
|
||||
|
||||
Returns the currently configured mode of the pin. The integer returned
|
||||
will match one of the allowed constants for the mode argument to the init
|
||||
function.
|
||||
|
||||
.. method:: pin.name()
|
||||
|
||||
Get the pin name.
|
||||
|
||||
.. method:: pin.names()
|
||||
|
||||
Returns the cpu and board names for this pin.
|
||||
|
||||
.. method:: pin.pin()
|
||||
|
||||
Get the pin number.
|
||||
|
||||
.. method:: pin.port()
|
||||
|
||||
Get the pin port.
|
||||
|
||||
.. method:: pin.pull()
|
||||
|
||||
Returns the currently configured pull of the pin. The integer returned
|
||||
will match one of the allowed constants for the pull argument to the init
|
||||
function.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: Pin.AF_OD
|
||||
|
||||
initialise the pin to alternate-function mode with an open-drain drive
|
||||
|
||||
.. data:: Pin.AF_PP
|
||||
|
||||
initialise the pin to alternate-function mode with a push-pull drive
|
||||
|
||||
.. data:: Pin.ANALOG
|
||||
|
||||
initialise the pin to analog mode
|
||||
|
||||
.. data:: Pin.IN
|
||||
|
||||
initialise the pin to input mode
|
||||
|
||||
.. data:: Pin.OUT_OD
|
||||
|
||||
initialise the pin to output mode with an open-drain drive
|
||||
|
||||
.. data:: Pin.OUT_PP
|
||||
|
||||
initialise the pin to output mode with a push-pull drive
|
||||
|
||||
.. data:: Pin.PULL_DOWN
|
||||
|
||||
enable the pull-down resistor on the pin
|
||||
|
||||
.. data:: Pin.PULL_NONE
|
||||
|
||||
don't enable any pull up or down resistors on the pin
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
|
||||
enable the pull-up resistor on the pin
|
||||
|
||||
|
||||
class PinAF -- Pin Alternate Functions
|
||||
======================================
|
||||
|
||||
A Pin represents a physical pin on the microcprocessor. Each pin
|
||||
can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF
|
||||
object represents a particular function for a pin.
|
||||
|
||||
Usage Model::
|
||||
|
||||
x3 = pyb.Pin.board.X3
|
||||
x3_af = x3.af_list()
|
||||
|
||||
x3_af will now contain an array of PinAF objects which are availble on
|
||||
pin X3.
|
||||
|
||||
For the pyboard, x3_af would contain:
|
||||
[Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2]
|
||||
|
||||
Normally, each peripheral would configure the af automatically, but sometimes
|
||||
the same function is available on multiple pins, and having more control
|
||||
is desired.
|
||||
|
||||
To configure X3 to expose TIM2_CH3, you could use::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
|
||||
|
||||
or::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1)
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: pinaf.__str__()
|
||||
|
||||
Return a string describing the alternate function.
|
||||
|
||||
.. method:: pinaf.index()
|
||||
|
||||
Return the alternate function index.
|
||||
|
||||
.. method:: pinaf.name()
|
||||
|
||||
Return the name of the alternate function.
|
||||
|
||||
.. method:: pinaf.reg()
|
||||
|
||||
Return the base register associated with the peripheral assigned to this
|
||||
alternate function. For example, if the alternate function were TIM2_CH3
|
||||
this would return stm.TIM2
|
||||
48
docs/library/pyb.RTC.rst
Normal file
@@ -0,0 +1,48 @@
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
||||
The RTC is and independent clock that keeps track of the date
|
||||
and time.
|
||||
|
||||
Example usage::
|
||||
|
||||
rtc = pyb.RTC()
|
||||
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
|
||||
print(rtc.datetime())
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.RTC()
|
||||
|
||||
Create an RTC object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: rtc.datetime([datetimetuple])
|
||||
|
||||
Get or set the date and time of the RTC.
|
||||
|
||||
With no arguments, this method returns an 8-tuple with the current
|
||||
date and time. With 1 argument (being an 8-tuple) it sets the date
|
||||
and time.
|
||||
|
||||
The 8-tuple has the following format:
|
||||
|
||||
(year, month, day, weekday, hours, minutes, seconds, subseconds)
|
||||
|
||||
``weekday`` is 1-7 for Monday through Sunday.
|
||||
|
||||
``subseconds`` counts down from 255 to 0
|
||||
|
||||
.. method:: rtc.info()
|
||||
|
||||
Get information about the startup time and reset source.
|
||||
|
||||
- The lower 0xffff are the number of milliseconds the RTC took to
|
||||
start up.
|
||||
- Bit 0x10000 is set if a power-on reset occurred.
|
||||
- Bit 0x20000 is set if an external reset occurred
|
||||
106
docs/library/pyb.SPI.rst
Normal file
@@ -0,0 +1,106 @@
|
||||
.. _pyb.SPI:
|
||||
|
||||
class SPI -- a master-driven serial protocol
|
||||
============================================
|
||||
|
||||
SPI is a serial protocol that is driven by a master. At the physical level
|
||||
there are 3 lines: SCK, MOSI, MISO.
|
||||
|
||||
See usage model of I2C; SPI is very similar. Main difference is
|
||||
parameters to init the SPI bus::
|
||||
|
||||
from pyb import SPI
|
||||
spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
|
||||
|
||||
Only required parameter is mode, SPI.MASTER or SPI.SLAVE. Polarity can be
|
||||
0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
|
||||
to sample data on the first or second clock edge respectively. Crc can be
|
||||
None for no CRC, or a polynomial specifier.
|
||||
|
||||
Additional method for SPI::
|
||||
|
||||
data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
|
||||
buf = bytearray(4)
|
||||
spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
|
||||
spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.SPI(bus, ...)
|
||||
|
||||
Construct an SPI object on the given bus. ``bus`` can be 1 or 2.
|
||||
With no additional parameters, the SPI object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
The physical pins of the SPI busses are:
|
||||
|
||||
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
|
||||
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
|
||||
|
||||
At the moment, the NSS pin is not used by the SPI driver and is free
|
||||
for other use.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: spi.deinit()
|
||||
|
||||
Turn off the SPI bus.
|
||||
|
||||
.. method:: spi.init(mode, baudrate=328125, \*, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
|
||||
|
||||
Initialise the SPI bus with the given parameters:
|
||||
|
||||
- ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``.
|
||||
- ``baudrate`` is the SCK clock rate (only sensible for a master).
|
||||
|
||||
.. method:: spi.recv(recv, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``recv`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
|
||||
.. method:: spi.send(send, \*, timeout=5000)
|
||||
|
||||
Send data on the bus:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send.
|
||||
|
||||
Return value: ``None``.
|
||||
|
||||
.. method:: spi.send_recv(send, recv=None, \*, timeout=5000)
|
||||
|
||||
Send and receive data on the bus at the same time:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``recv`` is a mutable buffer which will be filled with received bytes.
|
||||
It can be the same as ``send``, or omitted. If omitted, a new buffer will
|
||||
be created.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: the buffer with the received bytes.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: SPI.MASTER
|
||||
.. data:: SPI.SLAVE
|
||||
|
||||
for initialising the SPI bus to master or slave mode
|
||||
|
||||
.. data:: SPI.LSB
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the least or most significant bit
|
||||
38
docs/library/pyb.Servo.rst
Normal file
@@ -0,0 +1,38 @@
|
||||
class Servo -- 3-wire hobby servo driver
|
||||
========================================
|
||||
|
||||
Servo controls standard hobby servos with 3-wires (ground, power, signal).
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Servo(id)
|
||||
|
||||
Create a servo object. ``id`` is 1-4.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: servo.angle([angle, time=0])
|
||||
|
||||
Get or set the angle of the servo.
|
||||
|
||||
- ``angle`` is the angle to move to in degrees.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified angle.
|
||||
|
||||
.. method:: servo.calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]])
|
||||
|
||||
Get or set the calibration of the servo timing.
|
||||
|
||||
.. method:: servo.pulse_width([value])
|
||||
|
||||
Get or set the pulse width in milliseconds.
|
||||
|
||||
.. method:: servo.speed([speed, time=0])
|
||||
|
||||
Get or set the speed of a continuous rotation servo.
|
||||
|
||||
- ``speed`` is the speed to move to change to, between -100 and 100.
|
||||
- ``time`` is the number of milliseconds to take to get to the specified speed.
|
||||
37
docs/library/pyb.Switch.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
class Switch -- switch object
|
||||
=============================
|
||||
|
||||
A Switch object is used to control a push-button switch.
|
||||
|
||||
Usage::
|
||||
|
||||
sw = pyb.Switch() # create a switch object
|
||||
sw() # get state (True if pressed, False otherwise)
|
||||
sw.callback(f) # register a callback to be called when the
|
||||
# switch is pressed down
|
||||
sw.callback(None) # remove the callback
|
||||
|
||||
Example::
|
||||
|
||||
pyb.Switch().callback(lambda: pyb.LED(1).toggle())
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Switch()
|
||||
|
||||
Create and return a switch object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: switch()
|
||||
|
||||
Return the switch state: ``True`` if pressed down, ``False`` otherwise.
|
||||
|
||||
.. method:: switch.callback(fun)
|
||||
|
||||
Register the given function to be called when the switch is pressed down.
|
||||
If ``fun`` is ``None``, then it disables the callback.
|
||||
234
docs/library/pyb.Timer.rst
Normal file
@@ -0,0 +1,234 @@
|
||||
.. _pyb.Timer:
|
||||
|
||||
class Timer -- control internal timers
|
||||
======================================
|
||||
|
||||
Timers can be used for a great variety of tasks. At the moment, only
|
||||
the simplest case is implemented: that of calling a function periodically.
|
||||
|
||||
Each timer consists of a counter that counts up at a certain rate. The rate
|
||||
at which it counts is the peripheral clock frequency (in Hz) divided by the
|
||||
timer prescaler. When the counter reaches the timer period it triggers an
|
||||
event, and the counter resets back to zero. By using the callback method,
|
||||
the timer event can call a Python function.
|
||||
|
||||
Example usage to toggle an LED at a fixed frequency::
|
||||
|
||||
tim = pyb.Timer(4) # create a timer object using timer 4
|
||||
tim.init(freq=2) # trigger at 2Hz
|
||||
tim.callback(lambda t:pyb.LED(1).toggle())
|
||||
|
||||
Further examples::
|
||||
|
||||
tim = pyb.Timer(4, freq=100) # freq in Hz
|
||||
tim = pyb.Timer(4, prescaler=0, period=99)
|
||||
tim.counter() # get counter (can also set)
|
||||
tim.prescaler(2) # set prescaler (can also get)
|
||||
tim.period(199) # set period (can also get)
|
||||
tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
|
||||
tim.callback(None) # clear callback
|
||||
|
||||
*Note:* Timer 3 is reserved for internal use. Timer 5 controls
|
||||
the servo driver, and Timer 6 is used for timed ADC/DAC reading/writing.
|
||||
It is recommended to use the other timers in your programs.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Timer(id, ...)
|
||||
|
||||
Construct a new timer object of the given id. If additional
|
||||
arguments are given, then the timer is initialised by ``init(...)``.
|
||||
``id`` can be 1 to 14, excluding 3.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: timer.callback(fun)
|
||||
|
||||
Set the function to be called when the timer triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
|
||||
.. method:: timer.channel(channel, mode, ...)
|
||||
|
||||
If only a channel number is passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
Othwerwise, a TimerChannel object is initialized and returned.
|
||||
|
||||
Each channel can be configured to perform pwm, output compare, or
|
||||
input capture. All channels share the same underlying timer, which means
|
||||
that they share the same timer clock.
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
|
||||
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
|
||||
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
|
||||
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
|
||||
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
|
||||
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
|
||||
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
|
||||
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
|
||||
- ``Timer.IC`` --- configure the timer in Input Capture mode.
|
||||
|
||||
- ``callback`` - as per TimerChannel.callback()
|
||||
|
||||
- ``pin`` None (the default) or a Pin object. If specified (and not None)
|
||||
this will cause the alternate function of the the indicated pin
|
||||
to be configured for this timer channel. An error will be raised if
|
||||
the pin doesn't support any alternate functions for this timer channel.
|
||||
|
||||
Keyword arguments for Timer.PWM modes:
|
||||
|
||||
- ``pulse_width`` - determines the initial pulse width value to use.
|
||||
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
|
||||
|
||||
Keyword arguments for Timer.OC modes:
|
||||
|
||||
- ``compare`` - determines the initial value of the compare register.
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
- ``Timer.HIGH`` - output is active high
|
||||
- ``Timer.LOW`` - output is acive low
|
||||
|
||||
Optional keyword arguments for Timer.IC modes:
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
- ``Timer.RISING`` - captures on rising edge.
|
||||
- ``Timer.FALLING`` - captures on falling edge.
|
||||
- ``Timer.BOTH`` - captures on both edges.
|
||||
|
||||
Note that capture only works on the primary channel, and not on the
|
||||
complimentary channels.
|
||||
|
||||
PWM Example::
|
||||
|
||||
timer = pyb.Timer(2, freq=1000)
|
||||
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=210000)
|
||||
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=420000)
|
||||
|
||||
.. method:: timer.counter([value])
|
||||
|
||||
Get or set the timer counter.
|
||||
|
||||
.. method:: timer.deinit()
|
||||
|
||||
Deinitialises the timer.
|
||||
|
||||
Disables the callback (and the associated irq).
|
||||
Disables any channel callbacks (and the associated irq).
|
||||
Stops the timer, and disables the timer peripheral.
|
||||
|
||||
.. method:: timer.freq([value])
|
||||
|
||||
Get or set the frequency for the timer (changes prescaler and period if set).
|
||||
|
||||
.. method:: timer.init(\*, freq, prescaler, period)
|
||||
|
||||
Initialise the timer. Initialisation must be either by frequency (in Hz)
|
||||
or by prescaler and period::
|
||||
|
||||
tim.init(freq=100) # set the timer to trigger at 100Hz
|
||||
tim.init(prescaler=83, period=999) # set the prescaler and period directly
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``freq`` --- specifies the periodic frequency of the timer. You migh also
|
||||
view this as the frequency with which the timer goes through one complete cycle.
|
||||
|
||||
- ``prescaler`` [0-0xffff] - specifies the value to be loaded into the
|
||||
timer's Prescaler Register (PSC). The timer clock source is divided by
|
||||
(``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14
|
||||
have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11
|
||||
have a clock source of 168 MHz (pyb.freq()[3] \* 2).
|
||||
|
||||
- ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
|
||||
Specifies the value to be loaded into the timer's AutoReload
|
||||
Register (ARR). This determines the period of the timer (i.e. when the
|
||||
counter cycles). The timer counter will roll-over after ``period + 1``
|
||||
timer clock cycles.
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Timer.UP`` - configures the timer to count from 0 to ARR (default)
|
||||
- ``Timer.DOWN`` - configures the timer to count from ARR down to 0.
|
||||
- ``Timer.CENTER`` - confgures the timer to count from 0 to ARR and
|
||||
then back down to 0.
|
||||
|
||||
- ``div`` can be one of 1, 2, or 4. Divides the timer clock to determine
|
||||
the sampling clock used by the digital filters.
|
||||
|
||||
- ``callback`` - as per Timer.callback()
|
||||
|
||||
- ``deadtime`` - specifies the amount of "dead" or inactive time between
|
||||
transitions on complimentary channels (both channels will be inactive)
|
||||
for this time). ``deadtime`` may be an integer between 0 and 1008, with
|
||||
the following restrictions: 0-128 in steps of 1. 128-256 in steps of
|
||||
2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadime``
|
||||
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
|
||||
``deadtime`` is only available on timers 1 and 8.
|
||||
|
||||
You must either specify freq or both of period and prescaler.
|
||||
|
||||
.. method:: timer.period([value])
|
||||
|
||||
Get or set the period of the timer.
|
||||
|
||||
.. method:: timer.prescaler([value])
|
||||
|
||||
Get or set the prescaler for the timer.
|
||||
|
||||
.. method:: timer.source_freq()
|
||||
|
||||
Get the frequency of the source of the timer.
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
|
||||
Timer channels are used to generate/capture a signal using a timer.
|
||||
|
||||
TimerChannel objects are created using the Timer.channel() method.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: timerchannel.callback(fun)
|
||||
|
||||
Set the function to be called when the timer channel triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
|
||||
.. method:: timerchannel.capture([value])
|
||||
|
||||
Get or set the capture value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
capture is the logical name to use when the channel is in input capture mode.
|
||||
|
||||
.. method:: timerchannel.compare([value])
|
||||
|
||||
Get or set the compare value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
compare is the logical name to use when the channel is in output compare mode.
|
||||
|
||||
.. method:: timerchannel.pulse_width([value])
|
||||
|
||||
Get or set the pulse width value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
pulse_width is the logical name to use when the channel is in PWM mode.
|
||||
|
||||
In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100%
|
||||
In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100%
|
||||
|
||||
.. method:: timerchannel.pulse_width_percent([value])
|
||||
|
||||
Get or set the pulse width percentage associated with a channel. The value
|
||||
is a number between 0 and 100 and sets the percentage of the timer period
|
||||
for which the pulse is active. The value can be an integer or
|
||||
floating-point number for more accuracy. For example, a value of 25 gives
|
||||
a duty cycle of 25%.
|
||||
136
docs/library/pyb.UART.rst
Normal file
@@ -0,0 +1,136 @@
|
||||
.. _pyb.UART:
|
||||
|
||||
class UART -- duplex serial communication bus
|
||||
=============================================
|
||||
|
||||
UART implements the standard UART/USART duplex serial communications protocol. At
|
||||
the physical level it consists of 2 lines: RX and TX. The unit of communication
|
||||
is a character (not to be confused with a string character) which can be 8 or 9
|
||||
bits wide.
|
||||
|
||||
UART objects can be created and initialised using::
|
||||
|
||||
from pyb import UART
|
||||
|
||||
uart = UART(1, 9600) # init with given baudrate
|
||||
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
|
||||
|
||||
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
A UART object acts like a stream object and reading and writing is done
|
||||
using the standard stream methods::
|
||||
|
||||
uart.read(10) # read 10 characters, returns a bytes object
|
||||
uart.readall() # read all available characters
|
||||
uart.readline() # read a line
|
||||
uart.readinto(buf) # read and store into the given buffer
|
||||
uart.write('abc') # write the 3 characters
|
||||
|
||||
Individual characters can be read/written using::
|
||||
|
||||
uart.readchar() # read 1 character and returns it as an integer
|
||||
uart.writechar(42) # write 1 character
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns True if any characters waiting
|
||||
|
||||
*Note:* The stream functions ``read``, ``write`` etc Are new in Micro Python since v1.3.4.
|
||||
Earlier versions use ``uart.send`` and ``uart.recv``.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.UART(bus, ...)
|
||||
|
||||
Construct a UART object on the given bus. ``bus`` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
|
||||
With no additional parameters, the UART object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
The physical pins of the UART busses are:
|
||||
|
||||
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
||||
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
|
||||
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: uart.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, timeout_char=0, read_buf_len=64)
|
||||
|
||||
Initialise the UART bus with the given parameters:
|
||||
|
||||
- ``baudrate`` is the clock rate.
|
||||
- ``bits`` is the number of bits per character, 7, 8 or 9.
|
||||
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- ``stop`` is the number of stop bits, 1 or 2.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the first character.
|
||||
- ``timeout_char`` is the timeout in milliseconds to wait between characters.
|
||||
- ``read_buf_len`` is the character length of the read buffer (0 to disable).
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
.. method:: uart.deinit()
|
||||
|
||||
Turn off the UART bus.
|
||||
|
||||
.. method:: uart.any()
|
||||
|
||||
Return ``True`` if any characters waiting, else ``False``.
|
||||
|
||||
.. method:: uart.read([nbytes])
|
||||
|
||||
Read characters. If ``nbytes`` is specified then read at most that many bytes.
|
||||
|
||||
*Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must
|
||||
be even, and the number of characters is ``nbytes/2``.
|
||||
|
||||
Return value: a bytes object containing the bytes read in. Returns ``b''``
|
||||
on timeout.
|
||||
|
||||
.. method:: uart.readall()
|
||||
|
||||
Read as much data as possible.
|
||||
|
||||
Return value: a bytes object.
|
||||
|
||||
.. method:: uart.readchar()
|
||||
|
||||
Receive a single character on the bus.
|
||||
|
||||
Return value: The character read, as an integer. Returns -1 on timeout.
|
||||
|
||||
.. method:: uart.readinto(buf[, nbytes])
|
||||
|
||||
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
|
||||
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
|
||||
|
||||
Return value: number of bytes read and stored into ``buf``.
|
||||
|
||||
.. method:: uart.readline()
|
||||
|
||||
Read a line, ending in a newline character.
|
||||
|
||||
Return value: the line read.
|
||||
|
||||
.. method:: uart.write(buf)
|
||||
|
||||
Write the buffer of bytes to the bus. If characters are 7 or 8 bits wide
|
||||
then each byte is one character. If characters are 9 bits wide then two
|
||||
bytes are used for each character (little endian), and ``buf`` must contain
|
||||
an even number of bytes.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
.. method:: uart.writechar(char)
|
||||
|
||||
Write a single character on the bus. ``char`` is an integer to write.
|
||||
Return value: ``None``.
|
||||
57
docs/library/pyb.USB_VCP.rst
Normal file
@@ -0,0 +1,57 @@
|
||||
class USB_VCP -- USB virtual comm port
|
||||
======================================
|
||||
|
||||
The USB_VCP class allows creation of an object representing the USB
|
||||
virtual comm port. It can be used to read and write data over USB to
|
||||
the connected host.
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.USB_VCP()
|
||||
|
||||
Create a new USB_VCP object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: usb_vcp.any()
|
||||
|
||||
Return ``True`` if any characters waiting, else ``False``.
|
||||
|
||||
.. method:: usb_vcp.close()
|
||||
|
||||
|
||||
.. method:: usb_vcp.read([nbytes])
|
||||
|
||||
|
||||
.. method:: usb_vcp.readall()
|
||||
|
||||
|
||||
.. method:: usb_vcp.readline()
|
||||
|
||||
|
||||
.. method:: usb_vcp.recv(data, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``data`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: if ``data`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the number of bytes read into ``data`` is returned.
|
||||
|
||||
.. method:: usb_vcp.send(data, \*, timeout=5000)
|
||||
|
||||
Send data over the USB VCP:
|
||||
|
||||
- ``data`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send.
|
||||
|
||||
Return value: number of bytes sent.
|
||||
|
||||
.. method:: usb_vcp.write(buf)
|
||||
|
||||
182
docs/library/pyb.rst
Normal file
@@ -0,0 +1,182 @@
|
||||
:mod:`pyb` --- functions related to the pyboard
|
||||
===============================================
|
||||
|
||||
.. module:: pyb
|
||||
:synopsis: functions related to the pyboard
|
||||
|
||||
The ``pyb`` module contains specific functions related to the pyboard.
|
||||
|
||||
Time related functions
|
||||
----------------------
|
||||
|
||||
.. function:: delay(ms)
|
||||
|
||||
Delay for the given number of milliseconds.
|
||||
|
||||
.. function:: udelay(us)
|
||||
|
||||
Delay for the given number of microseconds.
|
||||
|
||||
.. function:: millis()
|
||||
|
||||
Returns the number of milliseconds since the board was last reset.
|
||||
|
||||
The result is always a micropython smallint (31-bit signed number), so
|
||||
after 2^30 milliseconds (about 12.4 days) this will start to return
|
||||
negative numbers.
|
||||
|
||||
.. function:: micros()
|
||||
|
||||
Returns the number of microseconds since the board was last reset.
|
||||
|
||||
The result is always a micropython smallint (31-bit signed number), so
|
||||
after 2^30 microseconds (about 17.8 minutes) this will start to return
|
||||
negative numbers.
|
||||
|
||||
.. function:: elapsed_millis(start)
|
||||
|
||||
Returns the number of milliseconds which have elapsed since ``start``.
|
||||
|
||||
This function takes care of counter wrap, and always returns a positive
|
||||
number. This means it can be used to measure periods upto about 12.4 days.
|
||||
|
||||
Example::
|
||||
|
||||
start = pyb.millis()
|
||||
while pyb.elapsed_millis(start) < 1000:
|
||||
# Perform some operation
|
||||
|
||||
.. function:: elapsed_micros(start)
|
||||
|
||||
Returns the number of microseconds which have elapsed since ``start``.
|
||||
|
||||
This function takes care of counter wrap, and always returns a positive
|
||||
number. This means it can be used to measure periods upto about 17.8 minutes.
|
||||
|
||||
Example::
|
||||
|
||||
start = pyb.micros()
|
||||
while pyb.elapsed_micros(start) < 1000:
|
||||
# Perform some operation
|
||||
pass
|
||||
|
||||
Reset related functions
|
||||
-----------------------
|
||||
|
||||
.. function:: hard_reset()
|
||||
|
||||
Resets the pyboard in a manner similar to pushing the external RESET
|
||||
button.
|
||||
|
||||
.. function:: bootloader()
|
||||
|
||||
Activate the bootloader without BOOT\* pins.
|
||||
|
||||
Interrupt related functions
|
||||
---------------------------
|
||||
|
||||
.. function:: disable_irq()
|
||||
|
||||
Disable interrupt requests.
|
||||
Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs
|
||||
respectively. This return value can be passed to enable_irq to restore
|
||||
the IRQ to its original state.
|
||||
|
||||
.. function:: enable_irq(state=True)
|
||||
|
||||
Enable interrupt requests.
|
||||
If ``state`` is ``True`` (the default value) then IRQs are enabled.
|
||||
If ``state`` is ``False`` then IRQs are disabled. The most common use of
|
||||
this function is to pass it the value returned by ``disable_irq`` to
|
||||
exit a critical section.
|
||||
|
||||
Power related functions
|
||||
-----------------------
|
||||
|
||||
.. function:: freq([sys_freq])
|
||||
|
||||
If given no arguments, returns a tuple of clock frequencies:
|
||||
(SYSCLK, HCLK, PCLK1, PCLK2).
|
||||
|
||||
If given an argument, sets the system frequency to that value in Hz.
|
||||
Eg freq(120000000) gives 120MHz. Note that not all values are
|
||||
supported and the largest supported frequency not greater than
|
||||
the given sys_freq will be selected.
|
||||
|
||||
Supported frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
|
||||
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
|
||||
|
||||
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
|
||||
(internal oscillator) directly. The higher frequencies use the HSE to
|
||||
drive the PLL (phase locked loop), and then use the output of the PLL.
|
||||
|
||||
Note that if you change the frequency while the USB is enabled then
|
||||
the USB may become unreliable. It is best to change the frequency
|
||||
in boot.py, before the USB peripheral is started. Also note that
|
||||
frequencies below 36MHz do not allow the USB to function correctly.
|
||||
|
||||
.. function:: wfi()
|
||||
|
||||
Wait for an interrupt.
|
||||
This executies a ``wfi`` instruction which reduces power consumption
|
||||
of the MCU until an interrupt occurs, at which point execution continues.
|
||||
|
||||
.. function:: standby()
|
||||
|
||||
|
||||
.. function:: stop()
|
||||
|
||||
Miscellaneous functions
|
||||
-----------------------
|
||||
|
||||
.. function:: have_cdc()
|
||||
|
||||
Return True if USB is connected as a serial device, False otherwise.
|
||||
|
||||
.. function:: hid((buttons, x, y, z))
|
||||
|
||||
Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
|
||||
signal a HID mouse-motion event.
|
||||
|
||||
.. function:: info([dump_alloc_table])
|
||||
|
||||
Print out lots of information about the board.
|
||||
|
||||
.. function:: repl_uart(uart)
|
||||
|
||||
Get or set the UART object that the REPL is repeated on.
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 30-bit hardware generated random number.
|
||||
|
||||
.. function:: sync()
|
||||
|
||||
Sync all file systems.
|
||||
|
||||
.. function:: unique_id()
|
||||
|
||||
Returns a string of 12 bytes (96 bits), which is the unique ID for the MCU.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
pyb.Accel.rst
|
||||
pyb.ADC.rst
|
||||
pyb.CAN.rst
|
||||
pyb.DAC.rst
|
||||
pyb.ExtInt.rst
|
||||
pyb.I2C.rst
|
||||
pyb.LCD.rst
|
||||
pyb.LED.rst
|
||||
pyb.Pin.rst
|
||||
pyb.RTC.rst
|
||||
pyb.Servo.rst
|
||||
pyb.SPI.rst
|
||||
pyb.Switch.rst
|
||||
pyb.Timer.rst
|
||||
pyb.UART.rst
|
||||
pyb.USB_VCP.rst
|
||||
52
docs/library/select.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
:mod:`select` -- Provides select function to wait for events on a stream
|
||||
========================================================================
|
||||
|
||||
.. module:: select
|
||||
:synopsis: Provides select function to wait for events on a stream
|
||||
|
||||
This module provides the select function.
|
||||
|
||||
Pyboard specifics
|
||||
-----------------
|
||||
|
||||
Polling is an efficient way of waiting for read/write activity on multiple
|
||||
objects. Current objects that support polling are: :class:`pyb.UART`,
|
||||
:class:`pyb.USB_VCP`.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: poll()
|
||||
|
||||
Create an instance of the Poll class.
|
||||
|
||||
.. function:: select(rlist, wlist, xlist[, timeout])
|
||||
|
||||
Wait for activity on a set of objects.
|
||||
|
||||
.. _class: Poll
|
||||
|
||||
class ``Poll``
|
||||
--------------
|
||||
|
||||
Methods
|
||||
~~~~~~~
|
||||
|
||||
.. method:: poll.register(obj[, eventmask])
|
||||
|
||||
Register ``obj`` for polling. ``eventmask`` is 1 for read, 2 for
|
||||
write, 3 for read-write.
|
||||
|
||||
.. method:: poll.unregister(obj)
|
||||
|
||||
Unregister ``obj`` from polling.
|
||||
|
||||
.. method:: poll.modify(obj, eventmask)
|
||||
|
||||
Modify the ``eventmask`` for ``obj``.
|
||||
|
||||
.. method:: poll.poll([timeout])
|
||||
|
||||
Wait for one of the registered objects to become ready.
|
||||
|
||||
Timeout is in milliseconds.
|
||||
25
docs/library/struct.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
:mod:`struct` -- pack and unpack primitive data types
|
||||
=====================================================
|
||||
|
||||
.. module:: struct
|
||||
:synopsis: pack and unpack primitive data types
|
||||
|
||||
See `Python struct <https://docs.python.org/3/library/struct.html>`_ for more
|
||||
information.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: calcsize(fmt)
|
||||
|
||||
Return the number of bytes needed to store the given ``fmt``.
|
||||
|
||||
.. function:: pack(fmt, v1, v2, ...)
|
||||
|
||||
Pack the values ``v1``, ``v2``, ... according to the format string ``fmt``.
|
||||
The return value is a bytes object encoding the values.
|
||||
|
||||
.. function:: unpack(fmt, data)
|
||||
|
||||
Unpack from the ``data`` according to the format string ``fmt``.
|
||||
The return value is a tuple of the unpacked values.
|
||||
52
docs/library/sys.rst
Normal file
@@ -0,0 +1,52 @@
|
||||
:mod:`sys` -- system specific functions
|
||||
=======================================
|
||||
|
||||
.. module:: sys
|
||||
:synopsis: system specific functions
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: exit([retval])
|
||||
|
||||
Raise a ``SystemExit`` exception. If an argument is given, it is the
|
||||
value given to ``SystemExit``.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: argv
|
||||
|
||||
a mutable list of arguments this program started with
|
||||
|
||||
.. data:: byteorder
|
||||
|
||||
the byte order of the system ("little" or "big")
|
||||
|
||||
.. data:: path
|
||||
|
||||
a mutable list of directories to search for imported modules
|
||||
|
||||
.. data:: platform
|
||||
|
||||
the platform that Micro Python is running on
|
||||
|
||||
.. data:: stderr
|
||||
|
||||
standard error (connected to USB VCP, and optional UART object)
|
||||
|
||||
.. data:: stdin
|
||||
|
||||
standard input (connected to USB VCP, and optional UART object)
|
||||
|
||||
.. data:: stdout
|
||||
|
||||
standard output (connected to USB VCP, and optional UART object)
|
||||
|
||||
.. data:: version
|
||||
|
||||
Python language version that this implementation conforms to, as a string
|
||||
|
||||
.. data:: version_info
|
||||
|
||||
Python language version that this implementation conforms to, as a tuple of ints
|
||||
41
docs/library/time.rst
Normal file
@@ -0,0 +1,41 @@
|
||||
:mod:`time` -- time related functions
|
||||
=====================================
|
||||
|
||||
.. module:: time
|
||||
:synopsis: time related functions
|
||||
|
||||
The ``time`` module provides functions for getting the current time and date,
|
||||
and for sleeping.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: localtime([secs])
|
||||
|
||||
Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
If secs is not provided or None, then the current time from the RTC is used.
|
||||
year includes the century (for example 2014).
|
||||
|
||||
* month is 1-12
|
||||
* mday is 1-31
|
||||
* hour is 0-23
|
||||
* minute is 0-59
|
||||
* second is 0-59
|
||||
* weekday is 0-6 for Mon-Sun
|
||||
* yearday is 1-366
|
||||
|
||||
.. function:: mktime()
|
||||
|
||||
This is inverse function of localtime. It's argument is a full 8-tuple
|
||||
which expresses a time as per localtime. It returns an integer which is
|
||||
the number of seconds since Jan 1, 2000.
|
||||
|
||||
.. function:: sleep(seconds)
|
||||
|
||||
Sleep for the given number of seconds. Seconds can be a floating-point number to
|
||||
sleep for a fractional number of seconds.
|
||||
|
||||
.. function:: time()
|
||||
|
||||
Returns the number of seconds, as an integer, since 1/1/2000.
|
||||
25
docs/library/uheapq.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
:mod:`uheapq` -- heap queue algorithm
|
||||
=====================================
|
||||
|
||||
.. module:: uheapq
|
||||
:synopsis: heap queue algorithm
|
||||
|
||||
This module implements the heap queue algorithm.
|
||||
|
||||
A heap queue is simply a list that has its elements stored in a certain way.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: heappush(heap, item)
|
||||
|
||||
Push the ``item`` onto the ``heap``.
|
||||
|
||||
.. function:: heappop(heap)
|
||||
|
||||
Pop the first item froh the ``heap``, and return it. Raises IndexError if
|
||||
heap is empty.
|
||||
|
||||
.. function:: heapify(x)
|
||||
|
||||
Convert the list ``x`` into a heap. This is an in-place operation.
|
||||
20
docs/library/ujson.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
:mod:`ujson` -- JSON encoding and decoding
|
||||
==========================================
|
||||
|
||||
.. module:: ujson
|
||||
:synopsis: JSON encoding and decoding
|
||||
|
||||
This modules allows to convert between Python objects and the JSON
|
||||
data format.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: dumps(obj)
|
||||
|
||||
Return ``obj`` represented as a JSON string.
|
||||
|
||||
.. function:: loads(str)
|
||||
|
||||
Parse the JSON ``str`` and return an object. Raises ValueError if the
|
||||
string is not correctly formed.
|
||||
17
docs/library/usocket.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
:mod:`usocket` -- socket module
|
||||
===============================
|
||||
|
||||
.. module:: usocket
|
||||
:synopsis: socket module
|
||||
|
||||
Socket functionality.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: getaddrinfo(host, port)
|
||||
|
||||
|
||||
.. function:: socket(family=AF_INET, type=SOCK_STREAM, fileno=-1)
|
||||
|
||||
Create a socket.
|
||||
24
docs/license.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
Micro Python license information
|
||||
================================
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013, 2014 Damien P. George, and others
|
||||
|
||||
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.
|
||||
140
docs/quickref.rst
Normal file
@@ -0,0 +1,140 @@
|
||||
.. _quickref:
|
||||
|
||||
Quick reference for the pyboard
|
||||
===============================
|
||||
|
||||
.. image:: http://micropython.org/resources/pybv10-pinout.jpg
|
||||
:alt: PYBv1.0 pinout
|
||||
:width: 700px
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
|
||||
See :mod:`pyb`. ::
|
||||
|
||||
import pyb
|
||||
|
||||
pyb.delay(50) # wait 50 milliseconds
|
||||
pyb.millis() # number of milliseconds since bootup
|
||||
pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1)
|
||||
pyb.wfi() # pause CPU, waiting for interrupt
|
||||
pyb.freq() # get CPU and bus frequencies
|
||||
pyb.freq(60000000) # set CPU freq to 60MHz
|
||||
pyb.stop() # stop CPU, waiting for external interrupt
|
||||
|
||||
LEDs
|
||||
----
|
||||
|
||||
See :ref:`pyb.LED <pyb.LED>`. ::
|
||||
|
||||
from pyb import LED
|
||||
|
||||
led = LED(1) # red led
|
||||
led.toggle()
|
||||
led.on()
|
||||
led.off()
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>`. ::
|
||||
|
||||
from pyb import Pin
|
||||
|
||||
p_out = Pin('X1', Pin.OUT_PP)
|
||||
p_out.high()
|
||||
p_out.low()
|
||||
|
||||
p_in = Pin('X2', Pin.IN, Pin.PULL_UP)
|
||||
p_in.value() # get value, 0 or 1
|
||||
|
||||
External interrupts
|
||||
-------------------
|
||||
|
||||
See :ref:`pyb.ExtInt <pyb.ExtInt>`. ::
|
||||
|
||||
from pyb import Pin, ExtInt
|
||||
|
||||
callback = lambda e: print("intr")
|
||||
ext = ExtInt(Pin('Y1'), ExtInt.IRQ_RISING, Pin.PULL_NONE, callback)
|
||||
|
||||
Timers
|
||||
------
|
||||
|
||||
See :ref:`pyb.Timer <pyb.Timer>`. ::
|
||||
|
||||
from pyb import Timer
|
||||
|
||||
tim = Timer(1, freq=1000)
|
||||
tim.counter() # get counter value
|
||||
tim.freq(0.5) # 0.5 Hz
|
||||
tim.callback(lambda t: pyb.LED(1).toggle())
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::
|
||||
|
||||
from pyb import Pin, Timer
|
||||
|
||||
p = Pin('X1') # X1 has TIM2, CH1
|
||||
tim = Timer(2, freq=1000)
|
||||
ch = tim.channel(1, Timer.PWM, pin=p)
|
||||
ch.pulse_width_percent(50)
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.ADC <pyb.ADC>`. ::
|
||||
|
||||
from pyb import Pin, ADC
|
||||
|
||||
adc = ADC(Pin('X19'))
|
||||
adc.read() # read value, 0-4095
|
||||
|
||||
DAC (digital to analog conversion)
|
||||
----------------------------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.DAC <pyb.DAC>`. ::
|
||||
|
||||
from pyb import Pin, DAC
|
||||
|
||||
dac = DAC(Pin('X5'))
|
||||
dac.write(120) # output between 0 and 255
|
||||
|
||||
UART (serial bus)
|
||||
-----------------
|
||||
|
||||
See :ref:`pyb.UART <pyb.UART>`. ::
|
||||
|
||||
from pyb import UART
|
||||
|
||||
uart = UART(1, 9600)
|
||||
uart.write('hello')
|
||||
uart.read(5) # read up to 5 bytes
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
|
||||
See :ref:`pyb.SPI <pyb.SPI>`. ::
|
||||
|
||||
from pyb import SPI
|
||||
|
||||
spi = SPI(1, SPI.MASTER, baudrate=200000, polarity=1, phase=0)
|
||||
spi.send('hello')
|
||||
spi.recv(5) # receive 5 bytes on the bus
|
||||
spi.send_recv('hello') # send a receive 5 bytes
|
||||
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
See :ref:`pyb.I2C <pyb.I2C>`. ::
|
||||
|
||||
from pyb import I2C
|
||||
|
||||
i2c = I2C(1, I2C.MASTER, baudrate=100000)
|
||||
i2c.scan() # returns list of slave addresses
|
||||
i2c.send('hello', 0x42) # send 5 bytes to slave with address 0x42
|
||||
i2c.recv(5, 0x42) # receive 5 bytes from slave
|
||||
i2c.mem_read(2, 0x42, 0x10) # read 2 bytes from slave 0x42, slave memory 0x10
|
||||
i2c.mem_write('xy', 0x42, 0x10) # write 2 bytes to slave 0x42, slave memory 0x10
|
||||
93
docs/topindex.html
Normal file
@@ -0,0 +1,93 @@
|
||||
{% extends "defindex.html" %}
|
||||
{% block body %}
|
||||
|
||||
<h1>Micro Python documentation</h1>
|
||||
|
||||
<p>
|
||||
{{ _('Welcome! This is the documentation for Micro Python') }}
|
||||
v{{ release|e }}{% if last_updated %}, {{ _('last updated') }} {{ last_updated|e }}{% endif %}.
|
||||
</p>
|
||||
|
||||
<p><strong>Documentation for Micro Python and the pyboard:</strong></p>
|
||||
|
||||
<table class="contentstable"><tr>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("quickref") }}">Quick reference for the pyboard</a><br/>
|
||||
<span class="linkdescr">pinout for the pyboard and snippets of useful code</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("general") }}">General information about the pyboard</a><br/>
|
||||
<span class="linkdescr">read this first for a quick overview</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("tutorial/index") }}">Tutorials and code examples</a><br/>
|
||||
<span class="linkdescr">start here</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("library/index") }}">Library Reference</a><br/>
|
||||
<span class="linkdescr">Micro Python libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
|
||||
</p>
|
||||
</td>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("hardware/index") }}">The pyboard hardware</a><br/>
|
||||
<span class="linkdescr">schematics, dimensions and component datasheets</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="http://micropython.org/resources/Micro-Python-Windows-setup.pdf">Guide for pyboard on Windows (PDF)</a><br/>
|
||||
<span class="linkdescr">including DFU programming</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("license") }}">License</a><br/>
|
||||
<span class="linkdescr">Micro Python license information</span>
|
||||
</p>
|
||||
</td>
|
||||
</tr></table>
|
||||
|
||||
<p><strong>Indices and tables:</strong></p>
|
||||
<table class="contentstable"><tr>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("py-modindex") }}">Module index</a><br/>
|
||||
<span class="linkdescr">quick access to all modules</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("genindex") }}">Full index</a><br/>
|
||||
<span class="linkdescr">all functions, classes, constants</span>
|
||||
</p>
|
||||
</td>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("contents") }}">Table of contents</a><br/>
|
||||
<span class="linkdescr">a list of all sections and subsections</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
|
||||
<span class="linkdescr">search this documentation</span>
|
||||
</p>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<p><strong>External links:</strong></p>
|
||||
|
||||
<table class="contentstable"><tr>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="http://micropython.org">Micro Python homepage</a><br/>
|
||||
<span class="linkdescr">the official Micro Python site</span>
|
||||
</p>
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="http://forum.micropython.org">Micro Python forum</a><br/>
|
||||
<span class="linkdescr">community discussion for all things related to Micro Python</span>
|
||||
</p>
|
||||
</td>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="https://github.com/micropython">Micro Python on GitHub</a><br/>
|
||||
<span class="linkdescr">contribute to the source code on GitHub</span>
|
||||
</p>
|
||||
</td>
|
||||
</tr></table>
|
||||
|
||||
{% endblock %}
|
||||
@@ -3,11 +3,11 @@ The AMP audio skin
|
||||
|
||||
Soldering and using the AMP audio skin.
|
||||
|
||||
.. image:: http://micropython.org/static/doc/skin-amp-1.jpg
|
||||
.. image:: img/skin_amp_1.jpg
|
||||
:alt: AMP skin
|
||||
:width: 250px
|
||||
|
||||
.. image:: http://micropython.org/static/doc/skin-amp-3.jpg
|
||||
.. image:: img/skin_amp_2.jpg
|
||||
:alt: AMP skin
|
||||
:width: 250px
|
||||
|
||||
@@ -26,6 +26,7 @@ potentiometer, which is an I2C device with address 46 on the ``IC2(1)`` bus.
|
||||
|
||||
To set the volume, define the following function::
|
||||
|
||||
import pyb
|
||||
def volume(val):
|
||||
pyb.I2C(1, pyb.I2C.MASTER).mem_write(val, 46, 0)
|
||||
|
||||
@@ -50,11 +51,11 @@ For example::
|
||||
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
|
||||
|
||||
You can also play WAV files using the Python ``wave`` module. You can get
|
||||
the wave module [here](/static/doc/examples/wave.py) and you will also need
|
||||
the chunk module available [here](/static/doc/examples/chunk.py). Put these
|
||||
the wave module `here <http://micropython.org/resources/examples/wave.py>`_ and you will also need
|
||||
the chunk module available `here <http://micropython.org/resources/examples/chunk.py>`_. Put these
|
||||
on your pyboard (either on the flash or the SD card in the top-level
|
||||
directory). You will need an 8-bit WAV file to play, such as
|
||||
[this one](/static/doc/examples/test.wav). Then you can do::
|
||||
`this one <http://micropython.org/resources/examples/test.wav>`_. Then you can do::
|
||||
|
||||
>>> import wave
|
||||
>>> from pyb import DAC
|
||||
|
||||
37
docs/tutorial/debounce.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
Debouncing a pin input
|
||||
======================
|
||||
|
||||
A pin used as input from a switch or other mechanical device can have a lot
|
||||
of noise on it, rapidly changing from low to high when the switch is first
|
||||
pressed or released. This noise can be eliminated using a capacitor (a
|
||||
debouncing circuit). It can also be eliminated using a simple function that
|
||||
makes sure the value on the pin is stable.
|
||||
|
||||
The following function does just this. It gets the current value of the given
|
||||
pin, and then waits for the value to change. The new pin value must be stable
|
||||
for a continuous 20ms for it to register the change. You can adjust this time
|
||||
(to say 50ms) if you still have noise. ::
|
||||
|
||||
import pyb
|
||||
|
||||
def wait_pin_change(pin):
|
||||
# wait for pin to change value
|
||||
# it needs to be stable for a continuous 20ms
|
||||
cur_value = pin.value()
|
||||
active = 0
|
||||
while active < 20:
|
||||
if pin.value() != cur_value:
|
||||
active += 1
|
||||
else:
|
||||
active = 0
|
||||
pyb.delay(1)
|
||||
|
||||
|
||||
Use it something like this::
|
||||
|
||||
import pyb
|
||||
|
||||
pin_x1 = pyb.Pin('X1', pyb.Pin.IN, pyb.Pin.PULL_DOWN)
|
||||
while True:
|
||||
wait_pin_change(pin_x1)
|
||||
pyb.LED(4).toggle()
|
||||
89
docs/tutorial/fading_led.rst
Normal file
@@ -0,0 +1,89 @@
|
||||
Fading LEDs
|
||||
===========
|
||||
|
||||
In addition to turning LEDs on and off, it is also possible to control the brightness of an LED using `Pulse-Width Modulation (PWM) <http://en.wikipedia.org/wiki/Pulse-width_modulation>`_, a common technique for obtaining variable output from a digital pin. This allows us to fade an LED:
|
||||
|
||||
.. image:: http://upload.wikimedia.org/wikipedia/commons/a/a9/Fade.gif
|
||||
|
||||
Components
|
||||
----------
|
||||
|
||||
You will need:
|
||||
|
||||
- Standard 5 or 3 mm LED
|
||||
- 100 Ohm resistor
|
||||
- Wires
|
||||
- `Breadboard <http://en.wikipedia.org/wiki/Breadboard>`_ (optional, but makes things easier)
|
||||
|
||||
Connecting Things Up
|
||||
--------------------
|
||||
|
||||
For this tutorial, we will use the ``X1`` pin. Connect one end of the resistor to ``X1``, and the other end to the **anode** of the LED, which is the longer leg. Connect the **cathode** of the LED to ground.
|
||||
|
||||
.. image:: img/fading_leds_breadboard_fritzing.png
|
||||
|
||||
Code
|
||||
----
|
||||
By examining the :ref:`quickref`, we see that ``X1`` is connected to channel 1 of timer 5 (``TIM5 CH1``). Therefore we will first create a ``Timer`` object for timer 5, then create a ``TimerChannel`` object for channel 1::
|
||||
|
||||
from pyb import Timer
|
||||
from time import sleep
|
||||
|
||||
# timer 5 will be created with a frequency of 100 Hz
|
||||
tim = pyb.Timer(5, freq=100)
|
||||
tchannel = tim.channel(1, Timer.PWM, pin=pyb.Pin.board.X1, pulse_width=0)
|
||||
|
||||
Brightness of the LED in PWM is controlled by controlling the pulse-width, that is the amount of time the LED is on every cycle. With a timer frequency of 100 Hz, each cycle takes 0.01 second, or 10 ms.
|
||||
|
||||
To achieve the fading effect shown at the beginning of this tutorial, we want to set the pulse-width to a small value, then slowly increase the pulse-width to brighten the LED, and start over when we reach some maximum brightness::
|
||||
|
||||
# maximum and minimum pulse-width, which corresponds to maximum
|
||||
# and minimum brightness
|
||||
max_width = 200000
|
||||
min_width = 20000
|
||||
|
||||
# how much to change the pulse-width by each step
|
||||
wstep = 1500
|
||||
cur_width = min_width
|
||||
|
||||
while True:
|
||||
tchannel.pulse_width(cur_width)
|
||||
|
||||
# this determines how often we change the pulse-width. It is
|
||||
# analogous to frames-per-second
|
||||
sleep(0.01)
|
||||
|
||||
cur_width += wstep
|
||||
|
||||
if cur_width > max_width:
|
||||
cur_width = min_width
|
||||
|
||||
Breathing Effect
|
||||
----------------
|
||||
|
||||
If we want to have a breathing effect, where the LED fades from dim to bright then bright to dim, then we simply need to reverse the sign of ``wstep`` when we reach maximum brightness, and reverse it again at minimum brightness. To do this we modify the ``while`` loop to be::
|
||||
|
||||
while True:
|
||||
tchannel.pulse_width(cur_width)
|
||||
|
||||
sleep(0.01)
|
||||
|
||||
cur_width += wstep
|
||||
|
||||
if cur_width > max_width:
|
||||
cur_width = max_width
|
||||
wstep *= -1
|
||||
elif cur_width < min_width:
|
||||
cur_width = min_width
|
||||
wstep *= -1
|
||||
|
||||
Advanced Exercise
|
||||
-----------------
|
||||
|
||||
You may have noticed that the LED brightness seems to fade slowly, but increases quickly. This is because our eyes interprets brightness logarithmically (`Weber's Law <http://www.telescope-optics.net/eye_intensity_response.htm>`_
|
||||
), while the LED's brightness changes linearly, that is by the same amount each time. How do you solve this problem? (Hint: what is the opposite of the logarithmic function?)
|
||||
|
||||
Addendum
|
||||
--------
|
||||
|
||||
We could have also used the digital-to-analog converter (DAC) to achieve the same effect. The PWM method has the advantage that it drives the LED with the same current each time, but for different lengths of time. This allows better control over the brightness, because LEDs do not necessarily exhibit a linear relationship between the driving current and brightness.
|
||||
BIN
docs/tutorial/img/fading_leds_breadboard_fritzing.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/tutorial/img/pyboard_servo.jpg
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
docs/tutorial/img/pyboard_usb_micro.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
docs/tutorial/img/skin_amp_1.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
docs/tutorial/img/skin_amp_2.jpg
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
docs/tutorial/img/skin_lcd_1.jpg
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
docs/tutorial/img/skin_lcd_2.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
@@ -22,6 +22,7 @@ the tutorial through in the order below.
|
||||
usb_mouse.rst
|
||||
timer.rst
|
||||
assembler.rst
|
||||
power_ctrl.rst
|
||||
|
||||
Tutorials requiring extra components
|
||||
------------------------------------
|
||||
@@ -31,5 +32,16 @@ Tutorials requiring extra components
|
||||
:numbered:
|
||||
|
||||
servo.rst
|
||||
fading_led.rst
|
||||
lcd_skin.rst
|
||||
amp_skin.rst
|
||||
|
||||
Tips, tricks and useful things to know
|
||||
--------------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
debounce.rst
|
||||
pass_through.rst
|
||||
|
||||
@@ -3,11 +3,11 @@ The LCD and touch-sensor skin
|
||||
|
||||
Soldering and using the LCD and touch-sensor skin.
|
||||
|
||||
.. image:: http://micropython.org/static/doc/skin-lcd-3.jpg
|
||||
.. image:: img/skin_lcd_1.jpg
|
||||
:alt: pyboard with LCD skin
|
||||
:width: 250px
|
||||
|
||||
.. image:: http://micropython.org/static/doc/skin-lcd-1.jpg
|
||||
.. image:: img/skin_lcd_2.jpg
|
||||
:alt: pyboard with LCD skin
|
||||
:width: 250px
|
||||
|
||||
@@ -24,12 +24,14 @@ Using the LCD
|
||||
To get started using the LCD, try the following at the Micro Python prompt.
|
||||
Make sure the LCD skin is attached to the pyboard as pictured at the top of this page. ::
|
||||
|
||||
>>> import pyb
|
||||
>>> lcd = pyb.LCD('X')
|
||||
>>> lcd.light(True)
|
||||
>>> lcd.write('Hello uPy!\n')
|
||||
|
||||
You can make a simple animation using the code::
|
||||
|
||||
import pyb
|
||||
lcd = pyb.LCD('X')
|
||||
lcd.light(True)
|
||||
for x in range(-80, 128):
|
||||
@@ -46,6 +48,7 @@ MPR121 capacitive touch sensor has address 90.
|
||||
|
||||
To get started, try::
|
||||
|
||||
>>> import pyb
|
||||
>>> i2c = pyb.I2C(1, pyb.I2C.MASTER)
|
||||
>>> i2c.mem_write(4, 90, 0x5e)
|
||||
>>> touch = i2c.mem_read(1, 90, 0)[0]
|
||||
@@ -55,7 +58,7 @@ enables the 4 touch sensors. The third line reads the touch
|
||||
status and the ``touch`` variable holds the state of the 4 touch
|
||||
buttons (A, B, X, Y).
|
||||
|
||||
There is a simple driver [here](/static/doc/examples/mpr121.py)
|
||||
There is a simple driver `here <http://micropython.org/resources/examples/mpr121.py>`_
|
||||
which allows you to set the threshold and debounce parameters, and
|
||||
easily read the touch status and electrode voltage levels. Copy
|
||||
this script to your pyboard (either flash or SD card, in the top
|
||||
@@ -78,4 +81,4 @@ initialise the I2C bus using::
|
||||
>>> m = mpr121.MPR121(pyb.I2C(2, pyb.I2C.MASTER))
|
||||
|
||||
There is also a demo which uses the LCD and the touch sensors together,
|
||||
and can be found [here](/static/doc/examples/lcddemo.py).
|
||||
and can be found `here <http://micropython.org/resources/examples/lcddemo.py>`_.
|
||||
|
||||
17
docs/tutorial/pass_through.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
Making a UART - USB pass through
|
||||
================================
|
||||
|
||||
It's as simple as::
|
||||
|
||||
import pyb
|
||||
import select
|
||||
|
||||
def pass_through(usb, uart):
|
||||
while True:
|
||||
select.select([usb, uart], [], [])
|
||||
if usb.any():
|
||||
uart.write(usb.read(256))
|
||||
if uart.any():
|
||||
usb.write(uart.read(256))
|
||||
|
||||
pass_through(pyb.USB_VCP(), pyb.UART(1, 9600))
|
||||
13
docs/tutorial/power_ctrl.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
Power control
|
||||
=============
|
||||
|
||||
:meth:`pyb.wfi` is used to reduce power consumption while waiting for an
|
||||
event such as an interrupt. You would use it in the following situation::
|
||||
|
||||
while True:
|
||||
do_some_processing()
|
||||
pyb.wfi()
|
||||
|
||||
Control the frequency using :meth:`pyb.freq`::
|
||||
|
||||
pyb.freq(30000000) # set CPU frequency to 30MHz
|
||||
@@ -26,7 +26,7 @@ and see which COM port it is (eg COM4).
|
||||
|
||||
You now need to run your terminal program. You can use HyperTerminal if you
|
||||
have it installed, or download the free program PuTTY:
|
||||
[`putty.exe`](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html).
|
||||
`putty.exe <http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html>`_.
|
||||
Using your serial program you must connect to the COM port that you found in the
|
||||
previous step. With PuTTY, click on "Session" in the left-hand panel, then click
|
||||
the "Serial" radio button on the right, then enter you COM port (eg COM4) in the
|
||||
@@ -39,7 +39,7 @@ Open a terminal and run::
|
||||
|
||||
screen /dev/tty.usbmodem*
|
||||
|
||||
When you are finishend and want to exit screen, type CTRL-A CTRL-\\.
|
||||
When you are finished and want to exit screen, type CTRL-A CTRL-\\.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
@@ -10,7 +10,7 @@ Connecting your pyboard
|
||||
Connect your pyboard to your PC (Windows, Mac or Linux) with a micro USB cable.
|
||||
There is only one way that the cable will connect, so you can't get it wrong.
|
||||
|
||||
<img src="/static/doc/pyboard-usb-micro.jpg" alt="pyboard with USB micro cable" style="width:200px; border:1px solid black; display:inline-block;"/>
|
||||
.. image:: img/pyboard_usb_micro.jpg
|
||||
|
||||
When the pyboard is connected to your PC it will power on and enter the start up
|
||||
process (the boot process). The green LED should light up for half a second or
|
||||
@@ -46,16 +46,16 @@ a window (or command line) should be showing the files on the pyboard drive.
|
||||
The drive you are looking at is known as ``/flash`` by the pyboard, and should contain
|
||||
the following 4 files:
|
||||
|
||||
- [``boot.py``](/static/doc/fresh-pyboard/boot.py) -- this script is executed when the pyboard boots up. It sets
|
||||
* `boot.py <http://micropython.org/resources/fresh-pyboard/boot.py>`_ -- this script is executed when the pyboard boots up. It sets
|
||||
up various configuration options for the pyboard.
|
||||
|
||||
- [``main.py``](/static/doc/fresh-pyboard/main.py) -- this is the main script that will contain your Python program.
|
||||
* `main.py <http://micropython.org/resources/fresh-pyboard/main.py>`_ -- this is the main script that will contain your Python program.
|
||||
It is executed after ``boot.py``.
|
||||
|
||||
- [``README.txt``](/static/doc/fresh-pyboard/README.txt) -- this contains some very basic information about getting
|
||||
* `README.txt <http://micropython.org/resources/fresh-pyboard/README.txt>`_ -- this contains some very basic information about getting
|
||||
started with the pyboard.
|
||||
|
||||
- [``pybcdc.inf``](/static/doc/fresh-pyboard/pybcdc.inf) -- this is a Windows driver file to configure the serial USB
|
||||
* `pybcdc.inf <http://micropython.org/resources/fresh-pyboard/pybcdc.inf>`_ -- this is a Windows driver file to configure the serial USB
|
||||
device. More about this in the next tutorial.
|
||||
|
||||
Editing ``main.py``
|
||||
|
||||
@@ -8,7 +8,7 @@ These motors have 3 wires: ground, power and signal. On the pyboard you
|
||||
can connect them in the bottom right corner, with the signal pin on the
|
||||
far right. Pins X1, X2, X3 and X4 are the 4 dedicated servo signal pins.
|
||||
|
||||
<img src="/static/doc/pyboard-servo.jpg" alt="pyboard with servo motors" style="width:250px; border:1px solid black; display:inline-block;"/>
|
||||
.. image:: img/pyboard_servo.jpg
|
||||
|
||||
In this picture there are male-male double adaptors to connect the servos
|
||||
to the header pins on the pyboard.
|
||||
|
||||
234
drivers/nrf24l01/nrf24l01.py
Normal file
@@ -0,0 +1,234 @@
|
||||
"""NRF24L01 driver for Micro Python"""
|
||||
|
||||
import pyb
|
||||
|
||||
# nRF24L01+ registers
|
||||
CONFIG = const(0x00)
|
||||
EN_RXADDR = const(0x02)
|
||||
SETUP_AW = const(0x03)
|
||||
SETUP_RETR = const(0x04)
|
||||
RF_CH = const(0x05)
|
||||
RF_SETUP = const(0x06)
|
||||
STATUS = const(0x07)
|
||||
OBSERVE_TX = const(0x08)
|
||||
RX_ADDR_P0 = const(0x0a)
|
||||
TX_ADDR = const(0x10)
|
||||
RX_PW_P0 = const(0x11)
|
||||
FIFO_STATUS = const(0x17)
|
||||
DYNPD = const(0x1c)
|
||||
|
||||
# CONFIG register
|
||||
EN_CRC = const(0x08) # enable CRC
|
||||
CRCO = const(0x04) # CRC encoding scheme; 0=1 byte, 1=2 bytes
|
||||
PWR_UP = const(0x02) # 1=power up, 0=power down
|
||||
PRIM_RX = const(0x01) # RX/TX control; 0=PTX, 1=PRX
|
||||
|
||||
# RF_SETUP register
|
||||
POWER_0 = const(0x00) # -18 dBm
|
||||
POWER_1 = const(0x02) # -12 dBm
|
||||
POWER_2 = const(0x04) # -6 dBm
|
||||
POWER_3 = const(0x06) # 0 dBm
|
||||
SPEED_1M = const(0x00)
|
||||
SPEED_2M = const(0x08)
|
||||
SPEED_250K = const(0x20)
|
||||
|
||||
# STATUS register
|
||||
RX_DR = const(0x40) # RX data ready; write 1 to clear
|
||||
TX_DS = const(0x20) # TX data sent; write 1 to clear
|
||||
MAX_RT = const(0x10) # max retransmits reached; write 1 to clear
|
||||
|
||||
# FIFO_STATUS register
|
||||
RX_EMPTY = const(0x01) # 1 if RX FIFO is empty
|
||||
|
||||
# constants for instructions
|
||||
R_RX_PL_WID = const(0x60) # read RX payload width
|
||||
R_RX_PAYLOAD = const(0x61) # read RX payload
|
||||
W_TX_PAYLOAD = const(0xa0) # write TX payload
|
||||
FLUSH_TX = const(0xe1) # flush TX FIFO
|
||||
FLUSH_RX = const(0xe2) # flush RX FIFO
|
||||
NOP = const(0xff) # use to read STATUS register
|
||||
|
||||
class NRF24L01:
|
||||
def __init__(self, spi, cs, ce, channel=46, payload_size=16):
|
||||
assert payload_size <= 32
|
||||
|
||||
# init the SPI bus and pins
|
||||
spi.init(spi.MASTER, baudrate=4000000, polarity=0, phase=1, firstbit=spi.MSB)
|
||||
cs.init(cs.OUT_PP, cs.PULL_NONE)
|
||||
ce.init(ce.OUT_PP, ce.PULL_NONE)
|
||||
|
||||
# store the pins
|
||||
self.spi = spi
|
||||
self.cs = cs
|
||||
self.ce = ce
|
||||
|
||||
# reset everything
|
||||
self.ce.low()
|
||||
self.cs.high()
|
||||
self.payload_size = payload_size
|
||||
self.pipe0_read_addr = None
|
||||
pyb.delay(5)
|
||||
|
||||
# set address width to 5 bytes
|
||||
self.reg_write(SETUP_AW, 0b11)
|
||||
|
||||
# disable dynamic payloads
|
||||
self.reg_write(DYNPD, 0)
|
||||
|
||||
# auto retransmit delay: 1750us
|
||||
# auto retransmit count: 8
|
||||
self.reg_write(SETUP_RETR, (6 << 4) | 8)
|
||||
|
||||
# set rf power and speed
|
||||
self.set_power_speed(POWER_3, SPEED_1M)
|
||||
|
||||
# init CRC
|
||||
self.set_crc(2)
|
||||
|
||||
# clear status flags
|
||||
self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
|
||||
# set channel
|
||||
self.set_channel(channel)
|
||||
|
||||
# flush buffers
|
||||
self.flush_rx()
|
||||
self.flush_tx()
|
||||
|
||||
def reg_read(self, reg):
|
||||
self.cs.low()
|
||||
self.spi.send_recv(reg)
|
||||
buf = self.spi.recv(1)
|
||||
self.cs.high()
|
||||
return buf[0]
|
||||
|
||||
def reg_read_ret_status(self, reg):
|
||||
self.cs.low()
|
||||
status = self.spi.send_recv(reg)[0]
|
||||
buf = self.spi.recv(1)
|
||||
self.cs.high()
|
||||
return status
|
||||
|
||||
def reg_write(self, reg, buf):
|
||||
self.cs.low()
|
||||
status = self.spi.send_recv(0x20 | reg)[0]
|
||||
self.spi.send(buf)
|
||||
self.cs.high()
|
||||
return status
|
||||
|
||||
def flush_rx(self):
|
||||
self.cs.low()
|
||||
self.spi.send(FLUSH_RX)
|
||||
self.cs.high()
|
||||
|
||||
def flush_tx(self):
|
||||
self.cs.low()
|
||||
self.spi.send(FLUSH_TX)
|
||||
self.cs.high()
|
||||
|
||||
# power is one of POWER_x defines; speed is one of SPEED_x defines
|
||||
def set_power_speed(self, power, speed):
|
||||
setup = self.reg_read(RF_SETUP) & 0b11010001
|
||||
self.reg_write(RF_SETUP, setup | power | speed)
|
||||
|
||||
# length in bytes: 0, 1 or 2
|
||||
def set_crc(self, length):
|
||||
config = self.reg_read(CONFIG) & ~(CRCO | EN_CRC)
|
||||
if length == 0:
|
||||
pass
|
||||
elif length == 1:
|
||||
config |= EN_CRC
|
||||
else:
|
||||
config |= EN_CRC | CRCO
|
||||
self.reg_write(CONFIG, config)
|
||||
|
||||
def set_channel(self, channel):
|
||||
self.reg_write(RF_CH, min(channel, 127))
|
||||
|
||||
# address should be a bytes object 5 bytes long
|
||||
def open_tx_pipe(self, address):
|
||||
assert len(address) == 5
|
||||
self.reg_write(RX_ADDR_P0, address)
|
||||
self.reg_write(TX_ADDR, address)
|
||||
self.reg_write(RX_PW_P0, self.payload_size)
|
||||
|
||||
# address should be a bytes object 5 bytes long
|
||||
# pipe 0 and 1 have 5 byte address
|
||||
# pipes 2-5 use same 4 most-significant bytes as pipe 1, plus 1 extra byte
|
||||
def open_rx_pipe(self, pipe_id, address):
|
||||
assert len(address) == 5
|
||||
assert 0 <= pipe_id <= 5
|
||||
if pipe_id == 0:
|
||||
self.pipe0_read_addr = address
|
||||
if pipe_id < 2:
|
||||
self.reg_write(RX_ADDR_P0 + pipe_id, address)
|
||||
else:
|
||||
self.reg_write(RX_ADDR_P0 + pipe_id, address[0])
|
||||
self.reg_write(RX_PW_P0 + pipe_id, self.payload_size)
|
||||
self.reg_write(EN_RXADDR, self.reg_read(EN_RXADDR) | (1 << pipe_id))
|
||||
|
||||
def start_listening(self):
|
||||
self.reg_write(CONFIG, self.reg_read(CONFIG) | PWR_UP | PRIM_RX)
|
||||
self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
|
||||
if self.pipe0_read_addr is not None:
|
||||
self.reg_write(RX_ADDR_P0, self.pipe0_read_addr)
|
||||
|
||||
self.flush_rx()
|
||||
self.flush_tx()
|
||||
self.ce.high()
|
||||
pyb.udelay(130)
|
||||
|
||||
def stop_listening(self):
|
||||
self.ce.low()
|
||||
self.flush_tx()
|
||||
self.flush_rx()
|
||||
|
||||
# returns True if any data available to recv
|
||||
def any(self):
|
||||
return not bool(self.reg_read(FIFO_STATUS) & RX_EMPTY)
|
||||
|
||||
def recv(self):
|
||||
# get the data
|
||||
self.cs.low()
|
||||
self.spi.send(R_RX_PAYLOAD)
|
||||
buf = self.spi.recv(self.payload_size)
|
||||
self.cs.high()
|
||||
|
||||
# clear RX ready flag
|
||||
self.reg_write(STATUS, RX_DR)
|
||||
|
||||
return buf
|
||||
|
||||
def send(self, buf, timeout=500):
|
||||
# power up
|
||||
self.reg_write(CONFIG, (self.reg_read(CONFIG) | PWR_UP) & ~PRIM_RX)
|
||||
pyb.udelay(150)
|
||||
|
||||
# send the data
|
||||
self.cs.low()
|
||||
self.spi.send(W_TX_PAYLOAD)
|
||||
self.spi.send(buf)
|
||||
if len(buf) < self.payload_size:
|
||||
self.spi.send(b'\x00' * (self.payload_size - len(buf))) # pad out data
|
||||
self.cs.high()
|
||||
|
||||
# enable the chip so it can send the data
|
||||
self.ce.high()
|
||||
pyb.udelay(15) # needs to be >10us
|
||||
self.ce.low()
|
||||
|
||||
# blocking wait for tx complete
|
||||
start = pyb.millis()
|
||||
while pyb.millis() - start < timeout:
|
||||
status = self.reg_read_ret_status(OBSERVE_TX)
|
||||
if status & (TX_DS | MAX_RT):
|
||||
break
|
||||
|
||||
# get and clear all status flags
|
||||
status = self.reg_write(STATUS, RX_DR | TX_DS | MAX_RT)
|
||||
if not (status & TX_DS):
|
||||
raise OSError("send failed")
|
||||
|
||||
# power down
|
||||
self.reg_write(CONFIG, self.reg_read(CONFIG) & ~PWR_UP)
|
||||
100
drivers/nrf24l01/nrf24l01test.py
Normal file
@@ -0,0 +1,100 @@
|
||||
"""Test for nrf24l01 module."""
|
||||
|
||||
import struct
|
||||
import pyb
|
||||
from pyb import Pin, SPI
|
||||
from nrf24l01 import NRF24L01
|
||||
|
||||
pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2')
|
||||
|
||||
def master():
|
||||
nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8)
|
||||
|
||||
nrf.open_tx_pipe(pipes[0])
|
||||
nrf.open_rx_pipe(1, pipes[1])
|
||||
nrf.start_listening()
|
||||
|
||||
num_needed = 16
|
||||
num_successes = 0
|
||||
num_failures = 0
|
||||
led_state = 0
|
||||
|
||||
print('NRF24L01 master mode, sending %d packets...' % num_needed)
|
||||
|
||||
while num_successes < num_needed and num_failures < num_needed:
|
||||
# stop listening and send packet
|
||||
nrf.stop_listening()
|
||||
millis = pyb.millis()
|
||||
led_state = max(1, (led_state << 1) & 0x0f)
|
||||
print('sending:', millis, led_state)
|
||||
try:
|
||||
nrf.send(struct.pack('ii', millis, led_state))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# start listening again
|
||||
nrf.start_listening()
|
||||
|
||||
# wait for response, with 250ms timeout
|
||||
start_time = pyb.millis()
|
||||
timeout = False
|
||||
while not nrf.any() and not timeout:
|
||||
if pyb.elapsed_millis(start_time) > 250:
|
||||
timeout = True
|
||||
|
||||
if timeout:
|
||||
print('failed, respones timed out')
|
||||
num_failures += 1
|
||||
|
||||
else:
|
||||
# recv packet
|
||||
got_millis, = struct.unpack('i', nrf.recv())
|
||||
|
||||
# print response and round-trip delay
|
||||
print('got response:', got_millis, '(delay', pyb.millis() - got_millis, 'ms)')
|
||||
num_successes += 1
|
||||
|
||||
# delay then loop
|
||||
pyb.delay(250)
|
||||
|
||||
print('master finished sending; succeses=%d, failures=%d' % (num_successes, num_failures))
|
||||
|
||||
def slave():
|
||||
nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8)
|
||||
|
||||
nrf.open_tx_pipe(pipes[1])
|
||||
nrf.open_rx_pipe(1, pipes[0])
|
||||
nrf.start_listening()
|
||||
|
||||
print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)')
|
||||
|
||||
while True:
|
||||
pyb.wfi()
|
||||
if nrf.any():
|
||||
while nrf.any():
|
||||
buf = nrf.recv()
|
||||
millis, led_state = struct.unpack('ii', buf)
|
||||
print('received:', millis, led_state)
|
||||
for i in range(4):
|
||||
if led_state & (1 << i):
|
||||
pyb.LED(i + 1).on()
|
||||
else:
|
||||
pyb.LED(i + 1).off()
|
||||
pyb.delay(15)
|
||||
|
||||
nrf.stop_listening()
|
||||
try:
|
||||
nrf.send(struct.pack('i', millis))
|
||||
except OSError:
|
||||
pass
|
||||
print('sent response')
|
||||
nrf.start_listening()
|
||||
|
||||
print('NRF24L01 test module loaded')
|
||||
print('NRF24L01 pinout for test:')
|
||||
print(' CE on Y4')
|
||||
print(' CSN on Y5')
|
||||
print(' SCK on Y6')
|
||||
print(' MISO on Y7')
|
||||
print(' MOSI on Y8')
|
||||
print('run nrf24l01test.slave() on slave, then nrf24l01test.master() on master')
|
||||
@@ -19,7 +19,7 @@ while True:
|
||||
if switch():
|
||||
pyb.delay(200) # delay avoids detection of multiple presses
|
||||
blue.on() # blue LED indicates file open
|
||||
log = open('1:/log.csv', 'w') # open file on SD (SD: '1:/', flash: '0/)
|
||||
log = open('/sd/log.csv', 'w') # open file on SD (SD: '/sd/', flash: '/flash/)
|
||||
|
||||
# until switch is pressed again
|
||||
while not switch():
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#import essential libraries
|
||||
import lcd
|
||||
import pyb
|
||||
|
||||
lcd = pyb.LCD('x')
|
||||
lcd.light(1)
|
||||
|
||||
# do 1 iteration of Conway's Game of Life
|
||||
def conway_step():
|
||||
for x in range(128): # loop over x coordinates
|
||||
@@ -21,26 +23,24 @@ def conway_step():
|
||||
|
||||
# apply the rules of life
|
||||
if self and not (2 <= num_neighbours <= 3):
|
||||
lcd.reset(x, y) # not enough, or too many neighbours: cell dies
|
||||
lcd.pixel(x, y, 0) # not enough, or too many neighbours: cell dies
|
||||
elif not self and num_neighbours == 3:
|
||||
lcd.set(x, y) # exactly 3 neigbours around an empty cell: cell is born
|
||||
lcd.pixel(x, y, 1) # exactly 3 neigbours around an empty cell: cell is born
|
||||
|
||||
# randomise the start
|
||||
def conway_rand():
|
||||
lcd.clear() # clear the LCD
|
||||
lcd.fill(0) # clear the LCD
|
||||
for x in range(128): # loop over x coordinates
|
||||
for y in range(32): # loop over y coordinates
|
||||
if pyb.rand() & 1: # get a 1-bit random number
|
||||
lcd.set(x, y) # set the pixel randomly
|
||||
lcd.pixel(x, y, pyb.rng() & 1) # set the pixel randomly
|
||||
|
||||
# loop for a certain number of frames, doing iterations of Conway's Game of Life
|
||||
def conway_go(num_frames):
|
||||
for i in range(num_frames):
|
||||
conway_step() # do 1 iteration
|
||||
lcd.show() # update the LCD
|
||||
pyb.delay(300)
|
||||
pyb.delay(50)
|
||||
|
||||
# PC testing
|
||||
lcd = lcd.LCD(128, 32)
|
||||
# testing
|
||||
conway_rand()
|
||||
conway_go(1000)
|
||||
conway_go(100)
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# LCD testing object for PC
|
||||
# uses double buffering
|
||||
class LCD:
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
|
||||
def clear(self):
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x] = 0
|
||||
|
||||
def show(self):
|
||||
print('') # blank line to separate frames
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x]
|
||||
for y in range(self.height):
|
||||
row = ''.join(['*' if self.buf1[y][x] else ' ' for x in range(self.width)])
|
||||
print(row)
|
||||
|
||||
def get(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self.buf1[y][x]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def reset(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = 0
|
||||
|
||||
def set(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = 1
|
||||
@@ -6,8 +6,44 @@ def delay(n):
|
||||
pass
|
||||
|
||||
rand_seed = 1
|
||||
def rand():
|
||||
def rng():
|
||||
global rand_seed
|
||||
# for these choice of numbers, see P L'Ecuyer, "Tables of linear congruential generators of different sizes and good lattice structure"
|
||||
rand_seed = (rand_seed * 653276) % 8388593
|
||||
return rand_seed
|
||||
|
||||
# LCD testing object for PC
|
||||
# uses double buffering
|
||||
class LCD:
|
||||
def __init__(self, port):
|
||||
self.width = 128
|
||||
self.height = 32
|
||||
self.buf1 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
self.buf2 = [[0 for x in range(self.width)] for y in range(self.height)]
|
||||
|
||||
def light(self, value):
|
||||
pass
|
||||
|
||||
def fill(self, value):
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x] = value
|
||||
|
||||
def show(self):
|
||||
print('') # blank line to separate frames
|
||||
for y in range(self.height):
|
||||
for x in range(self.width):
|
||||
self.buf1[y][x] = self.buf2[y][x]
|
||||
for y in range(self.height):
|
||||
row = ''.join(['*' if self.buf1[y][x] else ' ' for x in range(self.width)])
|
||||
print(row)
|
||||
|
||||
def get(self, x, y):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
return self.buf1[y][x]
|
||||
else:
|
||||
return 0
|
||||
|
||||
def pixel(self, x, y, value):
|
||||
if 0 <= x < self.width and 0 <= y < self.height:
|
||||
self.buf2[y][x] = value
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
try:
|
||||
import microsocket as _socket
|
||||
import usocket as _socket
|
||||
except:
|
||||
import _socket
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
try:
|
||||
import microsocket as socket
|
||||
import usocket as socket
|
||||
except:
|
||||
import socket
|
||||
|
||||
@@ -1,595 +0,0 @@
|
||||
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
|
||||
See "unlicense" statement at the end of this file.
|
||||
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
|
||||
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
|
||||
|
||||
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
|
||||
*/
|
||||
#ifndef TINFL_HEADER_INCLUDED
|
||||
#define TINFL_HEADER_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef unsigned char mz_uint8;
|
||||
typedef signed short mz_int16;
|
||||
typedef unsigned short mz_uint16;
|
||||
typedef unsigned int mz_uint32;
|
||||
typedef unsigned int mz_uint;
|
||||
typedef unsigned long long mz_uint64;
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
|
||||
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
||||
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
|
||||
#define MINIZ_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
|
||||
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
|
||||
#define MINIZ_HAS_64BIT_REGISTERS 1
|
||||
#endif
|
||||
|
||||
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
|
||||
#ifdef _MSC_VER
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#else
|
||||
#define MZ_MACRO_END while (0)
|
||||
#endif
|
||||
|
||||
// Decompression flags used by tinfl_decompress().
|
||||
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
|
||||
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
|
||||
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
|
||||
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
|
||||
enum
|
||||
{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
|
||||
// On entry:
|
||||
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
|
||||
// On return:
|
||||
// Function returns a pointer to the decompressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must free() the returned block when it's no longer needed.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
|
||||
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
|
||||
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
|
||||
// Max size of LZ dictionary.
|
||||
#define TINFL_LZ_DICT_SIZE 32768
|
||||
|
||||
// Return status.
|
||||
typedef enum
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
} tinfl_status;
|
||||
|
||||
// Initializes the decompressor to its initial state.
|
||||
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
|
||||
#define tinfl_get_adler32(r) (r)->m_check_adler32
|
||||
|
||||
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
|
||||
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
|
||||
|
||||
// Internal/private bits follow.
|
||||
// dpgeorge: TINFL_FAST_LOOKUP_BITS can be adjusted to trade off RAM usage against speed.
|
||||
enum
|
||||
{
|
||||
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TINFL_FAST_LOOKUP_BITS = 7, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
} tinfl_huff_table;
|
||||
|
||||
#if MINIZ_HAS_64BIT_REGISTERS
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#endif
|
||||
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
#else
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
#endif
|
||||
|
||||
struct tinfl_decompressor_tag
|
||||
{
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
};
|
||||
|
||||
#endif // #ifdef TINFL_HEADER_INCLUDED
|
||||
|
||||
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
|
||||
|
||||
#ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
|
||||
#ifdef MINIZ_NO_MALLOC
|
||||
#define MZ_MALLOC(x) NULL
|
||||
#define MZ_FREE(x) x, ((void)0)
|
||||
#define MZ_REALLOC(p, x) NULL
|
||||
#else
|
||||
#define MZ_MALLOC(x) malloc(x)
|
||||
#define MZ_FREE(x) free(x)
|
||||
#define MZ_REALLOC(p, x) realloc(p, x)
|
||||
#endif
|
||||
|
||||
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
|
||||
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
|
||||
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
|
||||
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
|
||||
#else
|
||||
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
|
||||
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
||||
#endif
|
||||
|
||||
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
|
||||
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
|
||||
|
||||
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
|
||||
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
|
||||
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
|
||||
#define TINFL_CR_FINISH }
|
||||
|
||||
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
|
||||
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
|
||||
#define TINFL_GET_BYTE(state_index, c) do { \
|
||||
if (pIn_buf_cur >= pIn_buf_end) { \
|
||||
for ( ; ; ) { \
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
|
||||
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
|
||||
if (pIn_buf_cur < pIn_buf_end) { \
|
||||
c = *pIn_buf_cur++; \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
c = 0; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else c = *pIn_buf_cur++; } MZ_MACRO_END
|
||||
|
||||
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
|
||||
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
|
||||
|
||||
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
|
||||
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
|
||||
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
|
||||
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
|
||||
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
|
||||
do { \
|
||||
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
|
||||
if (temp >= 0) { \
|
||||
code_len = temp >> 9; \
|
||||
if ((code_len) && (num_bits >= code_len)) \
|
||||
break; \
|
||||
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; \
|
||||
do { \
|
||||
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
|
||||
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
|
||||
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
|
||||
} while (num_bits < 15);
|
||||
|
||||
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
|
||||
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
|
||||
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
|
||||
// The slow path is only executed at the very end of the input buffer.
|
||||
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
|
||||
int temp; mz_uint code_len, c; \
|
||||
if (num_bits < 15) { \
|
||||
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
|
||||
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
|
||||
} else { \
|
||||
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
|
||||
} \
|
||||
} \
|
||||
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
|
||||
code_len = temp >> 9, temp &= 511; \
|
||||
else { \
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
|
||||
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
|
||||
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
|
||||
{
|
||||
static const mz_uint16 s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
|
||||
static const mz_uint8 s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
|
||||
static const mz_uint16 s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
|
||||
static const mz_uint8 s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
|
||||
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
||||
static const mz_uint16 s_min_table_sizes[3] = { 257, 1, 4 };
|
||||
|
||||
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
|
||||
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
|
||||
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
|
||||
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
|
||||
|
||||
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
|
||||
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
|
||||
|
||||
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
|
||||
TINFL_CR_BEGIN
|
||||
|
||||
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
|
||||
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
|
||||
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
|
||||
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
|
||||
if (r->m_type == 0)
|
||||
{
|
||||
TINFL_SKIP_BITS(5, num_bits & 7);
|
||||
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
|
||||
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
|
||||
while ((counter) && (num_bits))
|
||||
{
|
||||
TINFL_GET_BITS(51, dist, 8);
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)dist;
|
||||
counter--;
|
||||
}
|
||||
while (counter)
|
||||
{
|
||||
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
while (pIn_buf_cur >= pIn_buf_end)
|
||||
{
|
||||
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
|
||||
{
|
||||
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
|
||||
}
|
||||
else
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
|
||||
}
|
||||
}
|
||||
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
|
||||
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
|
||||
}
|
||||
}
|
||||
else if (r->m_type == 3)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->m_type == 1)
|
||||
{
|
||||
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
|
||||
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
|
||||
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
|
||||
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
|
||||
r->m_table_sizes[2] = 19;
|
||||
}
|
||||
for ( ; (int)r->m_type >= 0; r->m_type--)
|
||||
{
|
||||
int tree_next, tree_cur; tinfl_huff_table *pTable;
|
||||
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
|
||||
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
|
||||
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
|
||||
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
|
||||
if ((65536 != total) && (used_syms > 1))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
|
||||
}
|
||||
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
|
||||
{
|
||||
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
|
||||
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
|
||||
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
|
||||
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
|
||||
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
|
||||
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
|
||||
{
|
||||
tree_cur -= ((rev_code >>= 1) & 1);
|
||||
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
|
||||
}
|
||||
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
|
||||
}
|
||||
if (r->m_type == 2)
|
||||
{
|
||||
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
|
||||
{
|
||||
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
|
||||
if ((dist == 16) && (!counter))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
|
||||
}
|
||||
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
|
||||
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
|
||||
}
|
||||
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
|
||||
}
|
||||
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
|
||||
}
|
||||
}
|
||||
for ( ; ; )
|
||||
{
|
||||
mz_uint8 *pSrc;
|
||||
for ( ; ; )
|
||||
{
|
||||
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
|
||||
{
|
||||
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
|
||||
if (counter >= 256)
|
||||
break;
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = (mz_uint8)counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sym2; mz_uint code_len;
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
|
||||
#else
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
|
||||
if (counter & 256)
|
||||
break;
|
||||
|
||||
#if !TINFL_USE_64BIT_BITBUF
|
||||
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
|
||||
#endif
|
||||
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
|
||||
code_len = sym2 >> 9;
|
||||
else
|
||||
{
|
||||
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
|
||||
}
|
||||
bit_buf >>= code_len; num_bits -= code_len;
|
||||
|
||||
pOut_buf_cur[0] = (mz_uint8)counter;
|
||||
if (sym2 & 256)
|
||||
{
|
||||
pOut_buf_cur++;
|
||||
counter = sym2;
|
||||
break;
|
||||
}
|
||||
pOut_buf_cur[1] = (mz_uint8)sym2;
|
||||
pOut_buf_cur += 2;
|
||||
}
|
||||
}
|
||||
if ((counter &= 511) == 256) break;
|
||||
|
||||
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
|
||||
|
||||
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
|
||||
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
|
||||
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
|
||||
|
||||
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
|
||||
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
|
||||
{
|
||||
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
|
||||
}
|
||||
|
||||
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
|
||||
|
||||
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
|
||||
{
|
||||
while (counter--)
|
||||
{
|
||||
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
|
||||
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
|
||||
else if ((counter >= 9) && (counter <= dist))
|
||||
{
|
||||
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
|
||||
do
|
||||
{
|
||||
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
|
||||
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
|
||||
pOut_buf_cur += 8;
|
||||
} while ((pSrc += 8) < pSrc_end);
|
||||
if ((counter &= 7) < 3)
|
||||
{
|
||||
if (counter)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if (counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
do
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur[2] = pSrc[2];
|
||||
pOut_buf_cur += 3; pSrc += 3;
|
||||
} while ((int)(counter -= 3) > 2);
|
||||
if ((int)counter > 0)
|
||||
{
|
||||
pOut_buf_cur[0] = pSrc[0];
|
||||
if ((int)counter > 1)
|
||||
pOut_buf_cur[1] = pSrc[1];
|
||||
pOut_buf_cur += counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!(r->m_final & 1));
|
||||
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
|
||||
{
|
||||
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
|
||||
}
|
||||
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
|
||||
TINFL_CR_FINISH
|
||||
|
||||
common_exit:
|
||||
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
|
||||
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
|
||||
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
|
||||
{
|
||||
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
|
||||
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
|
||||
while (buf_len)
|
||||
{
|
||||
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
|
||||
{
|
||||
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
|
||||
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
|
||||
}
|
||||
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
|
||||
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
|
||||
}
|
||||
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Higher level helper functions.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
|
||||
*pOut_len = 0;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
|
||||
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
src_buf_ofs += src_buf_size;
|
||||
*pOut_len += dst_buf_size;
|
||||
if (status == TINFL_STATUS_DONE) break;
|
||||
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
|
||||
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
|
||||
if (!pNew_buf)
|
||||
{
|
||||
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
|
||||
}
|
||||
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
|
||||
{
|
||||
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
|
||||
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
|
||||
}
|
||||
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
|
||||
{
|
||||
int result = 0;
|
||||
tinfl_decompressor decomp;
|
||||
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
|
||||
if (!pDict)
|
||||
return TINFL_STATUS_FAILED;
|
||||
tinfl_init(&decomp);
|
||||
for ( ; ; )
|
||||
{
|
||||
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
|
||||
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
|
||||
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
|
||||
in_buf_ofs += in_buf_size;
|
||||
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
|
||||
break;
|
||||
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
|
||||
{
|
||||
result = (status == TINFL_STATUS_DONE);
|
||||
break;
|
||||
}
|
||||
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
|
||||
}
|
||||
MZ_FREE(pDict);
|
||||
*pIn_buf_size = in_buf_ofs;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef TINFL_HEADER_FILE_ONLY
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
@@ -101,11 +101,16 @@ enum {
|
||||
|
||||
// Here we need to set sign bit right
|
||||
#define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1)
|
||||
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1));
|
||||
#define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1))
|
||||
// Bit 0 is "is_signed"
|
||||
#define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1))
|
||||
#define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits)
|
||||
|
||||
#define IS_SCALAR_ARRAY(tuple_desc) ((tuple_desc)->len == 2)
|
||||
// We cannot apply the below to INT8, as their range [-128, 127]
|
||||
#define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8)
|
||||
|
||||
// "struct" in uctypes context means "structural", i.e. aggregate, type.
|
||||
STATIC const mp_obj_type_t uctypes_struct_type;
|
||||
|
||||
typedef struct _mp_obj_uctypes_struct_t {
|
||||
@@ -153,6 +158,10 @@ STATIC void uctypes_struct_print(void (*print)(void *env, const char *fmt, ...),
|
||||
print(env, "<struct %s %p>", typen, self->addr);
|
||||
}
|
||||
|
||||
// Get size of any type descriptor
|
||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size);
|
||||
|
||||
// Get size of scalar type descriptor
|
||||
static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
|
||||
if (val_type == FLOAT32) {
|
||||
return 4;
|
||||
@@ -161,11 +170,60 @@ static inline mp_uint_t uctypes_struct_scalar_size(int val_type) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get size of aggregate type descriptor
|
||||
STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, mp_uint_t *max_field_size) {
|
||||
mp_uint_t total_size = 0;
|
||||
|
||||
mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT:
|
||||
return uctypes_struct_size(t->items[1], max_field_size);
|
||||
case PTR:
|
||||
if (sizeof(void*) > *max_field_size) {
|
||||
*max_field_size = sizeof(void*);
|
||||
}
|
||||
return sizeof(void*);
|
||||
case ARRAY: {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
// Elements of array are scalar
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
} else {
|
||||
// Elements of array are aggregates
|
||||
item_s = uctypes_struct_size(t->items[2], max_field_size);
|
||||
}
|
||||
|
||||
return item_s * arr_sz;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size) {
|
||||
mp_obj_dict_t *d = desc_in;
|
||||
mp_uint_t total_size = 0;
|
||||
|
||||
if (!MP_OBJ_IS_TYPE(desc_in, &mp_type_dict)) {
|
||||
if (MP_OBJ_IS_TYPE(desc_in, &mp_type_tuple)) {
|
||||
return uctypes_struct_agg_size((mp_obj_tuple_t*)desc_in, max_field_size);
|
||||
} else if (MP_OBJ_IS_SMALL_INT(desc_in)) {
|
||||
// We allow sizeof on both type definitions and structures/structure fields,
|
||||
// but scalar structure field is lowered into native Python int, so all
|
||||
// type info is lost. So, we cannot say if it's scalar type description,
|
||||
// or such lowered scalar.
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "Cannot unambiguously get sizeof scalar"));
|
||||
}
|
||||
syntax_error();
|
||||
}
|
||||
|
||||
@@ -189,48 +247,10 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size
|
||||
}
|
||||
mp_obj_tuple_t *t = (mp_obj_tuple_t*)v;
|
||||
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
|
||||
mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS);
|
||||
offset &= VALUE_MASK(AGG_TYPE_BITS);
|
||||
|
||||
switch (agg_type) {
|
||||
case STRUCT: {
|
||||
mp_uint_t s = uctypes_struct_size(t->items[1], max_field_size);
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTR: {
|
||||
if (offset + sizeof(void*) > total_size) {
|
||||
total_size = offset + sizeof(void*);
|
||||
}
|
||||
if (sizeof(void*) > *max_field_size) {
|
||||
*max_field_size = sizeof(void*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARRAY: {
|
||||
mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]);
|
||||
uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS);
|
||||
arr_sz &= VALUE_MASK(VAL_TYPE_BITS);
|
||||
mp_uint_t item_s;
|
||||
if (t->len == 2) {
|
||||
item_s = GET_SCALAR_SIZE(val_type);
|
||||
if (item_s > *max_field_size) {
|
||||
*max_field_size = item_s;
|
||||
}
|
||||
} else {
|
||||
item_s = uctypes_struct_size(t->items[2], max_field_size);
|
||||
}
|
||||
|
||||
mp_uint_t byte_sz = item_s * arr_sz;
|
||||
if (offset + byte_sz > total_size) {
|
||||
total_size = offset + byte_sz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
mp_uint_t s = uctypes_struct_agg_size(t, max_field_size);
|
||||
if (offset + s > total_size) {
|
||||
total_size = offset + s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +263,13 @@ STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, mp_uint_t *max_field_size
|
||||
|
||||
STATIC mp_obj_t uctypes_struct_sizeof(mp_obj_t obj_in) {
|
||||
mp_uint_t max_field_size = 0;
|
||||
if (MP_OBJ_IS_TYPE(obj_in, &mp_type_bytearray)) {
|
||||
return mp_obj_len(obj_in);
|
||||
}
|
||||
// We can apply sizeof either to structure definition (a dict)
|
||||
// or to instantiated structure
|
||||
if (MP_OBJ_IS_TYPE(obj_in, &uctypes_struct_type)) {
|
||||
// Extract structure definition
|
||||
mp_obj_uctypes_struct_t *obj = obj_in;
|
||||
obj_in = obj->desc;
|
||||
}
|
||||
@@ -401,7 +427,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
set_aligned_basic(val_type & 6, self->addr + offset, val);
|
||||
} else {
|
||||
mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
|
||||
self->addr + offset, (byte*)&val);
|
||||
self->addr + offset, val);
|
||||
}
|
||||
return set_val; // just !MP_OBJ_NULL
|
||||
}
|
||||
@@ -435,7 +461,14 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
|
||||
o->flags = self->flags;
|
||||
return o;
|
||||
}
|
||||
case PTR: case ARRAY: {
|
||||
case ARRAY: {
|
||||
mp_uint_t dummy;
|
||||
if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) {
|
||||
return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, &dummy), self->addr + offset);
|
||||
}
|
||||
// Fall thru to return uctypes struct object
|
||||
}
|
||||
case PTR: {
|
||||
mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t);
|
||||
o->base.type = &uctypes_struct_type;
|
||||
o->desc = sub;
|
||||
|
||||
138
extmod/moduheapq.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 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 <unistd.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "nlr.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objlist.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
|
||||
// the algorithm here is modelled on CPython's heapq.py
|
||||
|
||||
STATIC mp_obj_list_t *get_heap(mp_obj_t heap_in) {
|
||||
if (!MP_OBJ_IS_TYPE(heap_in, &mp_type_list)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "heap must be a list"));
|
||||
}
|
||||
return heap_in;
|
||||
}
|
||||
|
||||
STATIC void heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
|
||||
mp_obj_t item = heap->items[pos];
|
||||
while (pos > start_pos) {
|
||||
mp_uint_t parent_pos = (pos - 1) >> 1;
|
||||
mp_obj_t parent = heap->items[parent_pos];
|
||||
if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
|
||||
heap->items[pos] = parent;
|
||||
pos = parent_pos;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
}
|
||||
|
||||
STATIC void heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
|
||||
mp_uint_t start_pos = pos;
|
||||
mp_uint_t end_pos = heap->len;
|
||||
mp_obj_t item = heap->items[pos];
|
||||
for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
|
||||
// choose right child if it's <= left child
|
||||
if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
|
||||
child_pos += 1;
|
||||
}
|
||||
// bubble up the smaller child
|
||||
heap->items[pos] = heap->items[child_pos];
|
||||
pos = child_pos;
|
||||
}
|
||||
heap->items[pos] = item;
|
||||
heap_siftdown(heap, start_pos, pos);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
mp_obj_list_append(heap, item);
|
||||
heap_siftdown(heap, 0, heap->len - 1);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
if (heap->len == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "empty heap"));
|
||||
}
|
||||
mp_obj_t item = heap->items[0];
|
||||
heap->len -= 1;
|
||||
heap->items[0] = heap->items[heap->len];
|
||||
heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
|
||||
if (heap->len) {
|
||||
heap_siftup(heap, 0);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
|
||||
|
||||
STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
|
||||
mp_obj_list_t *heap = get_heap(heap_in);
|
||||
for (mp_uint_t i = heap->len / 2; i > 0;) {
|
||||
heap_siftup(heap, --i);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uheapq_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uheapq) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappush), (mp_obj_t)&mod_uheapq_heappush_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heappop), (mp_obj_t)&mod_uheapq_heappop_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapify), (mp_obj_t)&mod_uheapq_heapify_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uheapq_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uheapq_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uheapq_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uheapq = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uheapq,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uheapq_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_UHEAPQ
|
||||
250
extmod/modure.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "nlr.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
#include "binary.h"
|
||||
|
||||
#if MICROPY_PY_URE
|
||||
|
||||
#include "re1.5/re1.5.h"
|
||||
|
||||
#define FLAG_DEBUG 0x1000
|
||||
|
||||
typedef struct _mp_obj_re_t {
|
||||
mp_obj_base_t base;
|
||||
ByteProg re;
|
||||
} mp_obj_re_t;
|
||||
|
||||
typedef struct _mp_obj_match_t {
|
||||
mp_obj_base_t base;
|
||||
int num_matches;
|
||||
mp_obj_t str;
|
||||
const char *caps[0];
|
||||
} mp_obj_match_t;
|
||||
|
||||
|
||||
STATIC void match_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_match_t *self = self_in;
|
||||
print(env, "<match num=%d @%p>", self->num_matches);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
|
||||
mp_obj_match_t *self = self_in;
|
||||
mp_int_t no = mp_obj_int_get(no_in);
|
||||
if (no < 0 || no >= self->num_matches / 2) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_IndexError, no_in));
|
||||
}
|
||||
|
||||
const char *start = self->caps[no * 2];
|
||||
return mp_obj_new_str(start, self->caps[no * 2 + 1] - start, false);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);
|
||||
|
||||
STATIC const mp_map_elem_t match_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_group), (mp_obj_t) &match_group_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t match_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_match,
|
||||
.print = match_print,
|
||||
.locals_dict = (mp_obj_t)&match_locals_dict,
|
||||
};
|
||||
|
||||
STATIC void re_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_obj_re_t *self = self_in;
|
||||
print(env, "<re %p>", self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = args[0];
|
||||
Subject subj;
|
||||
mp_uint_t len;
|
||||
subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||
subj.end = subj.begin + len;
|
||||
int caps_num = (self->re.sub + 1) * 2;
|
||||
mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char*, caps_num);
|
||||
int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
|
||||
if (res == 0) {
|
||||
m_del_var(mp_obj_match_t, char*, caps_num, match);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
match->base.type = &match_type;
|
||||
match->num_matches = caps_num;
|
||||
match->str = args[1];
|
||||
return match;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t re_match(uint n_args, const mp_obj_t *args) {
|
||||
return re_exec(true, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
|
||||
|
||||
STATIC mp_obj_t re_search(uint n_args, const mp_obj_t *args) {
|
||||
return re_exec(false, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
|
||||
|
||||
STATIC mp_obj_t re_split(uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = args[0];
|
||||
Subject subj;
|
||||
mp_uint_t len;
|
||||
subj.begin = mp_obj_str_get_data(args[1], &len);
|
||||
subj.end = subj.begin + len;
|
||||
int caps_num = (self->re.sub + 1) * 2;
|
||||
|
||||
int maxsplit = 0;
|
||||
if (n_args > 2) {
|
||||
maxsplit = mp_obj_int_get(args[2]);
|
||||
}
|
||||
|
||||
mp_obj_t retval = mp_obj_new_list(0, NULL);
|
||||
const char *caps[caps_num];
|
||||
while (true) {
|
||||
int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
|
||||
|
||||
// if we didn't have a match, or had an empty match, it's time to stop
|
||||
if (!res || caps[0] == caps[1]) {
|
||||
break;
|
||||
}
|
||||
|
||||
mp_obj_t s = mp_obj_new_str(subj.begin, caps[0] - subj.begin, false);
|
||||
mp_obj_list_append(retval, s);
|
||||
if (self->re.sub > 0) {
|
||||
mp_not_implemented("Splitting with sub-captures");
|
||||
}
|
||||
subj.begin = caps[1];
|
||||
if (maxsplit > 0 && --maxsplit == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t s = mp_obj_new_str(subj.begin, subj.end - subj.begin, false);
|
||||
mp_obj_list_append(retval, s);
|
||||
return retval;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
|
||||
|
||||
STATIC const mp_map_elem_t re_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_match), (mp_obj_t) &re_match_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_search), (mp_obj_t) &re_search_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_split), (mp_obj_t) &re_split_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t re_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ure,
|
||||
.print = re_print,
|
||||
.locals_dict = (mp_obj_t)&re_locals_dict,
|
||||
};
|
||||
|
||||
mp_obj_t mod_re_compile(uint n_args, const mp_obj_t *args) {
|
||||
const char *re_str = mp_obj_str_get_str(args[0]);
|
||||
int size = re1_5_sizecode(re_str);
|
||||
mp_obj_re_t *o = m_new_obj_var(mp_obj_re_t, char, size);
|
||||
o->base.type = &re_type;
|
||||
int flags = 0;
|
||||
if (n_args > 1) {
|
||||
flags = mp_obj_get_int(args[1]);
|
||||
}
|
||||
int error = re1_5_compilecode(&o->re, re_str);
|
||||
if (error != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Error in regex"));
|
||||
}
|
||||
if (flags & FLAG_DEBUG) {
|
||||
re1_5_dumpcode(&o->re);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
|
||||
|
||||
STATIC mp_obj_t mod_re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
|
||||
mp_obj_re_t *self = mod_re_compile(1, args);
|
||||
|
||||
const mp_obj_t args2[] = {self, args[1]};
|
||||
mp_obj_match_t *match = re_exec(is_anchored, 2, args2);
|
||||
return match;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_re_match(uint n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(true, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_match_obj, 2, 4, mod_re_match);
|
||||
|
||||
STATIC mp_obj_t mod_re_search(uint n_args, const mp_obj_t *args) {
|
||||
return mod_re_exec(false, n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_search_obj, 2, 4, mod_re_search);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_re_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ure) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mod_re_compile_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_match), (mp_obj_t)&mod_re_match_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_search), (mp_obj_t)&mod_re_search_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG), MP_OBJ_NEW_SMALL_INT(FLAG_DEBUG) },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_re_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_re_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_re_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_re_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_ure = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ure,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_re_globals,
|
||||
};
|
||||
|
||||
// Source files #include'd here to make sure they're compiled in
|
||||
// only if module is enabled by config setting.
|
||||
|
||||
#define re1_5_fatal(x) assert(!x)
|
||||
#include "re1.5/compilecode.c"
|
||||
#include "re1.5/dumpcode.c"
|
||||
#include "re1.5/recursiveloop.c"
|
||||
#include "re1.5/charclass.c"
|
||||
|
||||
#endif //MICROPY_PY_URE
|
||||
114
extmod/moduzlib.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "nlr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_UZLIB
|
||||
|
||||
#include "uzlib/tinf.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) {
|
||||
if (alloc_req < 256) {
|
||||
alloc_req = 256;
|
||||
}
|
||||
DEBUG_printf("uzlib: Resizing buffer to " UINT_FMT " bytes\n", d->destSize + alloc_req);
|
||||
d->destStart = m_renew(byte, d->destStart, d->destSize, d->destSize + alloc_req);
|
||||
d->destSize += alloc_req;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mod_uzlib_decompress(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
|
||||
TINF_DATA *decomp = m_new_obj(TINF_DATA);
|
||||
DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp));
|
||||
|
||||
decomp->destStart = m_new(byte, bufinfo.len);
|
||||
decomp->destSize = bufinfo.len;
|
||||
decomp->destGrow = mod_uzlib_grow_buf;
|
||||
decomp->source = bufinfo.buf;
|
||||
|
||||
int st = tinf_zlib_uncompress_dyn(decomp, bufinfo.len);
|
||||
if (st != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)));
|
||||
}
|
||||
|
||||
mp_obj_t res = mp_obj_new_bytearray_by_ref(decomp->dest - decomp->destStart, decomp->destStart);
|
||||
m_del_obj(TINF_DATA, decomp);
|
||||
return res;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_uzlib_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uzlib) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_uzlib_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_uzlib_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_uzlib_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_uzlib_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_uzlib_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_uzlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uzlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_uzlib_globals,
|
||||
};
|
||||
|
||||
// Source files #include'd here to make sure they're compiled in
|
||||
// only if module is enabled by config setting.
|
||||
|
||||
#include "uzlib/tinflate.c"
|
||||
#include "uzlib/tinfzlib.c"
|
||||
#include "uzlib/adler32.c"
|
||||
|
||||
#endif // MICROPY_PY_UZLIB
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Paul Sokolovsky
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpconfig.h"
|
||||
#include "misc.h"
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "runtime.h"
|
||||
|
||||
#if MICROPY_PY_ZLIBD
|
||||
|
||||
#include "miniz/tinfl.c"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_printf DEBUG_printf
|
||||
#else // don't print debugging info
|
||||
#define DEBUG_printf(...) (void)0
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t mod_zlibd_decompress(uint n_args, mp_obj_t *args) {
|
||||
mp_obj_t data = args[0];
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
tinfl_decompressor *decomp = m_new_obj(tinfl_decompressor);
|
||||
tinfl_init(decomp);
|
||||
DEBUG_printf("sizeof(tinfl_decompressor)=" UINT_FMT "\n", sizeof(tinfl_decompressor));
|
||||
|
||||
byte *out = m_new(byte, bufinfo.len);
|
||||
size_t out_len = bufinfo.len;
|
||||
size_t in_buf_ofs = 0, dst_buf_ofs = 0;
|
||||
size_t dst_buf_sz = bufinfo.len;
|
||||
|
||||
while (1) {
|
||||
size_t in_buf_sz = bufinfo.len - in_buf_ofs;
|
||||
DEBUG_printf("tinfl in: in_ofs=%d in_sz=%d dst_ofs=%d, dst_sz=%d\n", in_buf_ofs, in_buf_sz, dst_buf_ofs, dst_buf_sz);
|
||||
tinfl_status st = tinfl_decompress(decomp,
|
||||
(mz_uint8*) bufinfo.buf + in_buf_ofs, &in_buf_sz,
|
||||
out, out + dst_buf_ofs, &dst_buf_sz,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
DEBUG_printf("tinfl out: st=%d, in_sz=%d, out_sz=%d\n", st, in_buf_sz, dst_buf_sz);
|
||||
in_buf_ofs += in_buf_sz;
|
||||
dst_buf_ofs += dst_buf_sz;
|
||||
if (st != TINFL_STATUS_HAS_MORE_OUTPUT) {
|
||||
break;
|
||||
}
|
||||
out = m_renew(byte, out, out_len, dst_buf_ofs + 256);
|
||||
out_len = dst_buf_ofs + 256;
|
||||
dst_buf_sz = out_len - dst_buf_ofs;
|
||||
}
|
||||
|
||||
m_del_obj(tinfl_decompressor, decomp);
|
||||
return mp_obj_new_bytearray_by_ref(dst_buf_ofs, out);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_zlibd_decompress_obj, 1, 3, mod_zlibd_decompress);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_zlibd_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_zlibd) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_decompress), (mp_obj_t)&mod_zlibd_decompress_obj },
|
||||
};
|
||||
|
||||
STATIC const mp_obj_dict_t mp_module_zlibd_globals = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_module_zlibd_globals_table),
|
||||
.table = (mp_map_elem_t*)mp_module_zlibd_globals_table,
|
||||
},
|
||||
};
|
||||
|
||||
const mp_obj_module_t mp_module_zlibd = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_zlibd,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_zlibd_globals,
|
||||
};
|
||||
|
||||
#endif //MICROPY_PY_ZLIBD
|
||||
13
extmod/re1.5/charclass.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "re1.5.h"
|
||||
|
||||
int _re1_5_classmatch(const char *pc, const char *sp)
|
||||
{
|
||||
// pc points to "cnt" byte after opcode
|
||||
int is_positive = (pc[-1] == Class);
|
||||
int cnt = *pc++;
|
||||
while (cnt--) {
|
||||
if (*sp >= *pc && *sp <= pc[1]) return is_positive;
|
||||
pc += 2;
|
||||
}
|
||||
return !is_positive;
|
||||
}
|
||||
249
extmod/re1.5/compilecode.c
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
static void insert_code(char *code, int at, int num, int *pc)
|
||||
{
|
||||
memmove(code + at + num, code + at, *pc - at);
|
||||
*pc += num;
|
||||
}
|
||||
|
||||
#define REL(at, to) (to - at - 2)
|
||||
|
||||
int re1_5_sizecode(const char *re)
|
||||
{
|
||||
int pc = 5 + NON_ANCHORED_PREFIX; // Save 0, Save 1, Match; more bytes for "search" (vs "match") prefix code
|
||||
|
||||
for (; *re; re++) {
|
||||
switch (*re) {
|
||||
case '\\':
|
||||
re++;
|
||||
default:
|
||||
pc += 2;
|
||||
break;
|
||||
case '+':
|
||||
// Skip entire "+?"
|
||||
if (re[1] == '?')
|
||||
re++;
|
||||
case '?':
|
||||
pc += 2;
|
||||
break;
|
||||
case '.':
|
||||
case '^':
|
||||
case '$':
|
||||
pc++;
|
||||
break;
|
||||
case '*':
|
||||
// Skip entire "*?"
|
||||
if (re[1] == '?')
|
||||
re++;
|
||||
case '|':
|
||||
case '(':
|
||||
pc += 4;
|
||||
break;
|
||||
case ')':
|
||||
break;
|
||||
case '[': {
|
||||
pc += 2;
|
||||
re++;
|
||||
if (*re == '^') re++;
|
||||
while (*re != ']') {
|
||||
if (!*re) return -1;
|
||||
if (re[1] == '-') {
|
||||
re += 2;
|
||||
}
|
||||
pc += 2;
|
||||
re++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
#define EMIT(at, byte) code[at] = byte
|
||||
|
||||
const char *_compilecode(const char *re, ByteProg *prog)
|
||||
{
|
||||
char *code = prog->insts;
|
||||
int pc = prog->bytelen;
|
||||
int start = pc;
|
||||
int term = pc;
|
||||
int alt_label = 0;
|
||||
|
||||
for (; *re && *re != ')'; re++) {
|
||||
switch (*re) {
|
||||
case '\\':
|
||||
re++;
|
||||
default:
|
||||
term = pc;
|
||||
EMIT(pc++, Char);
|
||||
EMIT(pc++, *re);
|
||||
prog->len++;
|
||||
break;
|
||||
case '.':
|
||||
term = pc;
|
||||
EMIT(pc++, Any);
|
||||
prog->len++;
|
||||
break;
|
||||
case '[': {
|
||||
int cnt;
|
||||
term = pc;
|
||||
re++;
|
||||
if (*re == '^') {
|
||||
EMIT(pc++, ClassNot);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(pc++, Class);
|
||||
}
|
||||
pc++; // Skip # of pair byte
|
||||
prog->len++;
|
||||
for (cnt = 0; *re != ']'; re++, cnt++) {
|
||||
if (!*re) return NULL;
|
||||
EMIT(pc++, *re);
|
||||
if (re[1] == '-') {
|
||||
re += 2;
|
||||
}
|
||||
EMIT(pc++, *re);
|
||||
}
|
||||
EMIT(term + 1, cnt);
|
||||
break;
|
||||
}
|
||||
case '(':
|
||||
term = pc;
|
||||
|
||||
EMIT(pc++, Save);
|
||||
EMIT(pc++, 2 * ++prog->sub);
|
||||
prog->len++;
|
||||
|
||||
prog->bytelen = pc;
|
||||
re = _compilecode(re + 1, prog);
|
||||
pc = prog->bytelen;
|
||||
|
||||
EMIT(pc++, Save);
|
||||
EMIT(pc++, 2 * prog->sub + 1);
|
||||
prog->len++;
|
||||
|
||||
break;
|
||||
case '?':
|
||||
insert_code(code, term, 2, &pc);
|
||||
EMIT(term, Split);
|
||||
EMIT(term + 1, REL(term, pc));
|
||||
prog->len++;
|
||||
break;
|
||||
case '*':
|
||||
insert_code(code, term, 2, &pc);
|
||||
EMIT(pc, Jmp);
|
||||
EMIT(pc + 1, REL(pc, term));
|
||||
pc += 2;
|
||||
if (re[1] == '?') {
|
||||
EMIT(term, RSplit);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(term, Split);
|
||||
}
|
||||
EMIT(term + 1, REL(term, pc));
|
||||
prog->len += 2;
|
||||
break;
|
||||
case '+':
|
||||
if (re[1] == '?') {
|
||||
EMIT(pc, Split);
|
||||
re++;
|
||||
} else {
|
||||
EMIT(pc, RSplit);
|
||||
}
|
||||
EMIT(pc + 1, REL(pc, term));
|
||||
pc += 2;
|
||||
prog->len++;
|
||||
break;
|
||||
case '|':
|
||||
if (alt_label) {
|
||||
EMIT(alt_label, REL(alt_label, pc) + 1);
|
||||
}
|
||||
insert_code(code, start, 2, &pc);
|
||||
EMIT(pc++, Jmp);
|
||||
alt_label = pc++;
|
||||
EMIT(start, Split);
|
||||
EMIT(start + 1, REL(start, pc));
|
||||
prog->len += 2;
|
||||
break;
|
||||
case '^':
|
||||
EMIT(pc++, Bol);
|
||||
prog->len++;
|
||||
break;
|
||||
case '$':
|
||||
EMIT(pc++, Eol);
|
||||
prog->len++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alt_label) {
|
||||
EMIT(alt_label, REL(alt_label, pc) + 1);
|
||||
}
|
||||
prog->bytelen = pc;
|
||||
return re;
|
||||
}
|
||||
|
||||
int re1_5_compilecode(ByteProg *prog, const char *re)
|
||||
{
|
||||
prog->len = 0;
|
||||
prog->bytelen = 0;
|
||||
prog->sub = 0;
|
||||
|
||||
// Add code to implement non-anchored operation ("search"),
|
||||
// for anchored operation ("match"), this code will be just skipped.
|
||||
// TODO: Implement search in much more efficient manner
|
||||
prog->insts[prog->bytelen++] = RSplit;
|
||||
prog->insts[prog->bytelen++] = 3;
|
||||
prog->insts[prog->bytelen++] = Any;
|
||||
prog->insts[prog->bytelen++] = Jmp;
|
||||
prog->insts[prog->bytelen++] = -5;
|
||||
prog->len += 3;
|
||||
|
||||
prog->insts[prog->bytelen++] = Save;
|
||||
prog->insts[prog->bytelen++] = 0;
|
||||
prog->len++;
|
||||
|
||||
_compilecode(re, prog);
|
||||
|
||||
prog->insts[prog->bytelen++] = Save;
|
||||
prog->insts[prog->bytelen++] = 1;
|
||||
prog->len++;
|
||||
|
||||
prog->insts[prog->bytelen++] = Match;
|
||||
prog->len++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cleanmarks(ByteProg *prog)
|
||||
{
|
||||
char *pc = prog->insts;
|
||||
char *end = pc + prog->bytelen;
|
||||
while (pc < end) {
|
||||
*pc &= 0x7f;
|
||||
switch (*pc) {
|
||||
case Jmp:
|
||||
case Split:
|
||||
case RSplit:
|
||||
case Save:
|
||||
case Char:
|
||||
pc++;
|
||||
}
|
||||
pc++;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int pc = 0;
|
||||
ByteProg *code = re1_5_compilecode(argv[1]);
|
||||
re1_5_dumpcode(code);
|
||||
}
|
||||
#endif
|
||||
62
extmod/re1.5/dumpcode.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
void re1_5_dumpcode(ByteProg *prog)
|
||||
{
|
||||
int pc = 0;
|
||||
char *code = prog->insts;
|
||||
while (pc < prog->bytelen) {
|
||||
printf("%2d: ", pc);
|
||||
switch(code[pc++]) {
|
||||
default:
|
||||
assert(0);
|
||||
// re1_5_fatal("printprog");
|
||||
case Split:
|
||||
printf("split %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case RSplit:
|
||||
printf("rsplit %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case Jmp:
|
||||
printf("jmp %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]);
|
||||
pc++;
|
||||
break;
|
||||
case Char:
|
||||
printf("char %c\n", code[pc++]);
|
||||
break;
|
||||
case Any:
|
||||
printf("any\n");
|
||||
break;
|
||||
case Class:
|
||||
case ClassNot: {
|
||||
int num = code[pc];
|
||||
printf("class%s %d", (code[pc - 1] == ClassNot ? "not" : ""), num);
|
||||
pc++;
|
||||
while (num--) {
|
||||
printf(" 0x%02x-0x%02x", code[pc], code[pc + 1]);
|
||||
pc += 2;
|
||||
}
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
case Match:
|
||||
printf("match\n");
|
||||
break;
|
||||
case Save:
|
||||
printf("save %d\n", (unsigned char)code[pc++]);
|
||||
break;
|
||||
case Bol:
|
||||
printf("assert bol\n");
|
||||
break;
|
||||
case Eol:
|
||||
printf("assert eol\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Bytes: %d, insts: %d\n", prog->bytelen, prog->len);
|
||||
}
|
||||
149
extmod/re1.5/re1.5.h
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2007-2009 Russ Cox. All Rights Reserved.
|
||||
// Copyright 2014 Paul Sokolovsky.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef _RE1_5_REGEXP__H
|
||||
#define _RE1_5_REGEXP__H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define nil ((void*)0)
|
||||
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
typedef struct Regexp Regexp;
|
||||
typedef struct Prog Prog;
|
||||
typedef struct ByteProg ByteProg;
|
||||
typedef struct Inst Inst;
|
||||
typedef struct Subject Subject;
|
||||
|
||||
struct Regexp
|
||||
{
|
||||
int type;
|
||||
int n;
|
||||
int ch;
|
||||
Regexp *left;
|
||||
Regexp *right;
|
||||
};
|
||||
|
||||
enum /* Regexp.type */
|
||||
{
|
||||
Alt = 1,
|
||||
Cat,
|
||||
Lit,
|
||||
Dot,
|
||||
Paren,
|
||||
Quest,
|
||||
Star,
|
||||
Plus,
|
||||
};
|
||||
|
||||
Regexp *parse(char*);
|
||||
Regexp *reg(int type, Regexp *left, Regexp *right);
|
||||
void printre(Regexp*);
|
||||
#ifndef re1_5_fatal
|
||||
void re1_5_fatal(char*);
|
||||
#endif
|
||||
void *mal(int);
|
||||
|
||||
struct Prog
|
||||
{
|
||||
Inst *start;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct ByteProg
|
||||
{
|
||||
int bytelen;
|
||||
int len;
|
||||
int sub;
|
||||
char insts[0];
|
||||
};
|
||||
|
||||
struct Inst
|
||||
{
|
||||
int opcode;
|
||||
int c;
|
||||
int n;
|
||||
Inst *x;
|
||||
Inst *y;
|
||||
int gen; // global state, oooh!
|
||||
};
|
||||
|
||||
enum /* Inst.opcode */
|
||||
{
|
||||
// Instructions which consume input bytes (and thus fail if none left)
|
||||
CONSUMERS = 1,
|
||||
Char = CONSUMERS,
|
||||
Any,
|
||||
Class,
|
||||
ClassNot,
|
||||
|
||||
ASSERTS = 0x50,
|
||||
Bol = ASSERTS,
|
||||
Eol,
|
||||
|
||||
// Instructions which take relative offset as arg
|
||||
JUMPS = 0x60,
|
||||
Jmp = JUMPS,
|
||||
Split,
|
||||
RSplit,
|
||||
|
||||
// Other (special) instructions
|
||||
Save = 0x7e,
|
||||
Match = 0x7f,
|
||||
};
|
||||
|
||||
#define inst_is_consumer(inst) ((inst) < ASSERTS)
|
||||
#define inst_is_jump(inst) ((inst) & 0x70 == JUMPS)
|
||||
|
||||
Prog *compile(Regexp*);
|
||||
void printprog(Prog*);
|
||||
|
||||
extern int gen;
|
||||
|
||||
enum {
|
||||
MAXSUB = 20
|
||||
};
|
||||
|
||||
typedef struct Sub Sub;
|
||||
|
||||
struct Sub
|
||||
{
|
||||
int ref;
|
||||
int nsub;
|
||||
const char *sub[MAXSUB];
|
||||
};
|
||||
|
||||
Sub *newsub(int n);
|
||||
Sub *incref(Sub*);
|
||||
Sub *copy(Sub*);
|
||||
Sub *update(Sub*, int, const char*);
|
||||
void decref(Sub*);
|
||||
|
||||
struct Subject {
|
||||
const char *begin;
|
||||
const char *end;
|
||||
};
|
||||
|
||||
|
||||
#define NON_ANCHORED_PREFIX 5
|
||||
#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode))
|
||||
|
||||
int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_recursiveloopprog(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_recursiveprog(ByteProg*, Subject*, const char**, int, int);
|
||||
int re1_5_thompsonvm(ByteProg*, Subject*, const char**, int, int);
|
||||
|
||||
int re1_5_sizecode(const char *re);
|
||||
int re1_5_compilecode(ByteProg *prog, const char *re);
|
||||
void re1_5_dumpcode(ByteProg *prog);
|
||||
void cleanmarks(ByteProg *prog);
|
||||
int _re1_5_classmatch(const char *pc, const char *sp);
|
||||
|
||||
#endif /*_RE1_5_REGEXP__H*/
|
||||
78
extmod/re1.5/recursiveloop.c
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2007-2009 Russ Cox. All Rights Reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "re1.5.h"
|
||||
|
||||
static int
|
||||
recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int nsubp)
|
||||
{
|
||||
const char *old;
|
||||
int off;
|
||||
|
||||
for(;;) {
|
||||
if(inst_is_consumer(*pc)) {
|
||||
// If we need to match a character, but there's none left, it's fail
|
||||
if(sp >= input->end)
|
||||
return 0;
|
||||
}
|
||||
switch(*pc++) {
|
||||
case Char:
|
||||
if(*sp != *pc++)
|
||||
return 0;
|
||||
case Any:
|
||||
sp++;
|
||||
continue;
|
||||
case Class:
|
||||
case ClassNot:
|
||||
if (!_re1_5_classmatch(pc, sp))
|
||||
return 0;
|
||||
pc += *(unsigned char*)pc * 2 + 1;
|
||||
sp++;
|
||||
continue;
|
||||
case Match:
|
||||
return 1;
|
||||
case Jmp:
|
||||
off = (signed char)*pc++;
|
||||
pc = pc + off;
|
||||
continue;
|
||||
case Split:
|
||||
off = (signed char)*pc++;
|
||||
if(recursiveloop(pc, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
pc = pc + off;
|
||||
continue;
|
||||
case RSplit:
|
||||
off = (signed char)*pc++;
|
||||
if(recursiveloop(pc + off, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
continue;
|
||||
case Save:
|
||||
off = (unsigned char)*pc++;
|
||||
if(off >= nsubp) {
|
||||
continue;
|
||||
}
|
||||
old = subp[off];
|
||||
subp[off] = sp;
|
||||
if(recursiveloop(pc, sp, input, subp, nsubp))
|
||||
return 1;
|
||||
subp[off] = old;
|
||||
return 0;
|
||||
case Bol:
|
||||
if(sp != input->begin)
|
||||
return 0;
|
||||
continue;
|
||||
case Eol:
|
||||
if(sp != input->end)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
re1_5_fatal("recursiveloop");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
re1_5_recursiveloopprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored)
|
||||
{
|
||||
return recursiveloop(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp);
|
||||
}
|
||||
78
extmod/uzlib/adler32.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Adler-32 checksum
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adler-32 algorithm taken from the zlib source, which is
|
||||
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
#define A32_BASE 65521
|
||||
#define A32_NMAX 5552
|
||||
|
||||
unsigned int tinf_adler32(const void *data, unsigned int length)
|
||||
{
|
||||
const unsigned char *buf = (const unsigned char *)data;
|
||||
|
||||
unsigned int s1 = 1;
|
||||
unsigned int s2 = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int k = length < A32_NMAX ? length : A32_NMAX;
|
||||
int i;
|
||||
|
||||
for (i = k / 16; i; --i, buf += 16)
|
||||
{
|
||||
s1 += buf[0]; s2 += s1; s1 += buf[1]; s2 += s1;
|
||||
s1 += buf[2]; s2 += s1; s1 += buf[3]; s2 += s1;
|
||||
s1 += buf[4]; s2 += s1; s1 += buf[5]; s2 += s1;
|
||||
s1 += buf[6]; s2 += s1; s1 += buf[7]; s2 += s1;
|
||||
|
||||
s1 += buf[8]; s2 += s1; s1 += buf[9]; s2 += s1;
|
||||
s1 += buf[10]; s2 += s1; s1 += buf[11]; s2 += s1;
|
||||
s1 += buf[12]; s2 += s1; s1 += buf[13]; s2 += s1;
|
||||
s1 += buf[14]; s2 += s1; s1 += buf[15]; s2 += s1;
|
||||
}
|
||||
|
||||
for (i = k % 16; i; --i) { s1 += *buf++; s2 += s1; }
|
||||
|
||||
s1 %= A32_BASE;
|
||||
s2 %= A32_BASE;
|
||||
|
||||
length -= k;
|
||||
}
|
||||
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
102
extmod/uzlib/tinf.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*/
|
||||
|
||||
#ifndef TINF_H_INCLUDED
|
||||
#define TINF_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* calling convention */
|
||||
#ifndef TINFCC
|
||||
#ifdef __WATCOMC__
|
||||
#define TINFCC __cdecl
|
||||
#else
|
||||
#define TINFCC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TINF_OK 0
|
||||
#define TINF_DATA_ERROR (-3)
|
||||
#define TINF_DEST_OVERFLOW (-4)
|
||||
|
||||
/* data structures */
|
||||
|
||||
typedef struct {
|
||||
unsigned short table[16]; /* table of code length counts */
|
||||
unsigned short trans[288]; /* code -> symbol translation table */
|
||||
} TINF_TREE;
|
||||
|
||||
struct TINF_DATA;
|
||||
typedef struct TINF_DATA {
|
||||
const unsigned char *source;
|
||||
unsigned int tag;
|
||||
unsigned int bitcount;
|
||||
|
||||
/* Buffer start */
|
||||
unsigned char *destStart;
|
||||
/* Buffer total size */
|
||||
unsigned int destSize;
|
||||
/* Current pointer in buffer */
|
||||
unsigned char *dest;
|
||||
/* Remaining bytes in buffer */
|
||||
unsigned int destRemaining;
|
||||
/* Argument is the allocation size which didn't fit into buffer. Note that
|
||||
exact mimumum size to grow buffer by is lastAlloc - destRemaining. But
|
||||
growing by this exact size is ineficient, as the next allocation will
|
||||
fail again. */
|
||||
int (*destGrow)(struct TINF_DATA *data, unsigned int lastAlloc);
|
||||
|
||||
TINF_TREE ltree; /* dynamic length/symbol tree */
|
||||
TINF_TREE dtree; /* dynamic distance tree */
|
||||
} TINF_DATA;
|
||||
|
||||
|
||||
/* low-level API */
|
||||
|
||||
/* Step 1: Allocate TINF_DATA structure */
|
||||
/* Step 2: Set destStart, destSize, and destGrow fields */
|
||||
/* Step 3: Set source field */
|
||||
/* Step 4: Call tinf_uncompress_dyn() */
|
||||
/* Step 5: In response to destGrow callback, update destStart and destSize fields */
|
||||
/* Step 6: When tinf_uncompress_dyn() returns, buf.dest points to a byte past last uncompressed byte */
|
||||
|
||||
int TINFCC tinf_uncompress_dyn(TINF_DATA *d);
|
||||
int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen);
|
||||
|
||||
/* high-level API */
|
||||
|
||||
void TINFCC tinf_init();
|
||||
|
||||
int TINFCC tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen);
|
||||
|
||||
unsigned int TINFCC tinf_adler32(const void *data, unsigned int length);
|
||||
|
||||
unsigned int TINFCC tinf_crc32(const void *data, unsigned int length);
|
||||
|
||||
/* compression API */
|
||||
|
||||
void TINFCC tinf_compress(void *data, const uint8_t *src, unsigned slen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* TINF_H_INCLUDED */
|
||||
511
extmod/uzlib/tinflate.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* tinflate - tiny inflate
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* Copyright (c) 2014 by Paul Sokolovsky
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
/* --------------------------------------------------- *
|
||||
* -- uninitialized global data (static structures) -- *
|
||||
* --------------------------------------------------- */
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
|
||||
/* extra bits and base tables for length codes */
|
||||
unsigned char length_bits[30];
|
||||
unsigned short length_base[30];
|
||||
|
||||
/* extra bits and base tables for distance codes */
|
||||
unsigned char dist_bits[30];
|
||||
unsigned short dist_base[30];
|
||||
|
||||
#else
|
||||
|
||||
const unsigned char length_bits[30] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 2, 2, 2, 2,
|
||||
3, 3, 3, 3, 4, 4, 4, 4,
|
||||
5, 5, 5, 5
|
||||
};
|
||||
const unsigned short length_base[30] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 13, 15, 17, 19, 23, 27, 31,
|
||||
35, 43, 51, 59, 67, 83, 99, 115,
|
||||
131, 163, 195, 227, 258
|
||||
};
|
||||
|
||||
const unsigned char dist_bits[30] = {
|
||||
0, 0, 0, 0, 1, 1, 2, 2,
|
||||
3, 3, 4, 4, 5, 5, 6, 6,
|
||||
7, 7, 8, 8, 9, 9, 10, 10,
|
||||
11, 11, 12, 12, 13, 13
|
||||
};
|
||||
const unsigned short dist_base[30] = {
|
||||
1, 2, 3, 4, 5, 7, 9, 13,
|
||||
17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073,
|
||||
4097, 6145, 8193, 12289, 16385, 24577
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* special ordering of code length codes */
|
||||
const unsigned char clcidx[] = {
|
||||
16, 17, 18, 0, 8, 7, 9, 6,
|
||||
10, 5, 11, 4, 12, 3, 13, 2,
|
||||
14, 1, 15
|
||||
};
|
||||
|
||||
/* ----------------------- *
|
||||
* -- utility functions -- *
|
||||
* ----------------------- */
|
||||
|
||||
/* Execute callback to grow destination buffer */
|
||||
static int tinf_grow_dest_buf(TINF_DATA *d, unsigned int lastAlloc)
|
||||
{
|
||||
unsigned int oldsize = d->dest - d->destStart;
|
||||
/* This will update only destStart and destSize */
|
||||
if (!d->destGrow)
|
||||
{
|
||||
return TINF_DEST_OVERFLOW;
|
||||
}
|
||||
d->destGrow(d, lastAlloc);
|
||||
d->dest = d->destStart + oldsize;
|
||||
d->destRemaining = d->destSize - oldsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
|
||||
{
|
||||
int i, sum;
|
||||
|
||||
/* build bits table */
|
||||
for (i = 0; i < delta; ++i) bits[i] = 0;
|
||||
for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
|
||||
|
||||
/* build base table */
|
||||
for (sum = first, i = 0; i < 30; ++i)
|
||||
{
|
||||
base[i] = sum;
|
||||
sum += 1 << bits[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* build the fixed huffman trees */
|
||||
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* build fixed length tree */
|
||||
for (i = 0; i < 7; ++i) lt->table[i] = 0;
|
||||
|
||||
lt->table[7] = 24;
|
||||
lt->table[8] = 152;
|
||||
lt->table[9] = 112;
|
||||
|
||||
for (i = 0; i < 24; ++i) lt->trans[i] = 256 + i;
|
||||
for (i = 0; i < 144; ++i) lt->trans[24 + i] = i;
|
||||
for (i = 0; i < 8; ++i) lt->trans[24 + 144 + i] = 280 + i;
|
||||
for (i = 0; i < 112; ++i) lt->trans[24 + 144 + 8 + i] = 144 + i;
|
||||
|
||||
/* build fixed distance tree */
|
||||
for (i = 0; i < 5; ++i) dt->table[i] = 0;
|
||||
|
||||
dt->table[5] = 32;
|
||||
|
||||
for (i = 0; i < 32; ++i) dt->trans[i] = i;
|
||||
}
|
||||
|
||||
/* given an array of code lengths, build a tree */
|
||||
static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned int num)
|
||||
{
|
||||
unsigned short offs[16];
|
||||
unsigned int i, sum;
|
||||
|
||||
/* clear code length count table */
|
||||
for (i = 0; i < 16; ++i) t->table[i] = 0;
|
||||
|
||||
/* scan symbol lengths, and sum code length counts */
|
||||
for (i = 0; i < num; ++i) t->table[lengths[i]]++;
|
||||
|
||||
t->table[0] = 0;
|
||||
|
||||
/* compute offset table for distribution sort */
|
||||
for (sum = 0, i = 0; i < 16; ++i)
|
||||
{
|
||||
offs[i] = sum;
|
||||
sum += t->table[i];
|
||||
}
|
||||
|
||||
/* create code->symbol translation table (symbols sorted by code) */
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
if (lengths[i]) t->trans[offs[lengths[i]]++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- decode functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* get one bit from source stream */
|
||||
static int tinf_getbit(TINF_DATA *d)
|
||||
{
|
||||
unsigned int bit;
|
||||
|
||||
/* check if tag is empty */
|
||||
if (!d->bitcount--)
|
||||
{
|
||||
/* load next tag */
|
||||
d->tag = *d->source++;
|
||||
d->bitcount = 7;
|
||||
}
|
||||
|
||||
/* shift bit out of tag */
|
||||
bit = d->tag & 0x01;
|
||||
d->tag >>= 1;
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
/* read a num bit value from a stream and add base */
|
||||
static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
/* read num bits */
|
||||
if (num)
|
||||
{
|
||||
unsigned int limit = 1 << (num);
|
||||
unsigned int mask;
|
||||
|
||||
for (mask = 1; mask < limit; mask *= 2)
|
||||
if (tinf_getbit(d)) val += mask;
|
||||
}
|
||||
|
||||
return val + base;
|
||||
}
|
||||
|
||||
/* given a data stream and a tree, decode a symbol */
|
||||
static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
|
||||
{
|
||||
int sum = 0, cur = 0, len = 0;
|
||||
|
||||
/* get more bits while code value is above sum */
|
||||
do {
|
||||
|
||||
cur = 2*cur + tinf_getbit(d);
|
||||
|
||||
++len;
|
||||
|
||||
sum += t->table[len];
|
||||
cur -= t->table[len];
|
||||
|
||||
} while (cur >= 0);
|
||||
|
||||
return t->trans[sum + cur];
|
||||
}
|
||||
|
||||
/* given a data stream, decode dynamic trees from it */
|
||||
static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
unsigned char lengths[288+32];
|
||||
unsigned int hlit, hdist, hclen;
|
||||
unsigned int i, num, length;
|
||||
|
||||
/* get 5 bits HLIT (257-286) */
|
||||
hlit = tinf_read_bits(d, 5, 257);
|
||||
|
||||
/* get 5 bits HDIST (1-32) */
|
||||
hdist = tinf_read_bits(d, 5, 1);
|
||||
|
||||
/* get 4 bits HCLEN (4-19) */
|
||||
hclen = tinf_read_bits(d, 4, 4);
|
||||
|
||||
for (i = 0; i < 19; ++i) lengths[i] = 0;
|
||||
|
||||
/* read code lengths for code length alphabet */
|
||||
for (i = 0; i < hclen; ++i)
|
||||
{
|
||||
/* get 3 bits code length (0-7) */
|
||||
unsigned int clen = tinf_read_bits(d, 3, 0);
|
||||
|
||||
lengths[clcidx[i]] = clen;
|
||||
}
|
||||
|
||||
/* build code length tree, temporarily use length tree */
|
||||
tinf_build_tree(lt, lengths, 19);
|
||||
|
||||
/* decode code lengths for the dynamic trees */
|
||||
for (num = 0; num < hlit + hdist; )
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
switch (sym)
|
||||
{
|
||||
case 16:
|
||||
/* copy previous code length 3-6 times (read 2 bits) */
|
||||
{
|
||||
unsigned char prev = lengths[num - 1];
|
||||
for (length = tinf_read_bits(d, 2, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = prev;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
/* repeat code length 0 for 3-10 times (read 3 bits) */
|
||||
for (length = tinf_read_bits(d, 3, 3); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
/* repeat code length 0 for 11-138 times (read 7 bits) */
|
||||
for (length = tinf_read_bits(d, 7, 11); length; --length)
|
||||
{
|
||||
lengths[num++] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* values 0-15 represent the actual code lengths */
|
||||
lengths[num++] = sym;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build dynamic trees */
|
||||
tinf_build_tree(lt, lengths, hlit);
|
||||
tinf_build_tree(dt, lengths + hlit, hdist);
|
||||
}
|
||||
|
||||
/* ----------------------------- *
|
||||
* -- block inflate functions -- *
|
||||
* ----------------------------- */
|
||||
|
||||
/* given a stream and two trees, inflate a block of data */
|
||||
static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int sym = tinf_decode_symbol(d, lt);
|
||||
|
||||
/* check for end of block */
|
||||
if (sym == 256)
|
||||
{
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
if (sym < 256)
|
||||
{
|
||||
if (d->destRemaining == 0)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, 1);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
*d->dest++ = sym;
|
||||
|
||||
} else {
|
||||
|
||||
int length, dist, offs;
|
||||
int i;
|
||||
|
||||
sym -= 257;
|
||||
|
||||
/* possibly get more bits from length code */
|
||||
length = tinf_read_bits(d, length_bits[sym], length_base[sym]);
|
||||
|
||||
dist = tinf_decode_symbol(d, dt);
|
||||
|
||||
/* possibly get more bits from distance code */
|
||||
offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
/* copy match */
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
d->dest[i] = d->dest[i - offs];
|
||||
}
|
||||
|
||||
d->dest += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* inflate an uncompressed block of data */
|
||||
static int tinf_inflate_uncompressed_block(TINF_DATA *d)
|
||||
{
|
||||
unsigned int length, invlength;
|
||||
unsigned int i;
|
||||
|
||||
/* get length */
|
||||
length = d->source[1];
|
||||
length = 256*length + d->source[0];
|
||||
|
||||
/* get one's complement of length */
|
||||
invlength = d->source[3];
|
||||
invlength = 256*invlength + d->source[2];
|
||||
|
||||
/* check length */
|
||||
if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
|
||||
|
||||
if (d->destRemaining < length)
|
||||
{
|
||||
int res = tinf_grow_dest_buf(d, length);
|
||||
if (res) return res;
|
||||
}
|
||||
|
||||
d->source += 4;
|
||||
|
||||
/* copy block */
|
||||
for (i = length; i; --i) *d->dest++ = *d->source++;
|
||||
|
||||
/* make sure we start next block on a byte boundary */
|
||||
d->bitcount = 0;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with fixed huffman trees */
|
||||
static int tinf_inflate_fixed_block(TINF_DATA *d)
|
||||
{
|
||||
/* build fixed huffman trees */
|
||||
tinf_build_fixed_trees(&d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using fixed trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* inflate a block of data compressed with dynamic huffman trees */
|
||||
static int tinf_inflate_dynamic_block(TINF_DATA *d)
|
||||
{
|
||||
/* decode trees from stream */
|
||||
tinf_decode_trees(d, &d->ltree, &d->dtree);
|
||||
|
||||
/* decode block using decoded trees */
|
||||
return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
|
||||
}
|
||||
|
||||
/* ---------------------- *
|
||||
* -- public functions -- *
|
||||
* ---------------------- */
|
||||
|
||||
/* initialize global (static) data */
|
||||
void tinf_init()
|
||||
{
|
||||
#ifdef RUNTIME_BITS_TABLES
|
||||
/* build extra bits and base tables */
|
||||
tinf_build_bits_base(length_bits, length_base, 4, 3);
|
||||
tinf_build_bits_base(dist_bits, dist_base, 2, 1);
|
||||
|
||||
/* fix a special case */
|
||||
length_bits[28] = 0;
|
||||
length_base[28] = 258;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_uncompress_dyn(&d);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* inflate stream from source to dest */
|
||||
int tinf_uncompress_dyn(TINF_DATA *d)
|
||||
{
|
||||
int bfinal;
|
||||
|
||||
/* initialise data */
|
||||
d->bitcount = 0;
|
||||
|
||||
d->dest = d->destStart;
|
||||
d->destRemaining = d->destSize;
|
||||
|
||||
do {
|
||||
|
||||
unsigned int btype;
|
||||
int res;
|
||||
|
||||
/* read final block flag */
|
||||
bfinal = tinf_getbit(d);
|
||||
|
||||
/* read block type (2 bits) */
|
||||
btype = tinf_read_bits(d, 2, 0);
|
||||
|
||||
/* decompress block */
|
||||
switch (btype)
|
||||
{
|
||||
case 0:
|
||||
/* decompress uncompressed block */
|
||||
res = tinf_inflate_uncompressed_block(d);
|
||||
break;
|
||||
case 1:
|
||||
/* decompress block with fixed huffman trees */
|
||||
res = tinf_inflate_fixed_block(d);
|
||||
break;
|
||||
case 2:
|
||||
/* decompress block with dynamic huffman trees */
|
||||
res = tinf_inflate_dynamic_block(d);
|
||||
break;
|
||||
default:
|
||||
return TINF_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (res != TINF_OK) return TINF_DATA_ERROR;
|
||||
|
||||
} while (!bfinal);
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
101
extmod/uzlib/tinfzlib.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* tinfzlib - tiny zlib decompressor
|
||||
*
|
||||
* Copyright (c) 2003 by Joergen Ibsen / Jibz
|
||||
* All Rights Reserved
|
||||
*
|
||||
* http://www.ibsensoftware.com/
|
||||
*
|
||||
* This software is provided 'as-is', without any express
|
||||
* or implied warranty. In no event will the authors be
|
||||
* held liable for any damages arising from the use of
|
||||
* this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software
|
||||
* for any purpose, including commercial applications,
|
||||
* and to alter it and redistribute it freely, subject to
|
||||
* the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be
|
||||
* misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this
|
||||
* software in a product, an acknowledgment in
|
||||
* the product documentation would be appreciated
|
||||
* but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked
|
||||
* as such, and must not be misrepresented as
|
||||
* being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from
|
||||
* any source distribution.
|
||||
*/
|
||||
|
||||
#include "tinf.h"
|
||||
|
||||
int tinf_zlib_uncompress(void *dest, unsigned int *destLen,
|
||||
const void *source, unsigned int sourceLen)
|
||||
{
|
||||
TINF_DATA d;
|
||||
int res;
|
||||
|
||||
/* initialise data */
|
||||
d.source = (const unsigned char *)source;
|
||||
|
||||
d.destStart = (unsigned char *)dest;
|
||||
d.destRemaining = *destLen;
|
||||
|
||||
res = tinf_zlib_uncompress_dyn(&d, sourceLen);
|
||||
|
||||
*destLen = d.dest - d.destStart;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen)
|
||||
{
|
||||
unsigned int a32;
|
||||
int res;
|
||||
unsigned char cmf, flg;
|
||||
|
||||
/* -- get header bytes -- */
|
||||
|
||||
cmf = d->source[0];
|
||||
flg = d->source[1];
|
||||
|
||||
/* -- check format -- */
|
||||
|
||||
/* check checksum */
|
||||
if ((256*cmf + flg) % 31) return TINF_DATA_ERROR;
|
||||
|
||||
/* check method is deflate */
|
||||
if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR;
|
||||
|
||||
/* check window size is valid */
|
||||
if ((cmf >> 4) > 7) return TINF_DATA_ERROR;
|
||||
|
||||
/* check there is no preset dictionary */
|
||||
if (flg & 0x20) return TINF_DATA_ERROR;
|
||||
|
||||
/* -- get adler32 checksum -- */
|
||||
|
||||
a32 = d->source[sourceLen - 4];
|
||||
a32 = 256*a32 + d->source[sourceLen - 3];
|
||||
a32 = 256*a32 + d->source[sourceLen - 2];
|
||||
a32 = 256*a32 + d->source[sourceLen - 1];
|
||||
|
||||
d->source += 2;
|
||||
|
||||
/* -- inflate -- */
|
||||
|
||||
res = tinf_uncompress_dyn(d);
|
||||
|
||||
if (res != TINF_OK) return res;
|
||||
|
||||
/* -- check adler32 checksum -- */
|
||||
|
||||
if (a32 != tinf_adler32(d->destStart, d->dest - d->destStart)) return TINF_DATA_ERROR;
|
||||
|
||||
return TINF_OK;
|
||||
}
|
||||
|
||||
33
lib/libm/roundf.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
// roundf from musl-0.9.15
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
float roundf(float x)
|
||||
{
|
||||
union {float f; uint32_t i;} u = {x};
|
||||
int e = u.i >> 23 & 0xff;
|
||||
float_t y;
|
||||
|
||||
if (e >= 0x7f+23)
|
||||
return x;
|
||||
if (u.i >> 31)
|
||||
x = -x;
|
||||
if (e < 0x7f-1) {
|
||||
FORCE_EVAL(x + 0x1p23f);
|
||||
return 0*u.f;
|
||||
}
|
||||
y = (float)(x + 0x1p23f) - 0x1p23f - x;
|
||||
if (y > 0.5f)
|
||||
y = y + x - 1;
|
||||
else if (y <= -0.5f)
|
||||
y = y + x + 1;
|
||||
else
|
||||
y = y + x;
|
||||
if (u.i >> 31)
|
||||
y = -y;
|
||||
return y;
|
||||
}
|
||||
93
py/asmarm.c
@@ -175,6 +175,21 @@ STATIC uint asm_arm_op_sub_reg(uint rd, uint rn, uint rm) {
|
||||
return 0x0400000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_and_reg(uint rd, uint rn, uint rm) {
|
||||
// and rd, rn, rm
|
||||
return 0x0000000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_eor_reg(uint rd, uint rn, uint rm) {
|
||||
// eor rd, rn, rm
|
||||
return 0x0200000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
STATIC uint asm_arm_op_orr_reg(uint rd, uint rn, uint rm) {
|
||||
// orr rd, rn, rm
|
||||
return 0x1800000 | (rn << 16) | (rd << 12) | rm;
|
||||
}
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as) {
|
||||
// bkpt #0
|
||||
emit_al(as, 0x1200070);
|
||||
@@ -297,10 +312,9 @@ void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
emit_al(as, 0x1500000 | (rd << 16) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
asm_arm_cmp_reg_reg(as, rn, rm); // cmp rn, rm
|
||||
emit(as, asm_arm_op_mov_imm(rd, 1) | ASM_ARM_CC_LT); // movlt rd, #1
|
||||
emit(as, asm_arm_op_mov_imm(rd, 0) | ASM_ARM_CC_GE); // movge rd, #0
|
||||
void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond) {
|
||||
emit(as, asm_arm_op_mov_imm(rd, 1) | cond); // movCOND rd, #1
|
||||
emit(as, asm_arm_op_mov_imm(rd, 0) | (cond ^ (1 << 28))); // mov!COND rd, #0
|
||||
}
|
||||
|
||||
void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
@@ -313,11 +327,82 @@ void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
emit_al(as, asm_arm_op_sub_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// and rd, rn, rm
|
||||
emit_al(as, asm_arm_op_and_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// eor rd, rn, rm
|
||||
emit_al(as, asm_arm_op_eor_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) {
|
||||
// orr rd, rn, rm
|
||||
emit_al(as, asm_arm_op_orr_reg(rd, rn, rm));
|
||||
}
|
||||
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) {
|
||||
// add rd, sp, #local_num*4
|
||||
emit_al(as, asm_arm_op_add_imm(rd, ASM_ARM_REG_SP, local_num << 2));
|
||||
}
|
||||
|
||||
void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs) {
|
||||
// mov rd, rd, lsl rs
|
||||
emit_al(as, 0x1a00010 | (rd << 12) | (rs << 8) | rd);
|
||||
}
|
||||
|
||||
void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) {
|
||||
// mov rd, rd, asr rs
|
||||
emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd);
|
||||
}
|
||||
|
||||
void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldr rd, [rn]
|
||||
emit_al(as, 0x5900000 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldrh rd, [rn]
|
||||
emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) {
|
||||
// ldrb rd, [rn]
|
||||
emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// str rd, [rm]
|
||||
emit_al(as, 0x5800000 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// strh rd, [rm]
|
||||
emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) {
|
||||
// strb rd, [rm]
|
||||
emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12));
|
||||
}
|
||||
|
||||
void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// str rd, [rm, rn, lsl #2]
|
||||
emit_al(as, 0x7800100 | (rm << 16) | (rd << 12) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// strh doesn't support scaled register index
|
||||
emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1
|
||||
emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8]
|
||||
}
|
||||
|
||||
void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
|
||||
// strb rd, [rm, rn]
|
||||
emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | rn);
|
||||
}
|
||||
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
|
||||
assert(label < as->max_num_labels);
|
||||
mp_uint_t dest = as->label_offsets[label];
|
||||
|
||||
25
py/asmarm.h
@@ -81,18 +81,41 @@ void asm_arm_align(asm_arm_t* as, uint align);
|
||||
void asm_arm_data(asm_arm_t* as, uint bytesize, uint val);
|
||||
|
||||
void asm_arm_bkpt(asm_arm_t *as);
|
||||
|
||||
// mov
|
||||
void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src);
|
||||
void asm_arm_mov_reg_i32(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_mov_local_reg(asm_arm_t *as, int local_num, uint rd);
|
||||
void asm_arm_mov_reg_local(asm_arm_t *as, uint rd, int local_num);
|
||||
void asm_arm_setcc_reg(asm_arm_t *as, uint rd, uint cond);
|
||||
|
||||
// compare
|
||||
void asm_arm_cmp_reg_i8(asm_arm_t *as, uint rd, int imm);
|
||||
void asm_arm_cmp_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_less_op(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
|
||||
// arithmetic
|
||||
void asm_arm_add_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_sub_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_and_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_eor_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm);
|
||||
void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num);
|
||||
void asm_arm_lsl_reg_reg(asm_arm_t *as, uint rd, uint rs);
|
||||
void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs);
|
||||
|
||||
// memory
|
||||
void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn);
|
||||
void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm);
|
||||
// store to array
|
||||
void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
|
||||
|
||||
// control flow
|
||||
void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label);
|
||||
void asm_arm_b_label(asm_arm_t *as, uint label);
|
||||
void asm_arm_bl_ind(asm_arm_t *as, void *fun_ptr, uint fun_id, uint reg_temp);
|
||||
|
||||
46
py/asmx64.c
@@ -51,8 +51,12 @@
|
||||
#define OPCODE_MOV_I32_TO_RM32 (0xc7)
|
||||
#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */
|
||||
#define OPCODE_MOV_R64_TO_RM64 (0x89) /* /r */
|
||||
#define OPCODE_MOV_RM64_TO_R64 (0x8b)
|
||||
#define OPCODE_MOV_RM64_TO_R64 (0x8b) /* /r */
|
||||
#define OPCODE_MOVZX_RM8_TO_R64 (0xb6) /* 0x0f 0xb6/r */
|
||||
#define OPCODE_MOVZX_RM16_TO_R64 (0xb7) /* 0x0f 0xb7/r */
|
||||
#define OPCODE_LEA_MEM_TO_R64 (0x8d) /* /r */
|
||||
#define OPCODE_AND_R64_TO_RM64 (0x21) /* /r */
|
||||
#define OPCODE_OR_R64_TO_RM64 (0x09) /* /r */
|
||||
#define OPCODE_XOR_R64_TO_RM64 (0x31) /* /r */
|
||||
#define OPCODE_ADD_R64_TO_RM64 (0x01) /* /r */
|
||||
#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
|
||||
@@ -300,7 +304,7 @@ void asm_x64_mov_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_MOV_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
assert(dest_r64 < 8);
|
||||
if (src_r64 < 8) {
|
||||
asm_x64_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);
|
||||
@@ -310,7 +314,7 @@ void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_d
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
assert(dest_r64 < 8);
|
||||
if (src_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R64_TO_RM64);
|
||||
@@ -320,14 +324,34 @@ void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r64_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp) {
|
||||
// use REX prefix for 64 bit operation
|
||||
assert(dest_r64 < 8);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (src_r64 < 8 ? 0 : REX_R), OPCODE_MOV_R64_TO_RM64);
|
||||
asm_x64_write_r64_disp(as, src_r64, dest_r64, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_disp_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM8_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
assert(src_r64 < 8);
|
||||
if (dest_r64 < 8) {
|
||||
asm_x64_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
} else {
|
||||
asm_x64_write_byte_3(as, REX_PREFIX | REX_R, 0x0f, OPCODE_MOVZX_RM16_TO_R64);
|
||||
}
|
||||
asm_x64_write_r64_disp(as, dest_r64, src_r64, src_disp);
|
||||
}
|
||||
|
||||
void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64) {
|
||||
// use REX prefix for 64 bit operation
|
||||
assert(src_r64 < 8);
|
||||
asm_x64_write_byte_2(as, REX_PREFIX | REX_W | (dest_r64 < 8 ? 0 : REX_R), OPCODE_MOV_RM64_TO_R64);
|
||||
@@ -385,6 +409,14 @@ void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64
|
||||
asm_x64_mov_i64_to_r64(as, src_i64, dest_r64);
|
||||
}
|
||||
|
||||
void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_AND_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_OR_R64_TO_RM64);
|
||||
}
|
||||
|
||||
void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64) {
|
||||
asm_x64_generic_r64_r64(as, dest_r64, src_r64, OPCODE_XOR_R64_TO_RM64);
|
||||
}
|
||||
@@ -577,11 +609,11 @@ STATIC int asm_x64_local_offset_from_ebp(asm_x64_t *as, int local_num) {
|
||||
}
|
||||
|
||||
void asm_x64_mov_local_to_r64(asm_x64_t *as, int src_local_num, int dest_r64) {
|
||||
asm_x64_mov_disp_to_r64(as, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, src_local_num), dest_r64);
|
||||
asm_x64_mov_mem64_to_r64(as, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, src_local_num), dest_r64);
|
||||
}
|
||||
|
||||
void asm_x64_mov_r64_to_local(asm_x64_t *as, int src_r64, int dest_local_num) {
|
||||
asm_x64_mov_r64_to_disp(as, src_r64, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, dest_local_num));
|
||||
asm_x64_mov_r64_to_mem64(as, src_r64, ASM_X64_REG_RBP, asm_x64_local_offset_from_ebp(as, dest_local_num));
|
||||
}
|
||||
|
||||
void asm_x64_mov_local_addr_to_r64(asm_x64_t *as, int local_num, int dest_r64) {
|
||||
|
||||
11
py/asmx64.h
@@ -83,9 +83,14 @@ void asm_x64_mov_r64_r64(asm_x64_t* as, int dest_r64, int src_r64);
|
||||
void asm_x64_mov_i64_to_r64(asm_x64_t* as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64);
|
||||
void asm_x64_mov_r8_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r16_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r64_to_disp(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r8_to_mem8(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r16_to_mem16(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_r64_to_mem64(asm_x64_t *as, int src_r64, int dest_r64, int dest_disp);
|
||||
void asm_x64_mov_mem8_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_mov_mem16_to_r64zx(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_mov_mem64_to_r64(asm_x64_t *as, int src_r64, int src_disp, int dest_r64);
|
||||
void asm_x64_and_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_or_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_xor_r64_r64(asm_x64_t *as, int dest_r64, int src_r64);
|
||||
void asm_x64_shl_r64_cl(asm_x64_t* as, int dest_r64);
|
||||
void asm_x64_sar_r64_cl(asm_x64_t* as, int dest_r64);
|
||||
|
||||
42
py/asmx86.c
@@ -50,9 +50,13 @@
|
||||
#define OPCODE_MOV_I32_TO_R32 (0xb8)
|
||||
//#define OPCODE_MOV_I32_TO_RM32 (0xc7)
|
||||
#define OPCODE_MOV_R8_TO_RM8 (0x88) /* /r */
|
||||
#define OPCODE_MOV_R32_TO_RM32 (0x89)
|
||||
#define OPCODE_MOV_RM32_TO_R32 (0x8b)
|
||||
#define OPCODE_MOV_R32_TO_RM32 (0x89) /* /r */
|
||||
#define OPCODE_MOV_RM32_TO_R32 (0x8b) /* /r */
|
||||
#define OPCODE_MOVZX_RM8_TO_R32 (0xb6) /* 0x0f 0xb6/r */
|
||||
#define OPCODE_MOVZX_RM16_TO_R32 (0xb7) /* 0x0f 0xb7/r */
|
||||
#define OPCODE_LEA_MEM_TO_R32 (0x8d) /* /r */
|
||||
#define OPCODE_AND_R32_TO_RM32 (0x21) /* /r */
|
||||
#define OPCODE_OR_R32_TO_RM32 (0x09) /* /r */
|
||||
#define OPCODE_XOR_R32_TO_RM32 (0x31) /* /r */
|
||||
#define OPCODE_ADD_R32_TO_RM32 (0x01)
|
||||
#define OPCODE_ADD_I32_TO_RM32 (0x81) /* /0 */
|
||||
@@ -242,22 +246,32 @@ void asm_x86_mov_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_MOV_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r8_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_R8_TO_RM8);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r16_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_2(as, OP_SIZE_PREFIX, OPCODE_MOV_R32_TO_RM32);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r32_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_R32_TO_RM32);
|
||||
asm_x86_write_r32_disp(as, src_r32, dest_r32, dest_disp);
|
||||
}
|
||||
|
||||
STATIC void asm_x86_mov_disp_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM8_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_2(as, 0x0f, OPCODE_MOVZX_RM16_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
|
||||
void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32) {
|
||||
asm_x86_write_byte_1(as, OPCODE_MOV_RM32_TO_R32);
|
||||
asm_x86_write_r32_disp(as, dest_r32, src_r32, src_disp);
|
||||
}
|
||||
@@ -287,6 +301,14 @@ void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32
|
||||
asm_x86_mov_i32_to_r32(as, src_i32, dest_r32);
|
||||
}
|
||||
|
||||
void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_AND_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_OR_R32_TO_RM32);
|
||||
}
|
||||
|
||||
void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32) {
|
||||
asm_x86_generic_r32_r32(as, dest_r32, src_r32, OPCODE_XOR_R32_TO_RM32);
|
||||
}
|
||||
@@ -464,12 +486,12 @@ void asm_x86_push_arg(asm_x86_t *as, int src_arg_num) {
|
||||
#endif
|
||||
|
||||
void asm_x86_mov_arg_to_r32(asm_x86_t *as, int src_arg_num, int dest_r32) {
|
||||
asm_x86_mov_disp_to_r32(as, ASM_X86_REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE, dest_r32);
|
||||
asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_EBP, 2 * WORD_SIZE + src_arg_num * WORD_SIZE, dest_r32);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void asm_x86_mov_r32_to_arg(asm_x86_t *as, int src_r32, int dest_arg_num) {
|
||||
asm_x86_mov_r32_to_disp(as, src_r32, ASM_X86_REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE);
|
||||
asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_EBP, 2 * WORD_SIZE + dest_arg_num * WORD_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -489,11 +511,11 @@ STATIC int asm_x86_local_offset_from_ebp(asm_x86_t *as, int local_num) {
|
||||
}
|
||||
|
||||
void asm_x86_mov_local_to_r32(asm_x86_t *as, int src_local_num, int dest_r32) {
|
||||
asm_x86_mov_disp_to_r32(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, src_local_num), dest_r32);
|
||||
asm_x86_mov_mem32_to_r32(as, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, src_local_num), dest_r32);
|
||||
}
|
||||
|
||||
void asm_x86_mov_r32_to_local(asm_x86_t *as, int src_r32, int dest_local_num) {
|
||||
asm_x86_mov_r32_to_disp(as, src_r32, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, dest_local_num));
|
||||
asm_x86_mov_r32_to_mem32(as, src_r32, ASM_X86_REG_EBP, asm_x86_local_offset_from_ebp(as, dest_local_num));
|
||||
}
|
||||
|
||||
void asm_x86_mov_local_addr_to_r32(asm_x86_t *as, int local_num, int dest_r32) {
|
||||
|
||||
11
py/asmx86.h
@@ -80,9 +80,14 @@ void* asm_x86_get_code(asm_x86_t* as);
|
||||
void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
|
||||
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
|
||||
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32);
|
||||
void asm_x86_mov_r8_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r16_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r32_to_disp(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r8_to_mem8(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r16_to_mem16(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_r32_to_mem32(asm_x86_t *as, int src_r32, int dest_r32, int dest_disp);
|
||||
void asm_x86_mov_mem8_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_mov_mem16_to_r32zx(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_mov_mem32_to_r32(asm_x86_t *as, int src_r32, int src_disp, int dest_r32);
|
||||
void asm_x86_and_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_or_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_xor_r32_r32(asm_x86_t *as, int dest_r32, int src_r32);
|
||||
void asm_x86_shl_r32_cl(asm_x86_t* as, int dest_r32);
|
||||
void asm_x86_sar_r32_cl(asm_x86_t* as, int dest_r32);
|
||||
|
||||
26
py/bc.c
@@ -75,9 +75,9 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, mp_uint_t expecte
|
||||
}
|
||||
|
||||
#if DEBUG_PRINT
|
||||
STATIC void dump_args(const mp_obj_t *a, int sz) {
|
||||
STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
|
||||
DEBUG_printf("%p: ", a);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
for (mp_uint_t i = 0; i < sz; i++) {
|
||||
DEBUG_printf("%p ", a[i]);
|
||||
}
|
||||
DEBUG_printf("\n");
|
||||
@@ -93,7 +93,6 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
// usage for the common case of positional only args.
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
mp_uint_t n_state = code_state->n_state;
|
||||
const byte *ip = code_state->ip;
|
||||
|
||||
code_state->code_info = self->bytecode;
|
||||
code_state->sp = &code_state->state[0] - 1;
|
||||
@@ -153,13 +152,21 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
|
||||
*var_pos_kw_args = dict;
|
||||
}
|
||||
|
||||
// get pointer to arg_names array at start of bytecode prelude
|
||||
const mp_obj_t *arg_names;
|
||||
{
|
||||
const byte *code_info = code_state->code_info;
|
||||
mp_uint_t code_info_size = mp_decode_uint(&code_info);
|
||||
arg_names = (const mp_obj_t*)(code_state->code_info + code_info_size);
|
||||
}
|
||||
|
||||
for (mp_uint_t i = 0; i < n_kw; i++) {
|
||||
qstr arg_name = MP_OBJ_QSTR_VALUE(kwargs[2 * i]);
|
||||
mp_obj_t wanted_arg_name = kwargs[2 * i];
|
||||
for (mp_uint_t j = 0; j < self->n_pos_args + self->n_kwonly_args; j++) {
|
||||
if (arg_name == self->args[j]) {
|
||||
if (wanted_arg_name == arg_names[j]) {
|
||||
if (code_state->state[n_state - 1 - j] != MP_OBJ_NULL) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function got multiple values for argument '%s'", qstr_str(arg_name)));
|
||||
"function got multiple values for argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(wanted_arg_name))));
|
||||
}
|
||||
code_state->state[n_state - 1 - j] = kwargs[2 * i + 1];
|
||||
goto continue2;
|
||||
@@ -179,7 +186,7 @@ continue2:;
|
||||
// fill in defaults for positional args
|
||||
mp_obj_t *d = &code_state->state[n_state - self->n_pos_args];
|
||||
mp_obj_t *s = &self->extra_args[self->n_def_args - 1];
|
||||
for (int i = self->n_def_args; i > 0; i--, d++, s--) {
|
||||
for (mp_uint_t i = self->n_def_args; i > 0; i--, d++, s--) {
|
||||
if (*d == MP_OBJ_NULL) {
|
||||
*d = *s;
|
||||
}
|
||||
@@ -202,13 +209,13 @@ continue2:;
|
||||
if (code_state->state[n_state - 1 - self->n_pos_args - i] == MP_OBJ_NULL) {
|
||||
mp_map_elem_t *elem = NULL;
|
||||
if (self->has_def_kw_args) {
|
||||
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, MP_OBJ_NEW_QSTR(self->args[self->n_pos_args + i]), MP_MAP_LOOKUP);
|
||||
elem = mp_map_lookup(&((mp_obj_dict_t*)self->extra_args[self->n_def_args])->map, arg_names[self->n_pos_args + i], MP_MAP_LOOKUP);
|
||||
}
|
||||
if (elem != NULL) {
|
||||
code_state->state[n_state - 1 - self->n_pos_args - i] = elem->value;
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"function missing required keyword argument '%s'", qstr_str(self->args[self->n_pos_args + i])));
|
||||
"function missing required keyword argument '%s'", qstr_str(MP_OBJ_QSTR_VALUE(arg_names[self->n_pos_args + i]))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,6 +232,7 @@ continue2:;
|
||||
}
|
||||
|
||||
// bytecode prelude: initialise closed over variables
|
||||
const byte *ip = code_state->ip;
|
||||
for (mp_uint_t n_local = *ip++; n_local > 0; n_local--) {
|
||||
mp_uint_t local_num = *ip++;
|
||||
code_state->state[n_state - 1 - local_num] = mp_obj_new_cell(code_state->state[n_state - 1 - local_num]);
|
||||
|
||||
6
py/bc.h
@@ -42,7 +42,7 @@ typedef struct _mp_code_state {
|
||||
mp_obj_t *sp;
|
||||
// bit 0 is saved currently_in_except_block value
|
||||
mp_exc_stack_t *exc_sp;
|
||||
uint n_state;
|
||||
mp_uint_t n_state;
|
||||
// Variable-length
|
||||
mp_obj_t state[0];
|
||||
// Variable-length, never accessed by name, only as (void*)(state + n_state)
|
||||
@@ -53,8 +53,8 @@ mp_uint_t mp_decode_uint(const byte **ptr);
|
||||
|
||||
mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc);
|
||||
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
|
||||
void mp_bytecode_print(const void *descr, const byte *code, int len);
|
||||
void mp_bytecode_print2(const byte *code, int len);
|
||||
void mp_bytecode_print(const void *descr, mp_uint_t n_total_args, const byte *code, mp_uint_t len);
|
||||
void mp_bytecode_print2(const byte *code, mp_uint_t len);
|
||||
|
||||
// Helper macros to access pointer with least significant bit holding a flag
|
||||
#define MP_TAGPTR_PTR(x) ((void*)((mp_uint_t)(x) & ~((mp_uint_t)1)))
|
||||
|
||||
152
py/bc0.h
@@ -31,92 +31,90 @@
|
||||
#define MP_BC_LOAD_CONST_NONE (0x11)
|
||||
#define MP_BC_LOAD_CONST_TRUE (0x12)
|
||||
#define MP_BC_LOAD_CONST_ELLIPSIS (0x13)
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // 24-bit, in excess
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int
|
||||
#define MP_BC_LOAD_CONST_INT (0x15) // qstr
|
||||
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
|
||||
#define MP_BC_LOAD_CONST_BYTES (0x18) // qstr
|
||||
#define MP_BC_LOAD_CONST_STRING (0x19) // qstr
|
||||
#define MP_BC_LOAD_NULL (0x1a)
|
||||
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
|
||||
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
|
||||
#define MP_BC_LOAD_NULL (0x19)
|
||||
|
||||
#define MP_BC_LOAD_FAST_0 (0x20)
|
||||
#define MP_BC_LOAD_FAST_1 (0x21)
|
||||
#define MP_BC_LOAD_FAST_2 (0x22)
|
||||
#define MP_BC_LOAD_FAST_N (0x23) // uint
|
||||
#define MP_BC_LOAD_DEREF (0x25) // uint
|
||||
#define MP_BC_LOAD_NAME (0x26) // qstr
|
||||
#define MP_BC_LOAD_GLOBAL (0x27) // qstr
|
||||
#define MP_BC_LOAD_ATTR (0x28) // qstr
|
||||
#define MP_BC_LOAD_METHOD (0x29) // qstr
|
||||
#define MP_BC_LOAD_BUILD_CLASS (0x2a)
|
||||
#define MP_BC_LOAD_SUBSCR (0x2b)
|
||||
#define MP_BC_LOAD_FAST_N (0x1a) // uint
|
||||
#define MP_BC_LOAD_DEREF (0x1b) // uint
|
||||
#define MP_BC_LOAD_NAME (0x1c) // qstr
|
||||
#define MP_BC_LOAD_GLOBAL (0x1d) // qstr
|
||||
#define MP_BC_LOAD_ATTR (0x1e) // qstr
|
||||
#define MP_BC_LOAD_METHOD (0x1f) // qstr
|
||||
#define MP_BC_LOAD_BUILD_CLASS (0x20)
|
||||
#define MP_BC_LOAD_SUBSCR (0x21)
|
||||
|
||||
#define MP_BC_STORE_FAST_0 (0x30)
|
||||
#define MP_BC_STORE_FAST_1 (0x31)
|
||||
#define MP_BC_STORE_FAST_2 (0x32)
|
||||
#define MP_BC_STORE_FAST_N (0x33) // uint
|
||||
#define MP_BC_STORE_DEREF (0x34) // uint
|
||||
#define MP_BC_STORE_NAME (0x35) // qstr
|
||||
#define MP_BC_STORE_GLOBAL (0x36) // qstr
|
||||
#define MP_BC_STORE_ATTR (0x37) // qstr
|
||||
#define MP_BC_STORE_SUBSCR (0x38)
|
||||
#define MP_BC_STORE_FAST_N (0x22) // uint
|
||||
#define MP_BC_STORE_DEREF (0x23) // uint
|
||||
#define MP_BC_STORE_NAME (0x24) // qstr
|
||||
#define MP_BC_STORE_GLOBAL (0x25) // qstr
|
||||
#define MP_BC_STORE_ATTR (0x26) // qstr
|
||||
#define MP_BC_STORE_SUBSCR (0x27)
|
||||
|
||||
#define MP_BC_DELETE_FAST (0x39) // uint
|
||||
#define MP_BC_DELETE_DEREF (0x3a) // uint
|
||||
#define MP_BC_DELETE_NAME (0x3b) // qstr
|
||||
#define MP_BC_DELETE_GLOBAL (0x3c) // qstr
|
||||
#define MP_BC_DELETE_FAST (0x28) // uint
|
||||
#define MP_BC_DELETE_DEREF (0x29) // uint
|
||||
#define MP_BC_DELETE_NAME (0x2a) // qstr
|
||||
#define MP_BC_DELETE_GLOBAL (0x2b) // qstr
|
||||
|
||||
#define MP_BC_DUP_TOP (0x40)
|
||||
#define MP_BC_DUP_TOP_TWO (0x41)
|
||||
#define MP_BC_POP_TOP (0x42)
|
||||
#define MP_BC_ROT_TWO (0x43)
|
||||
#define MP_BC_ROT_THREE (0x44)
|
||||
#define MP_BC_DUP_TOP (0x30)
|
||||
#define MP_BC_DUP_TOP_TWO (0x31)
|
||||
#define MP_BC_POP_TOP (0x32)
|
||||
#define MP_BC_ROT_TWO (0x33)
|
||||
#define MP_BC_ROT_THREE (0x34)
|
||||
|
||||
#define MP_BC_JUMP (0x45) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_TRUE (0x46) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_WITH_CLEANUP (0x4e)
|
||||
#define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_SETUP_FINALLY (0x50) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_END_FINALLY (0x51)
|
||||
#define MP_BC_GET_ITER (0x52)
|
||||
#define MP_BC_FOR_ITER (0x53) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_POP_BLOCK (0x54)
|
||||
#define MP_BC_POP_EXCEPT (0x55)
|
||||
#define MP_BC_UNWIND_JUMP (0x56) // rel byte code offset, 16-bit signed, in excess; then a byte
|
||||
#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess
|
||||
#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_WITH_CLEANUP (0x3e)
|
||||
#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_END_FINALLY (0x41)
|
||||
#define MP_BC_GET_ITER (0x42)
|
||||
#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned
|
||||
#define MP_BC_POP_BLOCK (0x44)
|
||||
#define MP_BC_POP_EXCEPT (0x45)
|
||||
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
|
||||
|
||||
#define MP_BC_NOT (0x60)
|
||||
#define MP_BC_UNARY_OP (0x61) // byte
|
||||
#define MP_BC_BINARY_OP (0x62) // byte
|
||||
#define MP_BC_NOT (0x47)
|
||||
|
||||
#define MP_BC_BUILD_TUPLE (0x70) // uint
|
||||
#define MP_BC_BUILD_LIST (0x71) // uint
|
||||
#define MP_BC_LIST_APPEND (0x72) // uint
|
||||
#define MP_BC_BUILD_MAP (0x73) // uint
|
||||
#define MP_BC_STORE_MAP (0x74)
|
||||
#define MP_BC_MAP_ADD (0x75) // uint
|
||||
#define MP_BC_BUILD_SET (0x76) // uint
|
||||
#define MP_BC_SET_ADD (0x77) // uint
|
||||
#define MP_BC_BUILD_SLICE (0x78) // uint
|
||||
#define MP_BC_UNPACK_SEQUENCE (0x79) // uint
|
||||
#define MP_BC_UNPACK_EX (0x7a) // uint
|
||||
#define MP_BC_BUILD_TUPLE (0x50) // uint
|
||||
#define MP_BC_BUILD_LIST (0x51) // uint
|
||||
#define MP_BC_LIST_APPEND (0x52) // uint
|
||||
#define MP_BC_BUILD_MAP (0x53) // uint
|
||||
#define MP_BC_STORE_MAP (0x54)
|
||||
#define MP_BC_MAP_ADD (0x55) // uint
|
||||
#define MP_BC_BUILD_SET (0x56) // uint
|
||||
#define MP_BC_SET_ADD (0x57) // uint
|
||||
#define MP_BC_BUILD_SLICE (0x58) // uint
|
||||
#define MP_BC_UNPACK_SEQUENCE (0x59) // uint
|
||||
#define MP_BC_UNPACK_EX (0x5a) // uint
|
||||
|
||||
#define MP_BC_RETURN_VALUE (0x80)
|
||||
#define MP_BC_RAISE_VARARGS (0x81) // byte
|
||||
#define MP_BC_YIELD_VALUE (0x82)
|
||||
#define MP_BC_YIELD_FROM (0x83)
|
||||
#define MP_BC_RETURN_VALUE (0x5b)
|
||||
#define MP_BC_RAISE_VARARGS (0x5c) // byte
|
||||
#define MP_BC_YIELD_VALUE (0x5d)
|
||||
#define MP_BC_YIELD_FROM (0x5e)
|
||||
|
||||
#define MP_BC_MAKE_FUNCTION (0x90) // uint
|
||||
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x91) // uint
|
||||
#define MP_BC_MAKE_CLOSURE (0x92) // uint
|
||||
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x93) // uint
|
||||
#define MP_BC_CALL_FUNCTION (0x94) // uint
|
||||
#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint
|
||||
#define MP_BC_CALL_METHOD (0x96) // uint
|
||||
#define MP_BC_CALL_METHOD_VAR_KW (0x97) // uint
|
||||
#define MP_BC_MAKE_FUNCTION (0x60) // uint
|
||||
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint
|
||||
#define MP_BC_MAKE_CLOSURE (0x62) // uint
|
||||
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint
|
||||
#define MP_BC_CALL_FUNCTION (0x64) // uint
|
||||
#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint
|
||||
#define MP_BC_CALL_METHOD (0x66) // uint
|
||||
#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint
|
||||
|
||||
#define MP_BC_IMPORT_NAME (0xe0) // qstr
|
||||
#define MP_BC_IMPORT_FROM (0xe1) // qstr
|
||||
#define MP_BC_IMPORT_STAR (0xe2)
|
||||
#define MP_BC_IMPORT_NAME (0x68) // qstr
|
||||
#define MP_BC_IMPORT_FROM (0x69) // qstr
|
||||
#define MP_BC_IMPORT_STAR (0x6a)
|
||||
|
||||
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
|
||||
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
|
||||
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
|
||||
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
|
||||
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)
|
||||
|
||||
64
py/binary.c
@@ -99,7 +99,7 @@ int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
|
||||
return size;
|
||||
}
|
||||
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
|
||||
mp_int_t val = 0;
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
@@ -140,23 +140,23 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
|
||||
// The long long type is guaranteed to hold at least 64 bits, and size is at
|
||||
// most 8 (for q and Q), so we will always be able to parse the given data
|
||||
// and fit it into a long long.
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p) {
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) {
|
||||
int delta;
|
||||
if (!big_endian) {
|
||||
delta = -1;
|
||||
p += size - 1;
|
||||
src += size - 1;
|
||||
} else {
|
||||
delta = 1;
|
||||
}
|
||||
|
||||
long long val = 0;
|
||||
if (is_signed && *p & 0x80) {
|
||||
if (is_signed && *src & 0x80) {
|
||||
val = -1;
|
||||
}
|
||||
for (uint i = 0; i < size; i++) {
|
||||
val <<= 8;
|
||||
val |= *p;
|
||||
p += delta;
|
||||
val |= *src;
|
||||
src += delta;
|
||||
}
|
||||
|
||||
return val;
|
||||
@@ -201,20 +201,22 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr) {
|
||||
int in_delta, out_delta;
|
||||
if (big_endian) {
|
||||
in_delta = -1;
|
||||
out_delta = 1;
|
||||
val_ptr += val_sz - 1;
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
|
||||
if (MP_ENDIANNESS_LITTLE && !big_endian) {
|
||||
memcpy(dest, &val, val_sz);
|
||||
} else if (MP_ENDIANNESS_BIG && big_endian) {
|
||||
// only copy the least-significant val_sz bytes
|
||||
memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
|
||||
} else {
|
||||
in_delta = out_delta = 1;
|
||||
}
|
||||
|
||||
for (uint i = val_sz; i > 0; i--) {
|
||||
*p = *val_ptr;
|
||||
p += out_delta;
|
||||
val_ptr += in_delta;
|
||||
const byte *src;
|
||||
if (MP_ENDIANNESS_LITTLE) {
|
||||
src = (const byte*)&val + val_sz;
|
||||
} else {
|
||||
src = (const byte*)&val + sizeof(mp_uint_t);
|
||||
}
|
||||
while (val_sz--) {
|
||||
*dest++ = *--src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,31 +228,27 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
|
||||
if (struct_type == '@') {
|
||||
// Make pointer aligned
|
||||
p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
|
||||
#if MP_ENDIANNESS_LITTLE
|
||||
struct_type = '<';
|
||||
#else
|
||||
struct_type = '>';
|
||||
#endif
|
||||
if (MP_ENDIANNESS_LITTLE) {
|
||||
struct_type = '<';
|
||||
} else {
|
||||
struct_type = '>';
|
||||
}
|
||||
}
|
||||
*ptr = p + size;
|
||||
|
||||
#if MP_ENDIANNESS_BIG
|
||||
#error Not implemented
|
||||
#endif
|
||||
mp_int_t val;
|
||||
byte *in = (byte*)&val;
|
||||
mp_uint_t val;
|
||||
switch (val_type) {
|
||||
case 'O':
|
||||
in = (byte*)&val_in;
|
||||
val = (mp_uint_t)val_in;
|
||||
break;
|
||||
default:
|
||||
val = mp_obj_get_int(val_in);
|
||||
}
|
||||
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
|
||||
mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, val);
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
|
||||
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
|
||||
switch (typecode) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
@@ -265,7 +263,7 @@ void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in)
|
||||
}
|
||||
}
|
||||
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val) {
|
||||
switch (typecode) {
|
||||
case 'b':
|
||||
((int8_t*)p)[index] = val;
|
||||
|
||||
10
py/binary.h
@@ -29,10 +29,10 @@
|
||||
#define BYTEARRAY_TYPECODE 0
|
||||
|
||||
int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign);
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index);
|
||||
void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val);
|
||||
mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index);
|
||||
void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in);
|
||||
void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val);
|
||||
mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
|
||||
void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p);
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr);
|
||||
long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src);
|
||||
void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val);
|
||||
|
||||
32
py/builtin.c
@@ -33,6 +33,7 @@
|
||||
#include "qstr.h"
|
||||
#include "obj.h"
|
||||
#include "objstr.h"
|
||||
#include "smallint.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
@@ -253,8 +254,8 @@ STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
|
||||
}
|
||||
mp_obj_t args[2];
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(i1 / i2);
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(i1 % i2);
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(i1, i2));
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(i1, i2));
|
||||
return mp_obj_new_tuple(2, args);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {
|
||||
@@ -415,9 +416,9 @@ STATIC mp_obj_t mp_builtin_print(mp_uint_t n_args, const mp_obj_t *args, mp_map_
|
||||
|
||||
pfenv_t pfenv;
|
||||
pfenv.data = stream_obj;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, unsigned int))mp_stream_write;
|
||||
pfenv.print_strn = (void (*)(void *, const char *, mp_uint_t))mp_stream_write;
|
||||
#endif
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
if (i > 0) {
|
||||
#if MICROPY_PY_IO
|
||||
mp_stream_write(stream_obj, sep_data, sep_len);
|
||||
@@ -447,9 +448,30 @@ STATIC mp_obj_t mp_builtin_repr(mp_obj_t o_in) {
|
||||
vstr_free(vstr);
|
||||
return s;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_repr_obj, mp_builtin_repr);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_round(mp_obj_t o_in) {
|
||||
// TODO support second arg
|
||||
if (MP_OBJ_IS_INT(o_in)) {
|
||||
return o_in;
|
||||
}
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t val = mp_obj_get_float(o_in);
|
||||
mp_float_t rounded = MICROPY_FLOAT_C_FUN(round)(val);
|
||||
mp_int_t r = rounded;
|
||||
// make rounded value even if it was halfway between ints
|
||||
if (val - rounded == 0.5) {
|
||||
r = (r + 1) & (~1);
|
||||
} else if (val - rounded == -0.5) {
|
||||
r &= ~1;
|
||||
}
|
||||
#else
|
||||
mp_int_t r = mp_obj_get_int(o_in);
|
||||
#endif
|
||||
return mp_obj_new_int(r);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_round_obj, mp_builtin_round);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_sum(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
assert(1 <= n_args && n_args <= 2);
|
||||
mp_obj_t value;
|
||||
|
||||
10
py/builtin.h
@@ -24,8 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args);
|
||||
mp_obj_t mp_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj);
|
||||
@@ -35,6 +35,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj);
|
||||
@@ -60,6 +61,7 @@ MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_round_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj);
|
||||
|
||||
@@ -88,5 +90,7 @@ extern struct _dummy_t mp_sys_stderr_obj;
|
||||
|
||||
// extmod modules
|
||||
extern const mp_obj_module_t mp_module_uctypes;
|
||||
extern const mp_obj_module_t mp_module_zlibd;
|
||||
extern const mp_obj_module_t mp_module_uzlib;
|
||||
extern const mp_obj_module_t mp_module_ujson;
|
||||
extern const mp_obj_module_t mp_module_ure;
|
||||
extern const mp_obj_module_t mp_module_uheapq;
|
||||
|
||||
144
py/builtinevex.c
@@ -34,72 +34,120 @@
|
||||
#include "lexerunix.h"
|
||||
#include "parse.h"
|
||||
#include "obj.h"
|
||||
#include "objfun.h"
|
||||
#include "parsehelper.h"
|
||||
#include "compile.h"
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
|
||||
STATIC mp_obj_t parse_compile_execute(mp_obj_t o_in, mp_parse_input_kind_t parse_input_kind) {
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(o_in, &str_len);
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
typedef struct _mp_obj_code_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t module_fun;
|
||||
} mp_obj_code_t;
|
||||
|
||||
// parse the string
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, parse_input_kind, &parse_error_kind);
|
||||
STATIC const mp_obj_type_t mp_type_code = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_code,
|
||||
};
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error; raise exception
|
||||
mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
nlr_raise(exc);
|
||||
}
|
||||
|
||||
mp_lexer_free(lex);
|
||||
|
||||
// compile the string
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
// TODO handle compile error correctly
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
// complied successfully, execute it
|
||||
return mp_call_function_0(module_fun);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_eval(mp_obj_t o_in) {
|
||||
return parse_compile_execute(o_in, MP_PARSE_EVAL_INPUT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_eval_obj, mp_builtin_eval);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_exec(uint n_args, const mp_obj_t *args) {
|
||||
// Unconditional getting/setting assumes that these operations
|
||||
// are cheap, which is the case when this comment was written.
|
||||
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_t globals, mp_obj_t locals) {
|
||||
// save context and set new context
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
||||
mp_globals_set(globals);
|
||||
mp_locals_set(locals);
|
||||
|
||||
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
|
||||
// the correct one
|
||||
if (MP_OBJ_IS_TYPE(self->module_fun, &mp_type_fun_bc)) {
|
||||
mp_obj_fun_bc_t *fun_bc = self->module_fun;
|
||||
fun_bc->globals = globals;
|
||||
}
|
||||
|
||||
// execute code
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_obj_t ret = mp_call_function_0(self->module_fun);
|
||||
nlr_pop();
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return ret;
|
||||
} else {
|
||||
// exception; restore context and re-raise same exception
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
nlr_raise(nlr.ret_val);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_compile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// get the source
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||
|
||||
// get the filename
|
||||
qstr filename = mp_obj_str_get_qstr(args[1]);
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(filename, str, str_len, 0);
|
||||
|
||||
// get the compile mode
|
||||
qstr mode = mp_obj_str_get_qstr(args[2]);
|
||||
mp_parse_input_kind_t parse_input_kind;
|
||||
switch (mode) {
|
||||
case MP_QSTR_single: parse_input_kind = MP_PARSE_SINGLE_INPUT; break;
|
||||
case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break;
|
||||
case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break;
|
||||
default:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode"));
|
||||
}
|
||||
|
||||
mp_obj_code_t *code = m_new_obj(mp_obj_code_t);
|
||||
code->base.type = &mp_type_code;
|
||||
code->module_fun = mp_parse_compile_execute(lex, parse_input_kind, NULL, NULL);
|
||||
return code;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_compile);
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_COMPILE
|
||||
|
||||
STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) {
|
||||
// work out the context
|
||||
mp_obj_dict_t *globals = mp_globals_get();
|
||||
mp_obj_dict_t *locals = mp_locals_get();
|
||||
if (n_args > 1) {
|
||||
mp_obj_t globals = args[1];
|
||||
mp_obj_t locals;
|
||||
globals = args[1];
|
||||
if (n_args > 2) {
|
||||
locals = args[2];
|
||||
} else {
|
||||
locals = globals;
|
||||
}
|
||||
mp_globals_set(globals);
|
||||
mp_locals_set(locals);
|
||||
}
|
||||
mp_obj_t res = parse_compile_execute(args[0], MP_PARSE_FILE_INPUT);
|
||||
// TODO if the above call throws an exception, then we never get to reset the globals/locals
|
||||
mp_globals_set(old_globals);
|
||||
mp_locals_set(old_locals);
|
||||
return res;
|
||||
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
if (MP_OBJ_IS_TYPE(args[0], &mp_type_code)) {
|
||||
return code_execute(args[0], globals, locals);
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_uint_t str_len;
|
||||
const char *str = mp_obj_str_get_data(args[0], &str_len);
|
||||
|
||||
// create the lexer
|
||||
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_string_gt_, str, str_len, 0);
|
||||
|
||||
return mp_parse_compile_execute(lex, parse_input_kind, globals, locals);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_builtin_eval(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
return eval_exec_helper(n_args, args, MP_PARSE_EVAL_INPUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj, 1, 3, mp_builtin_eval);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_exec(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
return eval_exec_helper(n_args, args, MP_PARSE_FILE_INPUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "runtime0.h"
|
||||
#include "runtime.h"
|
||||
#include "builtin.h"
|
||||
#include "builtintables.h"
|
||||
|
||||
#if 0 // print debugging info
|
||||
#define DEBUG_PRINT (1)
|
||||
@@ -54,6 +55,12 @@
|
||||
|
||||
#define PATH_SEP_CHAR '/'
|
||||
|
||||
bool mp_obj_is_package(mp_obj_t module) {
|
||||
mp_obj_t dest[2];
|
||||
mp_load_method_maybe(module, MP_QSTR___path__, dest);
|
||||
return dest[0] != MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
STATIC mp_import_stat_t stat_dir_or_file(vstr_t *path) {
|
||||
//printf("stat %s\n", vstr_str(path));
|
||||
mp_import_stat_t stat = mp_import_stat(vstr_str(path));
|
||||
@@ -82,7 +89,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d
|
||||
return stat_dir_or_file(dest);
|
||||
} else {
|
||||
// go through each path looking for a directory or file
|
||||
for (int i = 0; i < path_num; i++) {
|
||||
for (mp_uint_t i = 0; i < path_num; i++) {
|
||||
vstr_reset(dest);
|
||||
mp_uint_t p_len;
|
||||
const char *p = mp_obj_str_get_data(path_items[i], &p_len);
|
||||
@@ -111,63 +118,20 @@ STATIC void do_load(mp_obj_t module_obj, vstr_t *file) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", vstr_str(file)));
|
||||
}
|
||||
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
|
||||
// save the old context
|
||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
||||
|
||||
// set the new context
|
||||
mp_locals_set(mp_obj_module_get_globals(module_obj));
|
||||
mp_globals_set(mp_obj_module_get_globals(module_obj));
|
||||
#if MICROPY_PY___FILE__
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, mp_obj_new_str(vstr_str(file), vstr_len(file), false));
|
||||
qstr source_name = mp_lexer_source_name(lex);
|
||||
mp_store_attr(module_obj, MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
|
||||
#endif
|
||||
|
||||
// parse the imported script
|
||||
mp_parse_error_kind_t parse_error_kind;
|
||||
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
|
||||
|
||||
if (pn == MP_PARSE_NODE_NULL) {
|
||||
// parse error; clean up and raise exception
|
||||
mp_obj_t exc = mp_parse_make_exception(lex, parse_error_kind);
|
||||
mp_lexer_free(lex);
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(exc);
|
||||
}
|
||||
|
||||
mp_lexer_free(lex);
|
||||
|
||||
// compile the imported script
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, false);
|
||||
|
||||
if (module_fun == mp_const_none) {
|
||||
// TODO handle compile error correctly
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_SyntaxError, "Syntax error in imported module"));
|
||||
}
|
||||
|
||||
// complied successfully, execute it
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
// exception; restore context and re-raise same exception
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
nlr_raise(nlr.ret_val);
|
||||
}
|
||||
mp_locals_set(old_locals);
|
||||
mp_globals_set(old_globals);
|
||||
// parse, compile and execute the module in its context
|
||||
mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj);
|
||||
mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals);
|
||||
}
|
||||
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
mp_obj_t mp_builtin___import__(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
#if DEBUG_PRINT
|
||||
DEBUG_printf("__import__:\n");
|
||||
for (int i = 0; i < n_args; i++) {
|
||||
for (mp_uint_t i = 0; i < n_args; i++) {
|
||||
DEBUG_printf(" ");
|
||||
mp_obj_print(args[i], PRINT_REPR);
|
||||
DEBUG_printf("\n");
|
||||
@@ -176,7 +140,7 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
|
||||
mp_obj_t module_name = args[0];
|
||||
mp_obj_t fromtuple = mp_const_none;
|
||||
int level = 0;
|
||||
mp_int_t level = 0;
|
||||
if (n_args >= 4) {
|
||||
fromtuple = args[3];
|
||||
if (n_args >= 5) {
|
||||
@@ -294,17 +258,42 @@ mp_obj_t mp_builtin___import__(mp_uint_t n_args, mp_obj_t *args) {
|
||||
}
|
||||
DEBUG_printf("Current path: %s\n", vstr_str(&path));
|
||||
|
||||
// fail if we couldn't find the file
|
||||
if (stat == MP_IMPORT_STAT_NO_EXIST) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", qstr_str(mod_name)));
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
// check if there is a weak link to this module
|
||||
if (i == mod_len) {
|
||||
mp_map_elem_t *el = mp_map_lookup((mp_map_t*)&mp_builtin_module_weak_links_dict_obj.map, MP_OBJ_NEW_QSTR(mod_name), MP_MAP_LOOKUP);
|
||||
if (el == NULL) {
|
||||
goto no_exist;
|
||||
}
|
||||
// found weak linked module
|
||||
module_obj = el->value;
|
||||
} else {
|
||||
no_exist:
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
// couldn't find the file, so fail
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "No module named '%s'", qstr_str(mod_name)));
|
||||
}
|
||||
} else {
|
||||
// found the file, so get the module
|
||||
module_obj = mp_module_get(mod_name);
|
||||
}
|
||||
|
||||
module_obj = mp_module_get(mod_name);
|
||||
if (module_obj == MP_OBJ_NULL) {
|
||||
// module not already loaded, so load it!
|
||||
|
||||
module_obj = mp_obj_new_module(mod_name);
|
||||
|
||||
// if args[3] (fromtuple) has magic value False, set up
|
||||
// this module for command-line "-m" option (set module's
|
||||
// name to __main__ instead of real name).
|
||||
if (i == mod_len && fromtuple == mp_const_false) {
|
||||
mp_obj_module_t *o = module_obj;
|
||||
mp_obj_dict_store(o->globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__));
|
||||
}
|
||||
|
||||
if (stat == MP_IMPORT_STAT_DIR) {
|
||||
DEBUG_printf("%s is dir\n", vstr_str(&path));
|
||||
// https://docs.python.org/3/reference/import.html
|
||||
|
||||
@@ -61,6 +61,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_int), (mp_obj_t)&mp_type_int },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_list), (mp_obj_t)&mp_type_list },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_map), (mp_obj_t)&mp_type_map },
|
||||
#if MICROPY_PY_BUILTINS_MEMORYVIEW
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_memoryview), (mp_obj_t)&mp_type_memoryview },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_object), (mp_obj_t)&mp_type_object },
|
||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_property), (mp_obj_t)&mp_type_property },
|
||||
@@ -88,6 +91,9 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&mp_builtin_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bin), (mp_obj_t)&mp_builtin_bin_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callable), (mp_obj_t)&mp_builtin_callable_obj },
|
||||
#if MICROPY_PY_BUILTINS_COMPILE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_compile), (mp_obj_t)&mp_builtin_compile_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_chr), (mp_obj_t)&mp_builtin_chr_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dir), (mp_obj_t)&mp_builtin_dir_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_divmod), (mp_obj_t)&mp_builtin_divmod_obj },
|
||||
@@ -112,6 +118,7 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pow), (mp_obj_t)&mp_builtin_pow_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_print), (mp_obj_t)&mp_builtin_print_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_repr), (mp_obj_t)&mp_builtin_repr_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_round), (mp_obj_t)&mp_builtin_round_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sorted), (mp_obj_t)&mp_builtin_sorted_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&mp_builtin_sum_obj },
|
||||
|
||||
@@ -136,7 +143,6 @@ STATIC const mp_map_elem_t mp_builtin_object_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RuntimeError), (mp_obj_t)&mp_type_RuntimeError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_StopIteration), (mp_obj_t)&mp_type_StopIteration },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SyntaxError), (mp_obj_t)&mp_type_SyntaxError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemError), (mp_obj_t)&mp_type_SystemError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SystemExit), (mp_obj_t)&mp_type_SystemExit },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_TypeError), (mp_obj_t)&mp_type_TypeError },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ValueError), (mp_obj_t)&mp_type_ValueError },
|
||||
@@ -203,12 +209,18 @@ STATIC const mp_map_elem_t mp_builtin_module_table[] = {
|
||||
#if MICROPY_PY_UCTYPES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
|
||||
#endif
|
||||
#if MICROPY_PY_ZLIBD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_zlibd), (mp_obj_t)&mp_module_zlibd },
|
||||
#if MICROPY_PY_UZLIB
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uzlib), (mp_obj_t)&mp_module_uzlib },
|
||||
#endif
|
||||
#if MICROPY_PY_UJSON
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ujson), (mp_obj_t)&mp_module_ujson },
|
||||
#endif
|
||||
#if MICROPY_PY_URE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ure), (mp_obj_t)&mp_module_ure },
|
||||
#endif
|
||||
#if MICROPY_PY_UHEAPQ
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uheapq), (mp_obj_t)&mp_module_uheapq },
|
||||
#endif
|
||||
|
||||
// extra builtin modules as defined by a port
|
||||
MICROPY_PORT_BUILTIN_MODULES
|
||||
@@ -224,3 +236,20 @@ const mp_obj_dict_t mp_builtin_module_dict_obj = {
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_table,
|
||||
},
|
||||
};
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
STATIC const mp_map_elem_t mp_builtin_module_weak_links_table[] = {
|
||||
MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS
|
||||
};
|
||||
|
||||
const mp_obj_dict_t mp_builtin_module_weak_links_dict_obj = {
|
||||
.base = {&mp_type_dict},
|
||||
.map = {
|
||||
.all_keys_are_qstrs = 1,
|
||||
.table_is_fixed_array = 1,
|
||||
.used = MP_ARRAY_SIZE(mp_builtin_module_weak_links_table),
|
||||
.alloc = MP_ARRAY_SIZE(mp_builtin_module_weak_links_table),
|
||||
.table = (mp_map_elem_t*)mp_builtin_module_weak_links_table,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -26,3 +26,7 @@
|
||||
|
||||
extern const mp_obj_dict_t mp_builtin_object_dict_obj;
|
||||
extern const mp_obj_dict_t mp_builtin_module_dict_obj;
|
||||
|
||||
#if MICROPY_MODULE_WEAK_LINKS
|
||||
extern const mp_obj_dict_t mp_builtin_module_weak_links_dict_obj;
|
||||
#endif
|
||||
|
||||
183
py/compile.c
@@ -62,24 +62,29 @@ typedef enum {
|
||||
#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))
|
||||
#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))
|
||||
|
||||
// elements in this struct are ordered to make it compact
|
||||
typedef struct _compiler_t {
|
||||
qstr source_file;
|
||||
|
||||
uint8_t is_repl;
|
||||
uint8_t pass; // holds enum type pass_kind_t
|
||||
uint8_t had_error; // try to keep compiler clean from nlr
|
||||
uint8_t func_arg_is_super; // used to compile special case of super() function call
|
||||
uint8_t have_star;
|
||||
|
||||
// try to keep compiler clean from nlr
|
||||
// this is set to an exception object if we have a compile error
|
||||
mp_obj_t compile_error;
|
||||
|
||||
uint next_label;
|
||||
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
int break_continue_except_level;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
|
||||
uint8_t have_star;
|
||||
uint16_t num_dict_params;
|
||||
uint16_t num_default_params;
|
||||
|
||||
uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
|
||||
uint16_t continue_label;
|
||||
uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
|
||||
uint16_t break_continue_except_level;
|
||||
|
||||
scope_t *scope_head;
|
||||
scope_t *scope_cur;
|
||||
|
||||
@@ -91,14 +96,15 @@ typedef struct _compiler_t {
|
||||
} compiler_t;
|
||||
|
||||
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
|
||||
// TODO store the error message to a variable in compiler_t instead of printing it
|
||||
mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
|
||||
// we don't have a 'block' name, so just pass the NULL qstr to indicate this
|
||||
if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line);
|
||||
mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL);
|
||||
} else {
|
||||
printf(" File \"%s\"\n", qstr_str(comp->source_file));
|
||||
// we don't have a line number, so just pass 0
|
||||
mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL);
|
||||
}
|
||||
printf("SyntaxError: %s\n", msg);
|
||||
comp->had_error = true;
|
||||
comp->compile_error = exc;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t mp_constants_table[] = {
|
||||
@@ -227,6 +233,11 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
||||
}
|
||||
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
|
||||
// int >> int
|
||||
if (arg1 >= BITS_PER_WORD) {
|
||||
// Shifting to big amounts is underfined behavior
|
||||
// in C and is CPU-dependent; propagate sign bit.
|
||||
arg1 = BITS_PER_WORD - 1;
|
||||
}
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
|
||||
} else {
|
||||
// shouldn't happen
|
||||
@@ -493,14 +504,14 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst
|
||||
return;
|
||||
}
|
||||
|
||||
int arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: assert(0);
|
||||
case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
|
||||
case MP_PARSE_NODE_STRING:
|
||||
case MP_PARSE_NODE_BYTES: {
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(arg, &len);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
|
||||
break;
|
||||
@@ -597,12 +608,13 @@ void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
}
|
||||
|
||||
STATIC bool node_is_const_false(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE);
|
||||
// untested: || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
|
||||
}
|
||||
|
||||
STATIC bool node_is_const_true(mp_parse_node_t pn) {
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 1);
|
||||
return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE)
|
||||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
@@ -853,7 +865,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
||||
assert(0);
|
||||
} else if (MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
int arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (assign_kind) {
|
||||
case ASSIGN_STORE:
|
||||
case ASSIGN_AUG_STORE:
|
||||
@@ -1107,7 +1119,7 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint
|
||||
comp->num_default_params = 0;
|
||||
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
|
||||
|
||||
if (comp->had_error) {
|
||||
if (comp->compile_error != MP_OBJ_NULL) {
|
||||
return MP_QSTR_NULL;
|
||||
}
|
||||
|
||||
@@ -1361,6 +1373,7 @@ void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (comp->break_label == 0) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop");
|
||||
}
|
||||
assert(comp->cur_except_level >= comp->break_continue_except_level);
|
||||
EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level);
|
||||
}
|
||||
|
||||
@@ -1368,6 +1381,7 @@ void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
if (comp->continue_label == 0) {
|
||||
compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop");
|
||||
}
|
||||
assert(comp->cur_except_level >= comp->break_continue_except_level);
|
||||
EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level);
|
||||
}
|
||||
|
||||
@@ -1459,7 +1473,7 @@ STATIC void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q_base) {
|
||||
if (i > 0) {
|
||||
*str_dest++ = '.';
|
||||
}
|
||||
uint str_src_len;
|
||||
mp_uint_t str_src_len;
|
||||
const byte *str_src = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &str_src_len);
|
||||
memcpy(str_dest, str_src, str_src_len);
|
||||
str_dest += str_src_len;
|
||||
@@ -1564,7 +1578,7 @@ void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
vstr_printf(vstr, ", ");
|
||||
}
|
||||
vstr_printf(vstr, "'");
|
||||
uint len;
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(id2, &len);
|
||||
vstr_add_strn(vstr, (const char*)str, len);
|
||||
vstr_printf(vstr, "'");
|
||||
@@ -1650,54 +1664,52 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
||||
uint l_end = comp_next_label(comp);
|
||||
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
|
||||
if (
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// optimisation to not jump over non-existent elif/else blocks (this optimisation is not in CPython)
|
||||
!(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])) &&
|
||||
#endif
|
||||
// optimisation to not jump if last instruction was return
|
||||
!EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
// optimisation: skip everything else when "if True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (
|
||||
// optimisation: don't jump over non-existent elif/else blocks (not in CPython)
|
||||
(MICROPY_EMIT_CPYTHON || !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])))
|
||||
// optimisation: don't jump if last instruction was return
|
||||
&& !EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
// jump over elif/else blocks
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
// compile elif blocks (if any)
|
||||
mp_parse_node_t *pn_elif;
|
||||
int n_elif = list_get(&pns->nodes[2], PN_if_stmt_elif_list, &pn_elif);
|
||||
for (int i = 0; i < n_elif; i++) {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pn_elif[i];
|
||||
|
||||
if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
|
||||
// compile elif blocks
|
||||
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pns->nodes[2];
|
||||
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns_elif) == PN_if_stmt_elif_list) {
|
||||
// multiple elif blocks
|
||||
|
||||
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_elif);
|
||||
for (int i = 0; i < n; i++) {
|
||||
mp_parse_node_struct_t *pns_elif2 = (mp_parse_node_struct_t*)pns_elif->nodes[i];
|
||||
l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif2->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif2->nodes[1]); // elif block
|
||||
if (!EMIT(last_emit_was_return_value)) { // simple optimisation to align with CPython
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
}
|
||||
|
||||
} else {
|
||||
// a single elif block
|
||||
|
||||
l_fail = comp_next_label(comp);
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns_elif->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif->nodes[1]); // elif block
|
||||
if (!EMIT(last_emit_was_return_value)) { // simple optimisation to align with CPython
|
||||
|
||||
// optimisation: skip everything else when "elif True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns_elif->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// optimisation: don't jump if last instruction was return
|
||||
if (!EMIT(last_emit_was_return_value)) {
|
||||
EMIT_ARG(jump, l_end);
|
||||
}
|
||||
EMIT_ARG(label_assign, l_fail);
|
||||
@@ -1707,12 +1719,14 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
// compile else block
|
||||
compile_node(comp, pns->nodes[3]); // can be null
|
||||
|
||||
done:
|
||||
EMIT_ARG(label_assign, l_end);
|
||||
}
|
||||
|
||||
#define START_BREAK_CONTINUE_BLOCK \
|
||||
uint old_break_label = comp->break_label; \
|
||||
uint old_continue_label = comp->continue_label; \
|
||||
uint16_t old_break_label = comp->break_label; \
|
||||
uint16_t old_continue_label = comp->continue_label; \
|
||||
uint16_t old_break_continue_except_level = comp->break_continue_except_level; \
|
||||
uint break_label = comp_next_label(comp); \
|
||||
uint continue_label = comp_next_label(comp); \
|
||||
comp->break_label = break_label; \
|
||||
@@ -1722,7 +1736,7 @@ void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#define END_BREAK_CONTINUE_BLOCK \
|
||||
comp->break_label = old_break_label; \
|
||||
comp->continue_label = old_continue_label; \
|
||||
comp->break_continue_except_level = comp->cur_except_level;
|
||||
comp->break_continue_except_level = old_break_continue_except_level;
|
||||
|
||||
void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
@@ -1744,12 +1758,16 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
EMIT(pop_block);
|
||||
}
|
||||
#else
|
||||
uint top_label = comp_next_label(comp);
|
||||
EMIT_ARG(jump, continue_label);
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
if (!node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False"
|
||||
uint top_label = comp_next_label(comp);
|
||||
if (!node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for "while True"
|
||||
EMIT_ARG(jump, continue_label);
|
||||
}
|
||||
EMIT_ARG(label_assign, top_label);
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
}
|
||||
#endif
|
||||
|
||||
// break/continue apply to outer loop (if any) in the else block
|
||||
@@ -2563,7 +2581,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
byte *s_dest = qstr_build_start(n_bytes, &q_ptr);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (MP_PARSE_NODE_IS_LEAF(pns->nodes[i])) {
|
||||
uint s_len;
|
||||
mp_uint_t s_len;
|
||||
const byte *s = qstr_data(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]), &s_len);
|
||||
memcpy(s_dest, s, s_len);
|
||||
s_dest += s_len;
|
||||
@@ -3415,7 +3433,8 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
||||
if (comp->pass > MP_PASS_SCOPE) {
|
||||
bool success = EMIT_INLINE_ASM(end_pass);
|
||||
if (!success) {
|
||||
comp->had_error = true;
|
||||
// TODO get proper exception from inline assembler
|
||||
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "inline assembler error");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3550,6 +3569,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
compiler_t *comp = m_new0(compiler_t, 1);
|
||||
comp->source_file = source_file;
|
||||
comp->is_repl = is_repl;
|
||||
comp->compile_error = MP_OBJ_NULL;
|
||||
|
||||
// optimise constants
|
||||
mp_map_t consts;
|
||||
@@ -3566,7 +3586,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
comp->emit_inline_asm = NULL;
|
||||
comp->emit_inline_asm_method_table = NULL;
|
||||
uint max_num_labels = 0;
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (false) {
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
} else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) {
|
||||
@@ -3583,7 +3603,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
}
|
||||
|
||||
// compute some things related to scope and identifiers
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
compile_scope_compute_things(comp, s);
|
||||
}
|
||||
|
||||
@@ -3600,7 +3620,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
emit_inline_asm_t *emit_inline_thumb = NULL;
|
||||
#endif
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
for (scope_t *s = comp->scope_head; s != NULL && !comp->had_error; s = s->next) {
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (false) {
|
||||
// dummy
|
||||
|
||||
@@ -3615,7 +3635,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
comp->emit_inline_asm = emit_inline_thumb;
|
||||
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
|
||||
compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope_inline_asm(comp, s, MP_PASS_EMIT);
|
||||
}
|
||||
#endif
|
||||
@@ -3674,12 +3694,12 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
// second last pass: compute code size
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_CODE_SIZE);
|
||||
}
|
||||
|
||||
// final pass: emit code
|
||||
if (!comp->had_error) {
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_EMIT);
|
||||
}
|
||||
}
|
||||
@@ -3722,12 +3742,11 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
||||
}
|
||||
|
||||
// free the compiler
|
||||
bool had_error = comp->had_error;
|
||||
mp_obj_t compile_error = comp->compile_error;
|
||||
m_del_obj(compiler_t, comp);
|
||||
|
||||
if (had_error) {
|
||||
// TODO return a proper error message
|
||||
return mp_const_none;
|
||||
if (compile_error != MP_OBJ_NULL) {
|
||||
return compile_error;
|
||||
} else {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// can't create code, so just return true
|
||||
|
||||