Merge pull request #49 from amirgon/update_micropython_v1.18
Update micropython v1.18 Related: https://github.com/lvgl/lv_binding_micropython/issues/203
This commit is contained in:
commit
f61da15cc3
18
.github/workflows/ports.yml
vendored
Normal file
18
.github/workflows/ports.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
name: Build ports metadata
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/*.yml'
|
||||||
|
- 'tools/**'
|
||||||
|
- ports/**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build ports download metadata
|
||||||
|
run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards
|
||||||
4
.github/workflows/ports_esp32.yml
vendored
4
.github/workflows/ports_esp32.yml
vendored
@ -24,13 +24,13 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_esp32_build
|
run: source tools/ci.sh && ci_esp32_build
|
||||||
|
|
||||||
build_idf43:
|
build_idf44:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Initialize lv_bindings submodule
|
- name: Initialize lv_bindings submodule
|
||||||
run: git submodule update --init --recursive lib/lv_bindings
|
run: git submodule update --init --recursive lib/lv_bindings
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_esp32_idf43_setup
|
run: source tools/ci.sh && ci_esp32_idf44_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_esp32_build
|
run: source tools/ci.sh && ci_esp32_build
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,6 +58,7 @@ __pycache__/
|
|||||||
GNUmakefile
|
GNUmakefile
|
||||||
user.props
|
user.props
|
||||||
ports/javascript/node_modules
|
ports/javascript/node_modules
|
||||||
|
.vscode/
|
||||||
|
|
||||||
# Generated rst files
|
# Generated rst files
|
||||||
######################
|
######################
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -26,12 +26,13 @@
|
|||||||
[submodule "lib/asf4"]
|
[submodule "lib/asf4"]
|
||||||
path = lib/asf4
|
path = lib/asf4
|
||||||
url = https://github.com/adafruit/asf4
|
url = https://github.com/adafruit/asf4
|
||||||
|
branch = circuitpython
|
||||||
[submodule "lib/tinyusb"]
|
[submodule "lib/tinyusb"]
|
||||||
path = lib/tinyusb
|
path = lib/tinyusb
|
||||||
url = https://github.com/hathach/tinyusb
|
url = https://github.com/hathach/tinyusb
|
||||||
[submodule "lib/mynewt-nimble"]
|
[submodule "lib/mynewt-nimble"]
|
||||||
path = lib/mynewt-nimble
|
path = lib/mynewt-nimble
|
||||||
url = https://github.com/apache/mynewt-nimble.git
|
url = https://github.com/micropython/mynewt-nimble.git
|
||||||
[submodule "lib/btstack"]
|
[submodule "lib/btstack"]
|
||||||
path = lib/btstack
|
path = lib/btstack
|
||||||
url = https://github.com/bluekitchen/btstack.git
|
url = https://github.com/bluekitchen/btstack.git
|
||||||
|
|||||||
2
.gitpod
2
.gitpod
@ -11,6 +11,8 @@ tasks:
|
|||||||
make -C ports/unix VARIANT=dev DEBUG=1 submodules
|
make -C ports/unix VARIANT=dev DEBUG=1 submodules
|
||||||
make -j $(nproc) -C mpy-cross VARIANT=dev DEBUG=1
|
make -j $(nproc) -C mpy-cross VARIANT=dev DEBUG=1
|
||||||
make -j $(nproc) -C ports/unix VARIANT=dev DEBUG=1
|
make -j $(nproc) -C ports/unix VARIANT=dev DEBUG=1
|
||||||
|
source tools/ci.sh && ci_esp32_idf44_setup
|
||||||
|
source tools/ci.sh && ci_esp32_build
|
||||||
command: |
|
command: |
|
||||||
xrandr --fb 500x500 # Fix resolution for LVGL screens which are smaller
|
xrandr --fb 500x500 # Fix resolution for LVGL screens which are smaller
|
||||||
ports/unix/micropython-dev -i lib/lv_bindings/examples/advanced_demo.py
|
ports/unix/micropython-dev -i lib/lv_bindings/examples/advanced_demo.py
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2013-2021 Damien P. George
|
Copyright (c) 2013-2022 Damien P. George
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@ -66,7 +66,7 @@ master_doc = 'index'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = 'MicroPython'
|
project = 'MicroPython'
|
||||||
copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
|
copyright = '- The MicroPython Documentation is Copyright © 2014-2022, Damien P. George, Paul Sokolovsky, and contributors'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
@ -74,7 +74,7 @@ copyright = '- The MicroPython Documentation is Copyright © 2014-2021, Damien P
|
|||||||
#
|
#
|
||||||
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
|
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
|
||||||
# breakdown, so use the same version identifier for both to avoid confusion.
|
# breakdown, so use the same version identifier for both to avoid confusion.
|
||||||
version = release = '1.17'
|
version = release = '1.18'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|||||||
@ -16,4 +16,3 @@ live in the main MicroPython repository.
|
|||||||
|
|
||||||
cmodules.rst
|
cmodules.rst
|
||||||
natmod.rst
|
natmod.rst
|
||||||
|
|
||||||
@ -24,4 +24,3 @@ MicroPython to a new platform and implementing a core MicroPython library.
|
|||||||
publiccapi.rst
|
publiccapi.rst
|
||||||
extendingmicropython.rst
|
extendingmicropython.rst
|
||||||
porting.rst
|
porting.rst
|
||||||
|
|
||||||
@ -53,8 +53,6 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main.
|
|||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
gc_init(heap, heap + sizeof(heap));
|
gc_init(heap, heap + sizeof(heap));
|
||||||
mp_init();
|
mp_init();
|
||||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
|
|
||||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
|
|
||||||
|
|
||||||
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
|
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
|
||||||
pyexec_friendly_repl();
|
pyexec_friendly_repl();
|
||||||
|
|||||||
@ -3,8 +3,21 @@
|
|||||||
MicroPython differences from CPython
|
MicroPython differences from CPython
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
The operations listed in this section produce conflicting results in MicroPython when compared to standard Python.
|
MicroPython implements Python 3.4 and some select features of Python 3.5 and
|
||||||
MicroPython implements Python 3.4 and some select features of Python 3.5.
|
above. The sections below describe the current status of these features.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
|
||||||
|
../differences/python_35.rst
|
||||||
|
../differences/python_36.rst
|
||||||
|
../differences/python_37.rst
|
||||||
|
../differences/python_38.rst
|
||||||
|
../differences/python_39.rst
|
||||||
|
|
||||||
|
For the features of Python that are implemented by MicroPython, there are
|
||||||
|
sometimes differences in their behaviour compared to standard Python. The
|
||||||
|
operations listed in the sections below produce conflicting results in
|
||||||
|
MicroPython when compared to standard Python.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|||||||
181
docs/differences/python_35.rst
Normal file
181
docs/differences/python_35.rst
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
.. _python_35:
|
||||||
|
|
||||||
|
Python 3.5
|
||||||
|
==========
|
||||||
|
|
||||||
|
Below is a list of finalised/accepted PEPs for Python 3.5 grouped into their impact to MicroPython.
|
||||||
|
|
||||||
|
+----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| **Extensions to the syntax:** | **Status** |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 448 <https://www.python.org/dev/peps/pep-0448/>`_ | additional unpacking generalizations | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 465 <https://www.python.org/dev/peps/pep-0465/>`_ | a new matrix multiplication operator | Completed |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 492 <https://www.python.org/dev/peps/pep-0492/>`_ | coroutines with async and await syntax | Completed |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| **Extensions and changes to runtime:** |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 461 <https://www.python.org/dev/peps/pep-0461/>`_ | % formatting for binary strings | Completed |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 475 <https://www.python.org/dev/peps/pep-0475/>`_ | retrying system calls that fail with EINTR | Completed |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 479 <https://www.python.org/dev/peps/pep-0479/>`_ | change StopIteration handling inside generators | Completed |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| **Standard library changes:** |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 471 <https://www.python.org/dev/peps/pep-0471/>`_ | os.scandir() | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 485 <https://www.python.org/dev/peps/pep-0485/>`_ | math.isclose(), a function for testing | Completed |
|
||||||
|
| | approximate equality | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| **Miscellaneous changes:** |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 441 <https://www.python.org/dev/peps/pep-0441/>`_ | improved Python zip application support | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 486 <https://www.python.org/dev/peps/pep-0486/>`_ | make the Python Laucher aware of virtual | |
|
||||||
|
| | environments | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ | type hints (advisory only) | In Progress |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 488 <https://www.python.org/dev/peps/pep-0488/>`_ | elimination of PYO files | Not relevant |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
| `PEP 489 <https://www.python.org/dev/peps/pep-0489/>`_ | redesigning extension module loading | |
|
||||||
|
+--------------------------------------------------------+-------------------------------------------------+---------------+
|
||||||
|
|
||||||
|
|
||||||
|
Other Language Changes:
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added the *namereplace* error handlers. The *backslashreplace* error handlers now work with decoding and | |
|
||||||
|
| translating. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Property docstrings are now writable. This is especially useful for collections.namedtuple() docstrings | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Circular imports involving relative imports are now supported. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
|
||||||
|
|
||||||
|
New Modules:
|
||||||
|
|
||||||
|
* `typing <https://docs.python.org/3/whatsnew/3.5.html#typing>`_
|
||||||
|
|
||||||
|
* `zipzap <https://docs.python.org/3/whatsnew/3.5.html#zipapp>`_
|
||||||
|
|
||||||
|
|
||||||
|
Changes to built-in modules:
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `collections <https://docs.python.org/3/whatsnew/3.5.html#collections>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *OrderedDict* class is now implemented in C, which makes it 4 to 100 times faster. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| *OrderedDict.items()* , *OrderedDict.keys()* , *OrderedDict.values()* views now support reversed() | |
|
||||||
|
| iteration. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The deque class now defines *index()*, *insert()*, and *copy()*, and supports the + and * operators. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Docstrings produced by namedtuple() can now be updated. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The UserString class now implements the *__getnewargs__()*, *__rmod__()*, *casefold()*, *format_map()*, | |
|
||||||
|
| *isprintable()*, and *maketrans()* methods to match the corresponding methods of str. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `heapq <https://docs.python.org/3/whatsnew/3.5.html#heapq>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Element comparison in *merge()* can now be customized by passing a key function in a new optional key | |
|
||||||
|
| keyword argument, and a new optional *reverse* keyword argument can be used to reverse element comparison | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `io <https://docs.python.org/3/whatsnew/3.5.html#io>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new *BufferedIOBase.readinto1()* method, that uses at most one call to the underlying raw stream's | |
|
||||||
|
| *RawIOBase.read()* or *RawIOBase.readinto()* methods | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `json <https://docs.python.org/3/whatsnew/3.5.html#json>`_ | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| JSON decoder now raises JSONDecodeError instead of ValueError to provide better context information about | |
|
||||||
|
| the error. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `math <https://docs.python.org/3/whatsnew/3.5.html#math>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Two new constants have been added to the math module: *inf* and *nan*. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new function *isclose()* provides a way to test for approximate equality. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new *gcd()* function has been added. The *fractions.gcd()* function is now deprecated. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `os <https://docs.python.org/3/whatsnew/3.5.html#os>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The new *scandir()* function returning an iterator of DirEntry objects has been added. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *urandom()* function now uses the *getrandom()* syscall on Linux 3.17 or newer, and *getentropy()* on | |
|
||||||
|
| OpenBSD 5.6 and newer, removing the need to use /dev/urandom and avoiding failures due to potential file | |
|
||||||
|
| descriptor exhaustion. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| New *get_blocking()* and *set_blocking()* functions allow getting and setting a file descriptor's blocking| |
|
||||||
|
| mode (O_NONBLOCK.) | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| There is a new *os.path.commonpath()* function returning the longest common sub-path of each passed | |
|
||||||
|
| pathname | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `re <https://docs.python.org/3/whatsnew/3.5.html#re>`_ | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| References and conditional references to groups with fixed length are now allowed in lookbehind assertions| |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The number of capturing groups in regular expressions is no longer limited to 100. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *sub()* and *subn()* functions now replace unmatched groups with empty strings instead of raising an | |
|
||||||
|
| exception. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *re.error* exceptions have new attributes, msg, pattern, pos, lineno, and colno, that provide better | |
|
||||||
|
| context information about the error | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `socket <https://docs.python.org/3/whatsnew/3.5.html#socket>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Functions with timeouts now use a monotonic clock, instead of a system clock. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new *socket.sendfile()* method allows sending a file over a socket by using the high-performance | |
|
||||||
|
| *os.sendfile()* function on UNIX, resulting in uploads being from 2 to 3 times faster than when using | |
|
||||||
|
| plain *socket.send()* | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *socket.sendall()* method no longer resets the socket timeout every time bytes are received or sent. | |
|
||||||
|
| The socket timeout is now the maximum total duration to send all data. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The backlog argument of the *socket.listen()* method is now optional. By default it is set to SOMAXCONN or| |
|
||||||
|
| to 128, whichever is less. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `ssl <https://docs.python.org/3/whatsnew/3.5.html#ssl>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Memory BIO Support | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Application-Layer Protocol Negotiation Support | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| There is a new *SSLSocket.version()* method to query the actual protocol version in use. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The SSLSocket class now implements a *SSLSocket.sendfile()* method. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *SSLSocket.send()* method now raises either the *ssl.SSLWantReadError* or *ssl.SSLWantWriteError* | |
|
||||||
|
| exception on a non-blocking socket if the operation would block. Previously, it would return 0. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *cert_time_to_seconds()* function now interprets the input time as UTC and not as local time, per RFC | |
|
||||||
|
| 5280. Additionally, the return value is always an int. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| New *SSLObject.shared_ciphers()* and *SSLSocket.shared_ciphers()* methods return the list of ciphers sent | |
|
||||||
|
| by the client during the handshake. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *SSLSocket.do_handshake()*, *SSLSocket.read()*, *SSLSocket.shutdown()*, and *SSLSocket.write()* | |
|
||||||
|
| methods of the SSLSocket class no longer reset the socket timeout every time bytes are received or sent. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *match_hostname()* function now supports matching of IP addresses. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `sys <https://docs.python.org/3/whatsnew/3.5.html#sys>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new *set_coroutine_wrapper()* function allows setting a global hook that will be called whenever a | |
|
||||||
|
| coroutine object is created by an async def function. A corresponding *get_coroutine_wrapper()* can be | |
|
||||||
|
| used to obtain a currently set wrapper. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A new *is_finalizing()* function can be used to check if the Python interpreter is shutting down. | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `time <https://docs.python.org/3/whatsnew/3.5.html#time>`_ |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *monotonic()* function is now always available | |
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+---------------+
|
||||||
191
docs/differences/python_36.rst
Normal file
191
docs/differences/python_36.rst
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
.. _python_36:
|
||||||
|
|
||||||
|
Python 3.6
|
||||||
|
==========
|
||||||
|
|
||||||
|
Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new features can be found here:
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------------------------------------+--------------+
|
||||||
|
| **New Syntax Features:** | **Status** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 498 <https://www.python.org/dev/peps/pep-0498/>`_ | Literal String Formatting | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 515 <https://www.python.org/dev/peps/pep-0515/>`_ | Underscores in Numeric Literals | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 525 <https://www.python.org/dev/peps/pep-0525/>`_ | Asynchronous Generators | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_ | Syntax for Variable Annotations (provisional) | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 530 <https://www.python.org/dev/peps/pep-0530/>`_ | Asynchronous Comprehensions | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| **New Built-in Features:** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 468 <https://www.python.org/dev/peps/pep-0468/>`_ | Preserving the order of *kwargs* in a function | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 487 <https://www.python.org/dev/peps/pep-0487/>`_ | Simpler customization of class creation | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 520 <https://www.python.org/dev/peps/pep-0520/>`_ | Preserving Class Attribute Definition Order | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| **Standard Library Changes:** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 495 <https://www.python.org/dev/peps/pep-0495/>`_ | Local Time Disambiguation | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 506 <https://www.python.org/dev/peps/pep-0506/>`_ | Adding A Secrets Module To The Standard Library | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 519 <https://www.python.org/dev/peps/pep-0519/>`_ | Adding a file system path protocol | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| **CPython internals:** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 509 <https://www.python.org/dev/peps/pep-0509/>`_ | Add a private version to dict | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 523 <https://www.python.org/dev/peps/pep-0523/>`_ | Adding a frame evaluation API to CPython | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| **Linux/Window Changes** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 524 <https://www.python.org/dev/peps/pep-0524/>`_ | Make os.urandom() blocking on Linux | |
|
||||||
|
| | (during system startup) | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 528 <https://www.python.org/dev/peps/pep-0528/>`_ | Change Windows console encoding to UTF-8 | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
| `PEP 529 <https://www.python.org/dev/peps/pep-0529/>`_ | Change Windows filesystem encoding to UTF-8 | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+--------------+
|
||||||
|
|
||||||
|
Other Language Changes:
|
||||||
|
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| A *global* or *nonlocal* statement must now textually appear before the first use of the affected name in | |
|
||||||
|
| the same scope. Previously this was a SyntaxWarning. | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| It is now possible to set a special method to None to indicate that the corresponding operation is not | |
|
||||||
|
| available. For example, if a class sets *__iter__()* to *None* , the class is not iterable. | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Long sequences of repeated traceback lines are now abbreviated as *[Previous line repeated {count} more | |
|
||||||
|
| times]* | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Import now raises the new exception *ModuleNotFoundError* when it cannot find a module. Code that currently | |
|
||||||
|
| checks for ImportError (in try-except) will still work. | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Class methods relying on zero-argument *super()* will now work correctly when called from metaclass methods | |
|
||||||
|
| during class creation. | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
|
||||||
|
Changes to built-in modules:
|
||||||
|
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `array <https://docs.python.org/3.6/whatsnew/3.6.html#array>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Exhausted iterators of *array.array* will now stay exhausted even if the iterated array is extended. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `binascii <https://docs.python.org/3.6/whatsnew/3.6.html#binascii>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The b2a_base64() function now accepts an optional newline keyword argument to control whether the newline | |
|
||||||
|
| character is appended to the return value | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `cmath <https://docs.python.org/3.6/whatsnew/3.6.html#cmath>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new cmath.tau (τ) constant has been added | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| New constants: *cmath.inf* and *cmath.nan* to match *math.inf* and *math.nan* , and also *cmath.infj* and | |
|
||||||
|
| *cmath.nanj* to match the format used by complex repr | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `collections <https://docs.python.org/3.6/whatsnew/3.6.html#collections>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new Collection abstract base class has been added to represent sized iterable container classes | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new *Reversible* abstract base class represents iterable classes that also provide the *__reversed__()* | |
|
||||||
|
| method. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new *AsyncGenerator* abstract base class represents asynchronous generators. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The *namedtuple()* function now accepts an optional keyword argument module, which, when specified, is used | |
|
||||||
|
| for the *__module__* attribute of the returned named tuple class. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The verbose and rename arguments for *namedtuple()* are now keyword-only. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Recursive *collections.deque* instances can now be pickled. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `hashlib <https://docs.python.org/3.6/whatsnew/3.6.html#hashlib>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| BLAKE2 hash functions were added to the module. *blake2b()* and *blake2s()* are always available and support | |
|
||||||
|
| the full feature set of BLAKE2. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The SHA-3 hash functions *sha3_224()*, *sha3_256()*, *sha3_384()*, *sha3_512()*, and *SHAKE* hash functions | |
|
||||||
|
| *shake_128()* and *shake_256()* were added. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The password-based key derivation function *scrypt()* is now available with OpenSSL 1.1.0 and newer. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `json <https://docs.python.org/3.6/whatsnew/3.6.html#json>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| *json.load()* and *json.loads()* now support binary input. Encoded JSON should be represented using either | |
|
||||||
|
| UTF-8, UTF-16, or UTF-32. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `math <https://docs.python.org/3.6/whatsnew/3.6.html#math>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new math.tau (τ) constant has been added | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `os <https://docs.python.org/3.6/whatsnew/3.6.html#os>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| A new *close()* method allows explicitly closing a *scandir()* iterator. The *scandir()* iterator now | |
|
||||||
|
| supports the context manager protocol. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| On Linux, *os.urandom()* now blocks until the system urandom entropy pool is initialized to increase the | |
|
||||||
|
| security. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The Linux *getrandom()* syscall (get random bytes) is now exposed as the new *os.getrandom()* function. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `re <https://docs.python.org/3.6/whatsnew/3.6.html#re>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Added support of modifier spans in regular expressions. Examples: *'(?i:p)ython'* matches 'python' and | |
|
||||||
|
| 'Python', but not 'PYTHON'; *'(?i)g(?-i:v)r'* matches *'GvR'* and *'gvr'*, but not *'GVR'* . | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Match object groups can be accessed by *__getitem__*, which is equivalent to *group()*. So *mo['name']* is | |
|
||||||
|
| now equivalent to *mo.group('name')*. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Match objects now support index-like objects as group indices. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `socket <https://docs.python.org/3.6/whatsnew/3.6.html#socket>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The *ioctl()* function now supports the *SIO_LOOPBACK_FAST_PATH* control code. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The *getsockopt()* constants *SO_DOMAIN* , *SO_PROTOCOL*, *SO_PEERSEC* , and *SO_PASSSEC* are now supported. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The *setsockopt()* now supports the *setsockopt(level, optname, None, optlen: int)* form. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The socket module now supports the address family *AF_ALG* to interface with Linux Kernel crypto API. | |
|
||||||
|
| *ALG_*, *SOL_ALG* and *sendmsg_afalg()* were added. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| New Linux constants *TCP_USER_TIMEOUT* and *TCP_CONGESTION* were added. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `ssl <https://docs.python.org/3.6/whatsnew/3.6.html#ssl>`_ |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| ssl supports OpenSSL 1.1.0. The minimum recommend version is 1.0.2. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| 3DES has been removed from the default cipher suites and ChaCha20 Poly1305 cipher suites have been added. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| *SSLContext* has better default configuration for options and ciphers. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| SSL session can be copied from one client-side connection to another with the new *SSLSession* class. TLS | |
|
||||||
|
| session resumption can speed up the initial handshake, reduce latency and improve performance. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new *get_ciphers()* method can be used to get a list of enabled ciphers in order of cipher priority. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| All constants and flags have been converted to *IntEnum* and *IntFlags*. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Server and client-side specific TLS protocols for *SSLContext* were added. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Added *SSLContext.post_handshake_auth* to enable and *ssl.SSLSocket.verify_client_post_handshake()* to | |
|
||||||
|
| initiate TLS 1.3 post-handshake authentication. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `struct <https://docs.python.org/3.6/whatsnew/3.6.html#struct>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| now supports IEEE 754 half-precision floats via the 'e' format specifier. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `sys <https://docs.python.org/3.6/whatsnew/3.6.html#sys>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new *getfilesystemencodeerrors()* function returns the name of the error mode used to convert between | |
|
||||||
|
| Unicode filenames and bytes filenames. | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `zlib <https://docs.python.org/3.6/whatsnew/3.6.html#zlib>`_ | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The *compress()* and *decompress()* functions now accept keyword arguments | |
|
||||||
|
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
95
docs/differences/python_37.rst
Normal file
95
docs/differences/python_37.rst
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
.. _python_37:
|
||||||
|
|
||||||
|
Python 3.7
|
||||||
|
==========
|
||||||
|
|
||||||
|
New Features:
|
||||||
|
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| **Features:** | **Status** |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 538 <https://www.python.org/dev/peps/pep-0538/>`_ | Coercing the legacy C locale to a UTF-8 based | |
|
||||||
|
| | locale | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 539 <https://www.python.org/dev/peps/pep-0539/>`_ | A New C-API for Thread-Local Storage in CPython | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 540 <https://www.python.org/dev/peps/pep-0540/>`_ | UTF-8 mode | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 552 <https://www.python.org/dev/peps/pep-0552/>`_ | Deterministic pyc | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 553 <https://www.python.org/dev/peps/pep-0553/>`_ | Built-in breakpoint() | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 557 <https://www.python.org/dev/peps/pep-0557/>`_ | Data Classes | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 560 <https://www.python.org/dev/peps/pep-0560/>`_ | Core support for typing module and generic types | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 562 <https://www.python.org/dev/peps/pep-0562/>`_ | Module __getattr__ and __dir__ | Partially done |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 563 <https://www.python.org/dev/peps/pep-0563/>`_ | Postponed Evaluation of Annotations | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 564 <https://www.python.org/dev/peps/pep-0564/>`_ | Time functions with nanosecond resolution | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 565 <https://www.python.org/dev/peps/pep-0565/>`_ | Show DeprecationWarning in __main__ | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
| `PEP 567 <https://www.python.org/dev/peps/pep-0567/>`_ | Context Variables | |
|
||||||
|
+--------------------------------------------------------+--------------------------------------------------+----------------+
|
||||||
|
|
||||||
|
Other Language Changes:
|
||||||
|
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| async and await are now reserved keywords | Completed |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| dict objects must preserve insertion-order | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| More than 255 arguments can now be passed to a function; a function can now have more than 255 parameters| |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| bytes.fromhex() and bytearray.fromhex() now ignore all ASCII whitespace, not only spaces | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| str, bytes, and bytearray gained support for the new isascii() method, which can be used to test if a | |
|
||||||
|
| string or bytes contain only the ASCII characters | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| ImportError now displays module name and module __file__ path whenfrom ... import ... fails | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Circular imports involving absolute imports with binding a submodule to a name are now supported | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| object.__format__(x, '') is now equivalent to str(x) rather than format(str(self), '') | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| In order to better support dynamic creation of stack traces, types.TracebackType can now be instantiated | |
|
||||||
|
| from Python code, and the tb_next attribute on tracebacks is now writable | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| When using the -m switch, sys.path[0] is now eagerly expanded to the full starting directory path, rather| |
|
||||||
|
| than being left as the empty directory (which allows imports from the current working directory at the | |
|
||||||
|
| time when an import occurs) | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| The new -X importtime option or the PYTHONPROFILEIMPORTTIME environment variable can be used to show the | |
|
||||||
|
| timing of each module import | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
|
||||||
|
Changes to built-in modules:
|
||||||
|
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `asyncio <https://docs.python.org/3/whatsnew/3.7.html#asyncio>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| asyncio (many, may need a separate ticket) | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `gc <https://docs.python.org/3/whatsnew/3.7.html#gc>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| New features include *gc.freeze()*, *gc.unfreeze()*, *gc-get_freeze_count* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `math <https://docs.python.org/3/whatsnew/3.7.html#math>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| math.remainder() added to implement IEEE 754-style remainder | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `re <https://docs.python.org/3/whatsnew/3.7.html#re>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| A number of tidy up features including better support for splitting on empty strings and copy support for | |
|
||||||
|
| compiled expressions and match objects | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `sys <https://docs.python.org/3/whatsnew/3.7.html#sys>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| sys.breakpointhook() added. sys.get(/set)_coroutine_origin_tracking_depth() added | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| `time <https://docs.python.org/3/whatsnew/3.7.html#time>`_ | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
|
| Mostly updates to support nanosecond resolution in PEP564, see above | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+----------------+
|
||||||
118
docs/differences/python_38.rst
Normal file
118
docs/differences/python_38.rst
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
.. _python_38:
|
||||||
|
|
||||||
|
Python 3.8
|
||||||
|
==========
|
||||||
|
|
||||||
|
Python 3.8.0 (final) was released on the 14 October 2019. The Features for 3.8
|
||||||
|
are defined in `PEP 569 <https://www.python.org/dev/peps/pep-0569/#id9>`_ and
|
||||||
|
a detailed description of the changes can be found in What's New in `Python
|
||||||
|
3.8. <https://docs.python.org/3/whatsnew/3.8.html>`_
|
||||||
|
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| **Features:** | Status |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 570 <https://www.python.org/dev/peps/pep-0570/>`_ | Positional-only arguments | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 572 <https://www.python.org/dev/peps/pep-0572/>`_ | Assignment Expressions | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 574 <https://www.python.org/dev/peps/pep-0574/>`_ | Pickle protocol 5 with out-of-band data | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 578 <https://www.python.org/dev/peps/pep-0578/>`_ | Runtime audit hooks | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 587 <https://www.python.org/dev/peps/pep-0587/>`_ | Python Initialization Configuration | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| `PEP 590 <https://www.python.org/dev/peps/pep-0590/>`_ | Vectorcall: a fast calling protocol for CPython | |
|
||||||
|
+--------------------------------------------------------+---------------------------------------------------+---------------+
|
||||||
|
| **Miscellaneous** |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| f-strings support = for self-documenting expressions and debugging | Completed |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
|
||||||
|
Other Language Changes:
|
||||||
|
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| A *continue* statement was illegal in the *finally* clause due to a problem with the implementation. In | Completed |
|
||||||
|
| Python 3.8 this restriction was lifted | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| The *bool*, *int* , and *fractions.Fraction* types now have an *as_integer_ratio()* method like that found | |
|
||||||
|
| in *float* and *decimal.Decimal* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Constructors of *int*, *float* and *complex* will now use the *__index__()* special method, if available | |
|
||||||
|
| and the corresponding method *__int__()*, *__float__()* or *__complex__()* is not available | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added support of *\N{name}* escapes in regular expressions | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Dict and dictviews are now iterable in reversed insertion order using *reversed()* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| The syntax allowed for keyword names in function calls was further restricted. In particular, | |
|
||||||
|
| f((keyword)=arg) is no longer allowed | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Generalized iterable unpacking in yield and return statements no longer requires enclosing parentheses | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| When a comma is missed in code such as [(10, 20) (30, 40)], the compiler displays a SyntaxWarning with a | |
|
||||||
|
| helpful suggestion | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Arithmetic operations between subclasses of *datetime.date* or *datetime.datetime* and *datetime.timedelta*| |
|
||||||
|
| objects now return an instance of the subclass, rather than the base class | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| When the Python interpreter is interrupted by *Ctrl-C (SIGINT)* and the resulting *KeyboardInterrupt* | |
|
||||||
|
| exception is not caught, the Python process now exits via a SIGINT signal or with the correct exit code | |
|
||||||
|
| such that the calling process can detect that it died due to a *Ctrl-C* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Some advanced styles of programming require updating the *types.CodeType* object for an existing function | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| For integers, the three-argument form of the pow() function now permits the exponent to be negative in the | |
|
||||||
|
| case where the base is relatively prime to the modulus | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Dict comprehensions have been synced-up with dict literals so that the key is computed first and the value | |
|
||||||
|
| second | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| The *object.__reduce__()* method can now return a tuple from two to six elements long | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
|
||||||
|
Changes to built-in modules:
|
||||||
|
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| `asyncio` |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| *asyncio.run()* has graduated from the provisional to stable API | Completed |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Running *python -m asyncio* launches a natively async REPL | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| The exception *asyncio.CancelledError* now inherits from *BaseException* rather than *Exception* and no | Completed |
|
||||||
|
| longer inherits from *concurrent.futures.CancelledError* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added *asyncio.Task.get_coro()* for getting the wrapped coroutine within an *asyncio.Task* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Asyncio tasks can now be named, either by passing the name keyword argument to *asyncio.create_task()* or | |
|
||||||
|
| the *create_task()* event loop method, or by calling the *set_name()* method on the task object | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added support for Happy Eyeballs to *asyncio.loop.create_connection()*. To specify the behavior, two new | |
|
||||||
|
| parameters have been added: *happy_eyeballs_delay* and interleave. | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| `gc` |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| *get_objects()* can now receive an optional generation parameter indicating a generation to get objects | |
|
||||||
|
| from. (Note, though, that while *gc* is a built-in, *get_objects()* is not implemented for MicroPython) | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| `math` |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added new function *math.dist()* for computing Euclidean distance between two points | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Expanded the *math.hypot()* function to handle multiple dimensions | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added new function, *math.prod()*, as analogous function to *sum()* that returns the product of a "start" | |
|
||||||
|
| value (default: 1) times an iterable of numbers | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added two new combinatoric functions *math.perm()* and *math.comb()* | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Added a new function *math.isqrt()* for computing accurate integer square roots without conversion to | |
|
||||||
|
| floating point | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| The function *math.factorial()* no longer accepts arguments that are not int-like | Completed |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| `sys` |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
|
| Add new *sys.unraisablehook()* function which can be overridden to control how "unraisable exceptions" | |
|
||||||
|
| are handled | |
|
||||||
|
+------------------------------------------------------------------------------------------------------------+-------------+
|
||||||
121
docs/differences/python_39.rst
Normal file
121
docs/differences/python_39.rst
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
.. _python_39:
|
||||||
|
|
||||||
|
Python 3.9
|
||||||
|
==========
|
||||||
|
|
||||||
|
Python 3.9.0 (final) was released on the 5th October 2020. The Features for 3.9 are
|
||||||
|
defined in `PEP 596 <https://www.python.org/dev/peps/pep-0596/#features-for-3-9>`_
|
||||||
|
and a detailed description of the changes can be found in
|
||||||
|
`What's New in Python 3.9 <https://docs.python.org/3/whatsnew/3.9.html>`_
|
||||||
|
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| **Features:** | | **Status** |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 573 <https://www.python.org/dev/peps/pep-0573/>`_ | fast access to module state from methods of C | |
|
||||||
|
| | extension types | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 584 <https://www.python.org/dev/peps/pep-0584/>`_ | union operators added to dict | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 585 <https://www.python.org/dev/peps/pep-0584/>`_ | type hinting generics in standard collections | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 593 <https://www.python.org/dev/peps/pep-0593/>`_ | flexible function and variable annotations | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 602 <https://www.python.org/dev/peps/pep-0602/>`_ | CPython adopts an annual release cycle. Instead of | |
|
||||||
|
| | annual, aiming for two month release cycle | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 614 <https://www.python.org/dev/peps/pep-0614/>`_ | relaxed grammar restrictions on decorators | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 615 <https://www.python.org/dev/peps/pep-0615/>`_ | the IANA Time Zone Database is now present in the | |
|
||||||
|
| | standard library in the zoneinfo module | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 616 <https://www.python.org/dev/peps/pep-0616/>`_ | string methods to remove prefixes and suffixes | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
| `PEP 617 <https://www.python.org/dev/peps/pep-0617/>`_ | CPython now uses a new parser based on PEG | |
|
||||||
|
+--------------------------------------------------------+----------------------------------------------------+--------------+
|
||||||
|
|
||||||
|
Other Language Changes:
|
||||||
|
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| *__import__()* now raises *ImportError* instead of *ValueError* | Completed |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Python now gets the absolute path of the script filename specified on the command line (ex: *python3* | |
|
||||||
|
| *script.py*): the *__file__* attribute of the *__main__* module became an absolute path, rather than a | |
|
||||||
|
| relative path | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| By default, for best performance, the errors argument is only checked at the first encoding/decoding error | |
|
||||||
|
| and the encoding argument is sometimes ignored for empty strings | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| *"".replace("", s, n)* now returns *s* instead of an empty string for all non-zero n. It is now consistent | |
|
||||||
|
| with *"".replace("", s)* | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Any valid expression can now be used as a decorator. Previously, the grammar was much more restrictive | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Parallel running of *aclose()* / *asend()* / *athrow()* is now prohibited, and *ag_running* now reflects | |
|
||||||
|
| the actual running status of the async generator | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Unexpected errors in calling the *__iter__* method are no longer masked by TypeError in the in operator and | |
|
||||||
|
| functions contains(), indexOf() and countOf() of the operator module | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Unparenthesized lambda expressions can no longer be the expression part in an if clause in comprehensions | |
|
||||||
|
| and generator expressions | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
|
||||||
|
Changes to built-in modules:
|
||||||
|
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `asyncio` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Due to significant security concerns, the reuse_address parameter of *asyncio.loop.create_datagram_endpoint()*| |
|
||||||
|
| is no longer supported | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added a new coroutine *shutdown_default_executor()* that schedules a shutdown for the default executor that | |
|
||||||
|
| waits on the *ThreadPoolExecutor* to finish closing. Also, *asyncio.run()* has been updated to use the new | |
|
||||||
|
| coroutine. | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added *asyncio.PidfdChildWatcher*, a Linux-specific child watcher implementation that polls process file | |
|
||||||
|
| descriptors | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| added a new *coroutine asyncio.to_thread()* | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| When cancelling the task due to a timeout, *asyncio.wait_for()* will now wait until the cancellation is | |
|
||||||
|
| complete also in the case when timeout is <= 0, like it does with positive timeouts | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| *asyncio* now raises *TyperError* when calling incompatible methods with an *ssl.SSLSocket* socket | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `gc` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Garbage collection does not block on resurrected objects | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added a new function *gc.is_finalized()* to check if an object has been finalized by the garbage collector | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `math` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Expanded the *math.gcd()* function to handle multiple arguments. Formerly, it only supported two arguments | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added *math.lcm()*: return the least common multiple of specified arguments | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added *math.nextafter()*: return the next floating-point value after x towards y | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added *math.ulp()*: return the value of the least significant bit of a float | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `os` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Exposed the Linux-specific *os.pidfd_open()* and *os.P_PIDFD* | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *os.unsetenv()* function is now also available on Windows | Completed |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| The *os.putenv()* and *os.unsetenv()* functions are now always available | Completed |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added *os.waitstatus_to_exitcode()* function: convert a wait status to an exit code | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `random` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added a new *random.Random.randbytes* method: generate random bytes | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| `sys` |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Added a new *sys.platlibdir* attribute: name of the platform-specific library directory | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
|
| Previously, *sys.stderr* was block-buffered when non-interactive. Now stderr defaults to always being | |
|
||||||
|
| line-buffered | |
|
||||||
|
+---------------------------------------------------------------------------------------------------------------+---------------+
|
||||||
@ -16,7 +16,7 @@ working with this board it may be useful to get an overview of the microcontroll
|
|||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
general.rst
|
general.rst
|
||||||
tutorial/intro.rst
|
tutorial/index.rst
|
||||||
|
|
||||||
Installing MicroPython
|
Installing MicroPython
|
||||||
----------------------
|
----------------------
|
||||||
@ -218,20 +218,48 @@ range from 1Hz to 40MHz but there is a tradeoff; as the base frequency
|
|||||||
*increases* the duty resolution *decreases*. See
|
*increases* the duty resolution *decreases*. See
|
||||||
`LED Control <https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html>`_
|
`LED Control <https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html>`_
|
||||||
for more details.
|
for more details.
|
||||||
Currently the duty cycle has to be in the range of 0-1023.
|
|
||||||
|
|
||||||
Use the ``machine.PWM`` class::
|
Use the :ref:`machine.PWM <machine.PWM>` class::
|
||||||
|
|
||||||
from machine import Pin, PWM
|
from machine import Pin, PWM
|
||||||
|
|
||||||
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
||||||
pwm0.freq() # get current frequency
|
freq = pwm0.freq() # get current frequency (default 5kHz)
|
||||||
pwm0.freq(1000) # set frequency
|
pwm0.freq(1000) # set PWM frequency from 1Hz to 40MHz
|
||||||
pwm0.duty() # get current duty cycle
|
|
||||||
pwm0.duty(200) # set duty cycle
|
duty = pwm0.duty() # get current duty cycle, range 0-1023 (default 512, 50%)
|
||||||
|
pwm0.duty(256) # set duty cycle from 0 to 1023 as a ratio duty/1023, (now 25%)
|
||||||
|
|
||||||
|
duty_u16 = pwm0.duty_u16() # get current duty cycle, range 0-65535
|
||||||
|
pwm0.duty_u16(2**16*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
|
||||||
|
|
||||||
|
duty_ns = pwm0.duty_ns() # get current pulse width in ns
|
||||||
|
pwm0.duty_ns(250_000) # set pulse width in nanoseconds from 0 to 1_000_000_000/freq, (now 25%)
|
||||||
|
|
||||||
pwm0.deinit() # turn off PWM on the pin
|
pwm0.deinit() # turn off PWM on the pin
|
||||||
|
|
||||||
pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
|
pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
|
||||||
|
print(pwm2) # view PWM settings
|
||||||
|
|
||||||
|
ESP chips have different hardware peripherals:
|
||||||
|
|
||||||
|
===================================================== ======== ======== ========
|
||||||
|
Hardware specification ESP32 ESP32-S2 ESP32-C3
|
||||||
|
----------------------------------------------------- -------- -------- --------
|
||||||
|
Number of groups (speed modes) 2 1 1
|
||||||
|
Number of timers per group 4 4 4
|
||||||
|
Number of channels per group 8 8 6
|
||||||
|
----------------------------------------------------- -------- -------- --------
|
||||||
|
Different PWM frequencies (groups * timers) 8 4 4
|
||||||
|
Total PWM channels (Pins, duties) (groups * channels) 16 8 6
|
||||||
|
===================================================== ======== ======== ========
|
||||||
|
|
||||||
|
A maximum number of PWM channels (Pins) are available on the ESP32 - 16 channels,
|
||||||
|
but only 8 different PWM frequencies are available, the remaining 8 channels must
|
||||||
|
have the same frequency. On the other hand, 16 independent PWM duty cycles are
|
||||||
|
possible at the same frequency.
|
||||||
|
|
||||||
|
See more examples in the :ref:`esp32_pwm` tutorial.
|
||||||
|
|
||||||
ADC (analog to digital conversion)
|
ADC (analog to digital conversion)
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@ -481,7 +509,7 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with
|
|||||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
||||||
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
||||||
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
||||||
r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||||
|
|
||||||
OneWire driver
|
OneWire driver
|
||||||
--------------
|
--------------
|
||||||
@ -545,6 +573,9 @@ For low-level driving of a NeoPixel::
|
|||||||
400kHz) devices by passing ``timing=0`` when constructing the
|
400kHz) devices by passing ``timing=0`` when constructing the
|
||||||
``NeoPixel`` object.
|
``NeoPixel`` object.
|
||||||
|
|
||||||
|
The low-level driver uses an RMT channel by default. To configure this see
|
||||||
|
`RMT.bitstream_channel`.
|
||||||
|
|
||||||
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
APA102 (DotStar) uses a different driver as it has an additional clock pin.
|
||||||
|
|
||||||
Capacitive touch
|
Capacitive touch
|
||||||
|
|||||||
23
docs/esp32/tutorial/index.rst
Normal file
23
docs/esp32/tutorial/index.rst
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.. _esp32_tutorial:
|
||||||
|
|
||||||
|
MicroPython tutorial for ESP32
|
||||||
|
==============================
|
||||||
|
|
||||||
|
This tutorial is intended to get you started using MicroPython on the ESP32
|
||||||
|
system-on-a-chip. If it is your first time it is recommended to follow the
|
||||||
|
tutorial through in the order below. Otherwise the sections are mostly self
|
||||||
|
contained, so feel free to skip to those that interest you.
|
||||||
|
|
||||||
|
The tutorial does not assume that you know Python, but it also does not attempt
|
||||||
|
to explain any of the details of the Python language. Instead it provides you
|
||||||
|
with commands that are ready to run, and hopes that you will gain a bit of
|
||||||
|
Python knowledge along the way. To learn more about Python itself please refer
|
||||||
|
to `<https://www.python.org>`__.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:numbered:
|
||||||
|
|
||||||
|
intro.rst
|
||||||
|
pwm.rst
|
||||||
|
peripheral_access.rst
|
||||||
44
docs/esp32/tutorial/peripheral_access.rst
Normal file
44
docs/esp32/tutorial/peripheral_access.rst
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
Accessing peripherals directly via registers
|
||||||
|
============================================
|
||||||
|
|
||||||
|
The ESP32's peripherals can be controlled via direct register reads and writes.
|
||||||
|
This requires reading the datasheet to know what registers to use and what
|
||||||
|
values to write to them. The following example shows how to turn on and change
|
||||||
|
the prescaler of the MCPWM0 peripheral.
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
from machine import mem32
|
||||||
|
|
||||||
|
# Define the register addresses that will be used.
|
||||||
|
DR_REG_DPORT_BASE = const(0x3FF00000)
|
||||||
|
DPORT_PERIP_CLK_EN_REG = const(DR_REG_DPORT_BASE + 0x0C0)
|
||||||
|
DPORT_PERIP_RST_EN_REG = const(DR_REG_DPORT_BASE + 0x0C4)
|
||||||
|
DPORT_PWM0_CLK_EN = const(1 << 17)
|
||||||
|
MCPWM0 = const(0x3FF5E000)
|
||||||
|
MCPWM1 = const(0x3FF6C000)
|
||||||
|
|
||||||
|
# Enable CLK and disable RST.
|
||||||
|
print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
|
||||||
|
print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
|
||||||
|
mem32[DPORT_PERIP_CLK_EN_REG] |= DPORT_PWM0_CLK_EN
|
||||||
|
mem32[DPORT_PERIP_RST_EN_REG] &= ~DPORT_PWM0_CLK_EN
|
||||||
|
print(hex(mem32[DPORT_PERIP_CLK_EN_REG] & 0xffffffff))
|
||||||
|
print(hex(mem32[DPORT_PERIP_RST_EN_REG] & 0xffffffff))
|
||||||
|
|
||||||
|
# Change the MCPWM0 prescaler.
|
||||||
|
print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG (reset value = 0)
|
||||||
|
mem32[MCPWM0] = 0x55 # change PWM_CLK_PRESCALE
|
||||||
|
print(hex(mem32[MCPWM0])) # read PWM_CLK_CFG_REG
|
||||||
|
|
||||||
|
Note that before a peripheral can be used its clock must be enabled and it must
|
||||||
|
be taken out of reset. In the above example the following registers are used
|
||||||
|
for this:
|
||||||
|
|
||||||
|
- ``DPORT_PERI_CLK_EN_REG``: used to enable a peripheral clock
|
||||||
|
|
||||||
|
- ``DPORT_PERI_RST_EN_REG``: used to reset (or take out of reset) a peripheral
|
||||||
|
|
||||||
|
The MCPWM0 peripheral is in bit position 17 of the above two registers, hence
|
||||||
|
the value of ``DPORT_PWM0_CLK_EN``.
|
||||||
115
docs/esp32/tutorial/pwm.rst
Normal file
115
docs/esp32/tutorial/pwm.rst
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
.. _esp32_pwm:
|
||||||
|
|
||||||
|
Pulse Width Modulation
|
||||||
|
======================
|
||||||
|
|
||||||
|
Pulse width modulation (PWM) is a way to get an artificial analog output on a
|
||||||
|
digital pin. It achieves this by rapidly toggling the pin from low to high.
|
||||||
|
There are two parameters associated with this: the frequency of the toggling,
|
||||||
|
and the duty cycle. The duty cycle is defined to be how long the pin is high
|
||||||
|
compared with the length of a single period (low plus high time). Maximum
|
||||||
|
duty cycle is when the pin is high all of the time, and minimum is when it is
|
||||||
|
low all of the time.
|
||||||
|
|
||||||
|
* More comprehensive example with all 16 PWM channels and 8 timers::
|
||||||
|
|
||||||
|
from machine import Pin, PWM
|
||||||
|
try:
|
||||||
|
f = 100 # Hz
|
||||||
|
d = 1024 // 16 # 6.25%
|
||||||
|
pins = (15, 2, 4, 16, 18, 19, 22, 23, 25, 26, 27, 14 , 12, 13, 32, 33)
|
||||||
|
pwms = []
|
||||||
|
for i, pin in enumerate(pins):
|
||||||
|
pwms.append(PWM(Pin(pin), freq=f * (i // 2 + 1), duty= 1023 if i==15 else d * (i + 1)))
|
||||||
|
print(pwms[i])
|
||||||
|
finally:
|
||||||
|
for pwm in pwms:
|
||||||
|
try:
|
||||||
|
pwm.deinit()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
Output is::
|
||||||
|
|
||||||
|
PWM(Pin(15), freq=100, duty=64, resolution=10, mode=0, channel=0, timer=0)
|
||||||
|
PWM(Pin(2), freq=100, duty=128, resolution=10, mode=0, channel=1, timer=0)
|
||||||
|
PWM(Pin(4), freq=200, duty=192, resolution=10, mode=0, channel=2, timer=1)
|
||||||
|
PWM(Pin(16), freq=200, duty=256, resolution=10, mode=0, channel=3, timer=1)
|
||||||
|
PWM(Pin(18), freq=300, duty=320, resolution=10, mode=0, channel=4, timer=2)
|
||||||
|
PWM(Pin(19), freq=300, duty=384, resolution=10, mode=0, channel=5, timer=2)
|
||||||
|
PWM(Pin(22), freq=400, duty=448, resolution=10, mode=0, channel=6, timer=3)
|
||||||
|
PWM(Pin(23), freq=400, duty=512, resolution=10, mode=0, channel=7, timer=3)
|
||||||
|
PWM(Pin(25), freq=500, duty=576, resolution=10, mode=1, channel=0, timer=0)
|
||||||
|
PWM(Pin(26), freq=500, duty=640, resolution=10, mode=1, channel=1, timer=0)
|
||||||
|
PWM(Pin(27), freq=600, duty=704, resolution=10, mode=1, channel=2, timer=1)
|
||||||
|
PWM(Pin(14), freq=600, duty=768, resolution=10, mode=1, channel=3, timer=1)
|
||||||
|
PWM(Pin(12), freq=700, duty=832, resolution=10, mode=1, channel=4, timer=2)
|
||||||
|
PWM(Pin(13), freq=700, duty=896, resolution=10, mode=1, channel=5, timer=2)
|
||||||
|
PWM(Pin(32), freq=800, duty=960, resolution=10, mode=1, channel=6, timer=3)
|
||||||
|
PWM(Pin(33), freq=800, duty=1023, resolution=10, mode=1, channel=7, timer=3)
|
||||||
|
|
||||||
|
* Example of a smooth frequency change::
|
||||||
|
|
||||||
|
from utime import sleep
|
||||||
|
from machine import Pin, PWM
|
||||||
|
|
||||||
|
F_MIN = 500
|
||||||
|
F_MAX = 1000
|
||||||
|
|
||||||
|
f = F_MIN
|
||||||
|
delta_f = 1
|
||||||
|
|
||||||
|
p = PWM(Pin(5), f)
|
||||||
|
print(p)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
p.freq(f)
|
||||||
|
|
||||||
|
sleep(10 / F_MIN)
|
||||||
|
|
||||||
|
f += delta_f
|
||||||
|
if f >= F_MAX or f <= F_MIN:
|
||||||
|
delta_f = -delta_f
|
||||||
|
|
||||||
|
See PWM wave at Pin(5) with an oscilloscope.
|
||||||
|
|
||||||
|
* Example of a smooth duty change::
|
||||||
|
|
||||||
|
from utime import sleep
|
||||||
|
from machine import Pin, PWM
|
||||||
|
|
||||||
|
DUTY_MAX = 2**16 - 1
|
||||||
|
|
||||||
|
duty_u16 = 0
|
||||||
|
delta_d = 16
|
||||||
|
|
||||||
|
p = PWM(Pin(5), 1000, duty_u16=duty_u16)
|
||||||
|
print(p)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
p.duty_u16(duty_u16)
|
||||||
|
|
||||||
|
sleep(1 / 1000)
|
||||||
|
|
||||||
|
duty_u16 += delta_d
|
||||||
|
if duty_u16 >= DUTY_MAX:
|
||||||
|
duty_u16 = DUTY_MAX
|
||||||
|
delta_d = -delta_d
|
||||||
|
elif duty_u16 <= 0:
|
||||||
|
duty_u16 = 0
|
||||||
|
delta_d = -delta_d
|
||||||
|
|
||||||
|
See PWM wave at Pin(5) with an oscilloscope.
|
||||||
|
|
||||||
|
Note: the Pin.OUT mode does not need to be specified. The channel is initialized
|
||||||
|
to PWM mode internally once for each Pin that is passed to the PWM constructor.
|
||||||
|
|
||||||
|
The following code is wrong::
|
||||||
|
|
||||||
|
pwm = PWM(Pin(5, Pin.OUT), freq=1000, duty=512) # Pin(5) in PWM mode here
|
||||||
|
pwm = PWM(Pin(5, Pin.OUT), freq=500, duty=256) # Pin(5) in OUT mode here, PWM is off
|
||||||
|
|
||||||
|
Use this code instead::
|
||||||
|
|
||||||
|
pwm = PWM(Pin(5), freq=1000, duty=512)
|
||||||
|
pwm.init(freq=500, duty=256)
|
||||||
@ -66,8 +66,8 @@ Subclassing FrameBuffer provides support for graphics primitives::
|
|||||||
display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1
|
display.hline(0, 8, 4, 1) # draw horizontal line x=0, y=8, width=4, colour=1
|
||||||
display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1
|
display.vline(0, 8, 4, 1) # draw vertical line x=0, y=8, height=4, colour=1
|
||||||
display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63
|
display.line(0, 0, 127, 63, 1) # draw a line from 0,0 to 127,63
|
||||||
display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 107,43, colour=1
|
display.rect(10, 10, 107, 43, 1) # draw a rectangle outline 10,10 to 117,53, colour=1
|
||||||
display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 107,43, colour=1
|
display.fill_rect(10, 10, 107, 43, 1) # draw a solid rectangle 10,10 to 117,53, colour=1
|
||||||
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1
|
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1
|
||||||
display.scroll(20, 0) # scroll 20 pixels to the right
|
display.scroll(20, 0) # scroll 20 pixels to the right
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ Configuration
|
|||||||
- ``'mac'``: The current address in use, depending on the current address mode.
|
- ``'mac'``: The current address in use, depending on the current address mode.
|
||||||
This returns a tuple of ``(addr_type, addr)``.
|
This returns a tuple of ``(addr_type, addr)``.
|
||||||
|
|
||||||
See :meth:`gatts_write <BLE.gap_scan>` for details about address type.
|
See :meth:`gatts_write <BLE.gatts_write>` for details about address type.
|
||||||
|
|
||||||
This may only be queried while the interface is currently active.
|
This may only be queried while the interface is currently active.
|
||||||
|
|
||||||
@ -359,13 +359,27 @@ Central Role
|
|||||||
|
|
||||||
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan<BLE.gap_scan>`) or with a known address.
|
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan<BLE.gap_scan>`) or with a known address.
|
||||||
|
|
||||||
.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /)
|
.. method:: BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, min_conn_interval_us=None, max_conn_interval_us=None, /)
|
||||||
|
|
||||||
Connect to a peripheral.
|
Connect to a peripheral.
|
||||||
|
|
||||||
See :meth:`gap_scan <BLE.gap_scan>` for details about address types.
|
See :meth:`gap_scan <BLE.gap_scan>` for details about address types.
|
||||||
|
|
||||||
On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
|
To cancel an outstanding connection attempt early, call
|
||||||
|
``gap_connect(None)``.
|
||||||
|
|
||||||
|
On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised. If
|
||||||
|
cancelling a connection attempt, the ``_IRQ_PERIPHERAL_DISCONNECT`` event
|
||||||
|
will be raised.
|
||||||
|
|
||||||
|
The device will wait up to *scan_duration_ms* to receive an advertising
|
||||||
|
payload from the device.
|
||||||
|
|
||||||
|
The connection interval can be configured in **micro**\ seconds using either
|
||||||
|
or both of *min_conn_interval_us* and *max_conn_interval_us*. Otherwise a
|
||||||
|
default interval will be chosen, typically between 30000 and 50000
|
||||||
|
microseconds. A shorter interval will increase throughput, at the expense
|
||||||
|
of power usage.
|
||||||
|
|
||||||
|
|
||||||
Peripheral Role
|
Peripheral Role
|
||||||
|
|||||||
@ -250,6 +250,17 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
|||||||
new sequence of pulses. Looping sequences longer than 126 pulses is not
|
new sequence of pulses. Looping sequences longer than 126 pulses is not
|
||||||
supported by the hardware.
|
supported by the hardware.
|
||||||
|
|
||||||
|
.. staticmethod:: RMT.bitstream_channel([value])
|
||||||
|
|
||||||
|
Select which RMT channel is used by the `machine.bitstream` implementation.
|
||||||
|
*value* can be ``None`` or a valid RMT channel number. The default RMT
|
||||||
|
channel is the highest numbered one.
|
||||||
|
|
||||||
|
Passing in ``None`` disables the use of RMT and instead selects a bit-banging
|
||||||
|
implementation for `machine.bitstream`.
|
||||||
|
|
||||||
|
Passing in no argument will not change the channel. This function returns
|
||||||
|
the current channel number.
|
||||||
|
|
||||||
Ultra-Low-Power co-processor
|
Ultra-Low-Power co-processor
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|||||||
@ -19,11 +19,11 @@ For example::
|
|||||||
import framebuf
|
import framebuf
|
||||||
|
|
||||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||||
fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
|
fbuf = framebuf.FrameBuffer(bytearray(100 * 10 * 2), 100, 10, framebuf.RGB565)
|
||||||
|
|
||||||
fbuf.fill(0)
|
fbuf.fill(0)
|
||||||
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
||||||
fbuf.hline(0, 10, 96, 0xffff)
|
fbuf.hline(0, 9, 96, 0xffff)
|
||||||
|
|
||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|||||||
@ -65,6 +65,7 @@ library.
|
|||||||
json.rst
|
json.rst
|
||||||
math.rst
|
math.rst
|
||||||
os.rst
|
os.rst
|
||||||
|
random.rst
|
||||||
re.rst
|
re.rst
|
||||||
select.rst
|
select.rst
|
||||||
socket.rst
|
socket.rst
|
||||||
@ -119,6 +120,7 @@ The following libraries are specific to the pyboard.
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
pyb.rst
|
pyb.rst
|
||||||
|
stm.rst
|
||||||
lcd160cr.rst
|
lcd160cr.rst
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,7 @@ Methods
|
|||||||
Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation.
|
Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation.
|
||||||
``handler`` is called in the context of the MicroPython scheduler.
|
``handler`` is called in the context of the MicroPython scheduler.
|
||||||
|
|
||||||
.. staticmethod:: I2S.shift(buf, bits, shift)
|
.. staticmethod:: I2S.shift(*, buf, bits, shift)
|
||||||
|
|
||||||
bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample.
|
bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample.
|
||||||
Positive for left shift, negative for right shift.
|
Positive for left shift, negative for right shift.
|
||||||
|
|||||||
@ -77,3 +77,34 @@ Methods
|
|||||||
With no arguments the pulse width in nanoseconds is returned.
|
With no arguments the pulse width in nanoseconds is returned.
|
||||||
|
|
||||||
With a single *value* argument the pulse width is set to that value.
|
With a single *value* argument the pulse width is set to that value.
|
||||||
|
|
||||||
|
Limitations of PWM
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Not all frequencies can be generated with absolute accuracy due to
|
||||||
|
the discrete nature of the computing hardware. Typically the PWM frequency
|
||||||
|
is obtained by dividing some integer base frequency by an integer divider.
|
||||||
|
For example, if the base frequency is 80MHz and the required PWM frequency is
|
||||||
|
300kHz the divider must be a non-integer number 80000000 / 300000 = 266.67.
|
||||||
|
After rounding the divider is set to 267 and the PWM frequency will be
|
||||||
|
80000000 / 267 = 299625.5 Hz, not 300kHz. If the divider is set to 266 then
|
||||||
|
the PWM frequency will be 80000000 / 266 = 300751.9 Hz, but again not 300kHz.
|
||||||
|
|
||||||
|
* The duty cycle has the same discrete nature and its absolute accuracy is not
|
||||||
|
achievable. On most hardware platforms the duty will be applied at the next
|
||||||
|
frequency period. Therefore, you should wait more than "1/frequency" before
|
||||||
|
measuring the duty.
|
||||||
|
|
||||||
|
* The frequency and the duty cycle resolution are usually interdependent.
|
||||||
|
The higher the PWM frequency the lower the duty resolution which is available,
|
||||||
|
and vice versa. For example, a 300kHz PWM frequency can have a duty cycle
|
||||||
|
resolution of 8 bit, not 16-bit as may be expected. In this case, the lowest
|
||||||
|
8 bits of *duty_u16* are insignificant. So::
|
||||||
|
|
||||||
|
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2)
|
||||||
|
|
||||||
|
and::
|
||||||
|
|
||||||
|
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255)
|
||||||
|
|
||||||
|
will generate PWM with the same 50% duty cycle.
|
||||||
|
|||||||
@ -74,6 +74,8 @@ Constructors
|
|||||||
- ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as
|
- ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as
|
||||||
open-drain. Not all ports implement this mode.
|
open-drain. Not all ports implement this mode.
|
||||||
|
|
||||||
|
- ``Pin.ANALOG`` - Pin is configured for analog input, see the :class:`ADC` class.
|
||||||
|
|
||||||
- ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be
|
- ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be
|
||||||
one of:
|
one of:
|
||||||
|
|
||||||
@ -247,6 +249,7 @@ not all constants are available on all ports.
|
|||||||
Pin.OPEN_DRAIN
|
Pin.OPEN_DRAIN
|
||||||
Pin.ALT
|
Pin.ALT
|
||||||
Pin.ALT_OPEN_DRAIN
|
Pin.ALT_OPEN_DRAIN
|
||||||
|
Pin.ANALOG
|
||||||
|
|
||||||
Selects the pin mode.
|
Selects the pin mode.
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,42 @@ Software SPI is implemented by bit-banging and can be used on any pin but
|
|||||||
is not as efficient. These classes have the same methods available and
|
is not as efficient. These classes have the same methods available and
|
||||||
differ primarily in the way they are constructed.
|
differ primarily in the way they are constructed.
|
||||||
|
|
||||||
|
Example usage::
|
||||||
|
|
||||||
|
from machine import SPI, Pin
|
||||||
|
|
||||||
|
spi = SPI(0, baudrate=400000) # Create SPI peripheral 0 at frequency of 400kHz.
|
||||||
|
# Depending on the use case, extra parameters may be required
|
||||||
|
# to select the bus characteristics and/or pins to use.
|
||||||
|
cs = Pin(4, mode=Pin.OUT, value=1) # Create chip-select on pin 4.
|
||||||
|
|
||||||
|
try:
|
||||||
|
cs(0) # Select peripheral.
|
||||||
|
spi.write(b"12345678") # Write 8 bytes, and don't care about received data.
|
||||||
|
finally:
|
||||||
|
cs(1) # Deselect peripheral.
|
||||||
|
|
||||||
|
try:
|
||||||
|
cs(0) # Select peripheral.
|
||||||
|
rxdata = spi.read(8, 0x42) # Read 8 bytes while writing 0x42 for each byte.
|
||||||
|
finally:
|
||||||
|
cs(1) # Deselect peripheral.
|
||||||
|
|
||||||
|
rxdata = bytearray(8)
|
||||||
|
try:
|
||||||
|
cs(0) # Select peripheral.
|
||||||
|
spi.readinto(rxdata, 0x42) # Read 8 bytes inplace while writing 0x42 for each byte.
|
||||||
|
finally:
|
||||||
|
cs(1) # Deselect peripheral.
|
||||||
|
|
||||||
|
txdata = b"12345678"
|
||||||
|
rxdata = bytearray(len(txdata))
|
||||||
|
try:
|
||||||
|
cs(0) # Select peripheral.
|
||||||
|
spi.write_readinto(txdata, rxdata) # Simultaneously write and read bytes.
|
||||||
|
finally:
|
||||||
|
cs(1) # Deselect peripheral.
|
||||||
|
|
||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
@ -27,10 +27,11 @@ instead of this class.
|
|||||||
Constructors
|
Constructors
|
||||||
------------
|
------------
|
||||||
|
|
||||||
.. class:: Timer(id, ...)
|
.. class:: Timer(id, /, ...)
|
||||||
|
|
||||||
Construct a new timer object of the given id. Id of -1 constructs a
|
Construct a new timer object of the given ``id``. ``id`` of -1 constructs a
|
||||||
virtual timer (if supported by a board).
|
virtual timer (if supported by a board).
|
||||||
|
``id`` shall not be passed as a keyword argument.
|
||||||
|
|
||||||
See ``init`` for parameters of initialisation.
|
See ``init`` for parameters of initialisation.
|
||||||
|
|
||||||
@ -41,8 +42,14 @@ Methods
|
|||||||
|
|
||||||
Initialise the timer. Example::
|
Initialise the timer. Example::
|
||||||
|
|
||||||
tim.init(period=100) # periodic with 100ms period
|
def mycallback(t):
|
||||||
tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms
|
pass
|
||||||
|
|
||||||
|
# periodic with 100ms period
|
||||||
|
tim.init(period=100, callback=mycallback)
|
||||||
|
|
||||||
|
# one shot firing after 1000ms
|
||||||
|
tim.init(mode=Timer.ONE_SHOT, period=1000, callback=mycallback)
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
|
|
||||||
@ -53,6 +60,14 @@ Methods
|
|||||||
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
|
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
|
||||||
frequency of the channel.
|
frequency of the channel.
|
||||||
|
|
||||||
|
- ``period`` - The timer period, in milliseconds.
|
||||||
|
|
||||||
|
- ``callback`` - The callable to call upon expiration of the timer period.
|
||||||
|
The callback must take one argument, which is passed the Timer object.
|
||||||
|
The ``callback`` argument shall be specified. Otherwise an exception
|
||||||
|
will occurr upon timer expiration:
|
||||||
|
``TypeError: 'NoneType' object isn't callable``
|
||||||
|
|
||||||
.. method:: Timer.deinit()
|
.. method:: Timer.deinit()
|
||||||
|
|
||||||
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
|
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
|
||||||
|
|||||||
@ -314,6 +314,12 @@ that the block device supports the extended interface.
|
|||||||
``ioctl(6, ...)`` must also be intercepted. The need for others is
|
``ioctl(6, ...)`` must also be intercepted. The need for others is
|
||||||
hardware dependent.
|
hardware dependent.
|
||||||
|
|
||||||
|
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
|
||||||
|
``ioctl(6, block)``. This enables a device driver to erase the block
|
||||||
|
prior to a write if the hardware requires it. Alternatively a driver
|
||||||
|
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
|
||||||
|
the driver assumes responsibility for detecting the need for erasure.
|
||||||
|
|
||||||
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
|
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
|
||||||
Consequently an implementation can ignore unused values of ``op``. Where
|
Consequently an implementation can ignore unused values of ``op``. Where
|
||||||
``op`` is intercepted, the return value for operations 4 and 5 are as
|
``op`` is intercepted, the return value for operations 4 and 5 are as
|
||||||
|
|||||||
82
docs/library/random.rst
Normal file
82
docs/library/random.rst
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
:mod:`random` -- generate random numbers
|
||||||
|
========================================
|
||||||
|
|
||||||
|
.. module:: random
|
||||||
|
:synopsis: random numbers
|
||||||
|
|
||||||
|
This module implements a pseudo-random number generator (PRNG).
|
||||||
|
|
||||||
|
|see_cpython_module| :mod:`python:random` .
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The following notation is used for intervals:
|
||||||
|
|
||||||
|
- () are open interval brackets and do not include their endpoints.
|
||||||
|
For example, (0, 1) means greater than 0 and less than 1.
|
||||||
|
In set notation: (0, 1) = {x | 0 < x < 1}.
|
||||||
|
|
||||||
|
- [] are closed interval brackets which include all their limit points.
|
||||||
|
For example, [0, 1] means greater than or equal to 0 and less than
|
||||||
|
or equal to 1.
|
||||||
|
In set notation: [0, 1] = {x | 0 <= x <= 1}.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The :func:`randrange`, :func:`randint` and :func:`choice` functions are only
|
||||||
|
available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is
|
||||||
|
enabled.
|
||||||
|
|
||||||
|
|
||||||
|
Functions for integers
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. function:: getrandbits(n)
|
||||||
|
|
||||||
|
Return an integer with *n* random bits (0 <= n <= 32).
|
||||||
|
|
||||||
|
.. function:: randint(a, b)
|
||||||
|
|
||||||
|
Return a random integer in the range [*a*, *b*].
|
||||||
|
|
||||||
|
.. function:: randrange(stop)
|
||||||
|
randrange(start, stop)
|
||||||
|
randrange(start, stop[, step])
|
||||||
|
|
||||||
|
The first form returns a random integer from the range [0, *stop*).
|
||||||
|
The second form returns a random integer from the range [*start*, *stop*).
|
||||||
|
The third form returns a random integer from the range [*start*, *stop*) in
|
||||||
|
steps of *step*. For instance, calling ``randrange(1, 10, 2)`` will
|
||||||
|
return odd numbers between 1 and 9 inclusive.
|
||||||
|
|
||||||
|
|
||||||
|
Functions for floats
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. function:: random()
|
||||||
|
|
||||||
|
Return a random floating point number in the range [0.0, 1.0).
|
||||||
|
|
||||||
|
.. function:: uniform(a, b)
|
||||||
|
|
||||||
|
Return a random floating point number N such that *a* <= N <= *b* for *a* <= *b*,
|
||||||
|
and *b* <= N <= *a* for *b* < *a*.
|
||||||
|
|
||||||
|
|
||||||
|
Other Functions
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. function:: seed(n=None, /)
|
||||||
|
|
||||||
|
Initialise the random number generator module with the seed *n* which should
|
||||||
|
be an integer. When no argument (or ``None``) is passed in it will (if
|
||||||
|
supported by the port) initialise the PRNG with a true random number
|
||||||
|
(usually a hardware generated random number).
|
||||||
|
|
||||||
|
The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is
|
||||||
|
enabled by the port, otherwise it raises ``ValueError``.
|
||||||
|
|
||||||
|
.. function:: choice(sequence)
|
||||||
|
|
||||||
|
Chooses and returns one item at random from *sequence* (tuple, list or
|
||||||
|
any object that supports the subscript operation).
|
||||||
@ -58,7 +58,7 @@ For running PIO programs, see :class:`rp2.StateMachine`.
|
|||||||
combined into a single 8-word FIFO for one direction only. The options
|
combined into a single 8-word FIFO for one direction only. The options
|
||||||
are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
|
are `PIO.JOIN_NONE`, `PIO.JOIN_RX` and `PIO.JOIN_TX`.
|
||||||
|
|
||||||
.. function:: asm_pio_encode(instr, sideset_count)
|
.. function:: asm_pio_encode(instr, sideset_count, sideset_opt=False)
|
||||||
|
|
||||||
Assemble a single PIO instruction. You usually want to use `asm_pio()`
|
Assemble a single PIO instruction. You usually want to use `asm_pio()`
|
||||||
instead.
|
instead.
|
||||||
@ -72,6 +72,158 @@ For running PIO programs, see :class:`rp2.StateMachine`.
|
|||||||
an error assembling a PIO program.
|
an error assembling a PIO program.
|
||||||
|
|
||||||
|
|
||||||
|
PIO assembly language instructions
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
PIO state machines are programmed in a custom assembly language with nine core
|
||||||
|
PIO-machine instructions. In MicroPython, PIO assembly routines are written as
|
||||||
|
a Python function with the decorator ``@rp2.asm_pio()``, and they use Python
|
||||||
|
syntax. Such routines support standard Python variables and arithmetic, as well
|
||||||
|
as the following custom functions that encode PIO instructions and direct the
|
||||||
|
assembler. See sec 3.4 of the RP2040 datasheet for further details.
|
||||||
|
|
||||||
|
wrap_target()
|
||||||
|
Specify the location where execution continues after program wrapping.
|
||||||
|
By default this is the start of the PIO routine.
|
||||||
|
|
||||||
|
wrap()
|
||||||
|
Specify the location where the program finishes and wraps around.
|
||||||
|
If this directive is not used then it is added automatically at the end of
|
||||||
|
the PIO routine. Wrapping does not cost any execution cycles.
|
||||||
|
|
||||||
|
label(label)
|
||||||
|
Define a label called *label* at the current location. *label* can be a
|
||||||
|
string or integer.
|
||||||
|
|
||||||
|
word(instr, label=None)
|
||||||
|
Insert an arbitrary 16-bit word in the assembled output.
|
||||||
|
|
||||||
|
- *instr*: the 16-bit value
|
||||||
|
- *label*: if given, look up the label and logical-or the label's value with
|
||||||
|
*instr*
|
||||||
|
|
||||||
|
jmp(...)
|
||||||
|
This instruction takes two forms:
|
||||||
|
|
||||||
|
jmp(label)
|
||||||
|
- *label*: label to jump to unconditionally
|
||||||
|
|
||||||
|
jmp(cond, label)
|
||||||
|
- *cond*: the condition to check, one of:
|
||||||
|
|
||||||
|
- ``not_x``, ``not_y``: true if register is zero
|
||||||
|
- ``x_dec``, ``y_dec``: true if register is non-zero, and do post
|
||||||
|
decrement
|
||||||
|
- ``x_not_y``: true if X is not equal to Y
|
||||||
|
- ``pin``: true if the input pin is set
|
||||||
|
- ``not_osre``: true if OSR is not empty (hasn't reached its
|
||||||
|
threshold)
|
||||||
|
|
||||||
|
- *label*: label to jump to if condition is true
|
||||||
|
|
||||||
|
wait(polarity, src, index)
|
||||||
|
Block, waiting for high/low on a pin or IRQ line.
|
||||||
|
|
||||||
|
- *polarity*: 0 or 1, whether to wait for a low or high value
|
||||||
|
- *src*: one of: ``gpio`` (absolute pin), ``pin`` (pin relative to
|
||||||
|
StateMachine's ``in_base`` argument), ``irq``
|
||||||
|
- *index*: 0-31, the index for *src*
|
||||||
|
|
||||||
|
in_(src, bit_count)
|
||||||
|
Shift data in from *src* to ISR.
|
||||||
|
|
||||||
|
- *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``isr``, ``osr``
|
||||||
|
- *bit_count*: number of bits to shift in (1-32)
|
||||||
|
|
||||||
|
out(dest, bit_count)
|
||||||
|
Shift data out from OSR to *dest*.
|
||||||
|
|
||||||
|
- *dest*: one of: ``pins``, ``x``, ``y``, ``pindirs``, ``pc``, ``isr``,
|
||||||
|
``exec``
|
||||||
|
- *bit_count*: number of bits to shift out (1-32)
|
||||||
|
|
||||||
|
push(...)
|
||||||
|
Push ISR to the RX FIFO, then clear ISR to zero.
|
||||||
|
This instruction takes the following forms:
|
||||||
|
|
||||||
|
- push()
|
||||||
|
- push(block)
|
||||||
|
- push(noblock)
|
||||||
|
- push(iffull)
|
||||||
|
- push(iffull, block)
|
||||||
|
- push(iffull, noblock)
|
||||||
|
|
||||||
|
If ``block`` is used then the instruction stalls if the RX FIFO is full.
|
||||||
|
The default is to block. If ``iffull`` is used then it only pushes if the
|
||||||
|
input shift count has reached its threshold.
|
||||||
|
|
||||||
|
pull(...)
|
||||||
|
Pull from the TX FIFO into OSR.
|
||||||
|
This instruction takes the following forms:
|
||||||
|
|
||||||
|
- pull()
|
||||||
|
- pull(block)
|
||||||
|
- pull(noblock)
|
||||||
|
- pull(ifempty)
|
||||||
|
- pull(ifempty, block)
|
||||||
|
- pull(ifempty, noblock)
|
||||||
|
|
||||||
|
If ``block`` is used then the instruction stalls if the TX FIFO is empty.
|
||||||
|
The default is to block. If ``ifempty`` is used then it only pulls if the
|
||||||
|
output shift count has reached its threshold.
|
||||||
|
|
||||||
|
mov(dest, src)
|
||||||
|
Move into *dest* the value from *src*.
|
||||||
|
|
||||||
|
- *dest*: one of: ``pins``, ``x``, ``y``, ``exec``, ``pc``, ``isr``, ``osr``
|
||||||
|
- *src*: one of: ``pins``, ``x``, ``y``, ``null``, ``status``, ``isr``,
|
||||||
|
``osr``; this argument can be optionally modified by wrapping it in
|
||||||
|
``invert()`` or ``reverse()`` (but not both together)
|
||||||
|
|
||||||
|
irq(...)
|
||||||
|
Set or clear an IRQ flag.
|
||||||
|
This instruction takes two forms:
|
||||||
|
|
||||||
|
irq(index)
|
||||||
|
- *index*: 0-7, or ``rel(0)`` to ``rel(7)``
|
||||||
|
|
||||||
|
irq(mode, index)
|
||||||
|
- *mode*: one of: ``block``, ``clear``
|
||||||
|
- *index*: 0-7, or ``rel(0)`` to ``rel(7)``
|
||||||
|
|
||||||
|
If ``block`` is used then the instruction stalls until the flag is cleared
|
||||||
|
by another entity. If ``clear`` is used then the flag is cleared instead of
|
||||||
|
being set. Relative IRQ indices add the state machine ID to the IRQ index
|
||||||
|
with modulo-4 addition. IRQs 0-3 are visible from to the processor, 4-7 are
|
||||||
|
internal to the state machines.
|
||||||
|
|
||||||
|
set(dest, data)
|
||||||
|
Set *dest* with the value *data*.
|
||||||
|
|
||||||
|
- *dest*: ``pins``, ``x``, ``y``, ``pindirs``
|
||||||
|
- *data*: value (0-31)
|
||||||
|
|
||||||
|
nop()
|
||||||
|
This is a pseudoinstruction that assembles to ``mov(y, y)`` and has no side
|
||||||
|
effect.
|
||||||
|
|
||||||
|
.side(value)
|
||||||
|
This is a modifier which can be applied to any instruction, and is used to
|
||||||
|
control side-set pin values.
|
||||||
|
|
||||||
|
- *value*: the value (bits) to output on the side-set pins
|
||||||
|
|
||||||
|
.delay(value)
|
||||||
|
This is a modifier which can be applied to any instruction, and specifies
|
||||||
|
how many cycles to delay for after the instruction executes.
|
||||||
|
|
||||||
|
- *value*: cycles to delay, 0-31 (maximum value reduced if side-set pins are
|
||||||
|
used)
|
||||||
|
|
||||||
|
[value]
|
||||||
|
This is a modifier and is equivalent to ``.delay(value)``.
|
||||||
|
|
||||||
|
|
||||||
Classes
|
Classes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|||||||
104
docs/library/stm.rst
Normal file
104
docs/library/stm.rst
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
.. currentmodule:: stm
|
||||||
|
|
||||||
|
:mod:`stm` --- functionality specific to STM32 MCUs
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
.. module:: stm
|
||||||
|
:synopsis: functionality specific to STM32 MCUs
|
||||||
|
|
||||||
|
This module provides functionality specific to STM32 microcontrollers, including
|
||||||
|
direct access to peripheral registers.
|
||||||
|
|
||||||
|
Memory access
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The module exposes three objects used for raw memory access.
|
||||||
|
|
||||||
|
.. data:: mem8
|
||||||
|
|
||||||
|
Read/write 8 bits of memory.
|
||||||
|
|
||||||
|
.. data:: mem16
|
||||||
|
|
||||||
|
Read/write 16 bits of memory.
|
||||||
|
|
||||||
|
.. data:: mem32
|
||||||
|
|
||||||
|
Read/write 32 bits of memory.
|
||||||
|
|
||||||
|
Use subscript notation ``[...]`` to index these objects with the address of
|
||||||
|
interest.
|
||||||
|
|
||||||
|
These memory objects can be used in combination with the peripheral register
|
||||||
|
constants to read and write registers of the MCU hardware peripherals, as well
|
||||||
|
as all other areas of address space.
|
||||||
|
|
||||||
|
|
||||||
|
Peripheral register constants
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The module defines constants for registers which are generated from CMSIS header
|
||||||
|
files, and the constants available depend on the microcontroller series that is
|
||||||
|
being compiled for. Examples of some constants include:
|
||||||
|
|
||||||
|
.. data:: GPIOA
|
||||||
|
|
||||||
|
Base address of the GPIOA peripheral.
|
||||||
|
|
||||||
|
.. data:: GPIOB
|
||||||
|
|
||||||
|
Base address of the GPIOB peripheral.
|
||||||
|
|
||||||
|
.. data:: GPIO_BSRR
|
||||||
|
|
||||||
|
Offset of the GPIO bit set/reset register.
|
||||||
|
|
||||||
|
.. data:: GPIO_IDR
|
||||||
|
|
||||||
|
Offset of the GPIO input data register.
|
||||||
|
|
||||||
|
.. data:: GPIO_ODR
|
||||||
|
|
||||||
|
Offset of the GPIO output data register.
|
||||||
|
|
||||||
|
Constants that are named after a peripheral, like ``GPIOA``, are the absolute
|
||||||
|
address of that peripheral. Constants that have a prefix which is the name of a
|
||||||
|
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
|
||||||
|
peripheral registers requires adding the absolute base address of the peripheral
|
||||||
|
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
|
||||||
|
full, absolute address of the ``GPIOA->BSRR`` register.
|
||||||
|
|
||||||
|
Example use:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
# set PA2 high
|
||||||
|
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
|
||||||
|
|
||||||
|
# read PA3
|
||||||
|
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
|
||||||
|
|
||||||
|
|
||||||
|
Functions specific to STM32WBxx MCUs
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
These functions are available on STM32WBxx microcontrollers, and interact with
|
||||||
|
the second CPU, the RF core.
|
||||||
|
|
||||||
|
.. function:: rfcore_status()
|
||||||
|
|
||||||
|
Returns the status of the second CPU as an integer (the first word of device
|
||||||
|
info table).
|
||||||
|
|
||||||
|
.. function:: rfcore_fw_version(id)
|
||||||
|
|
||||||
|
Get the version of the firmware running on the second CPU. Pass in 0 for
|
||||||
|
*id* to get the FUS version, and 1 to get the WS version.
|
||||||
|
|
||||||
|
Returns a 5-tuple with the full version number.
|
||||||
|
|
||||||
|
.. function:: rfcore_sys_hci(ogf, ocf, data, timeout_ms=0)
|
||||||
|
|
||||||
|
Execute a HCI command on the SYS channel. The execution is synchronous.
|
||||||
|
|
||||||
|
Returns a bytes object with the result of the SYS command.
|
||||||
@ -43,6 +43,15 @@ Functions
|
|||||||
positional; further arguments are not supported. CPython-compatible
|
positional; further arguments are not supported. CPython-compatible
|
||||||
``traceback`` module can be found in `micropython-lib`.
|
``traceback`` module can be found in `micropython-lib`.
|
||||||
|
|
||||||
|
.. function:: settrace(tracefunc)
|
||||||
|
|
||||||
|
Enable tracing of bytecode execution. For details see the `CPython
|
||||||
|
documentaion <https://docs.python.org/3/library/sys.html#sys.settrace>`_.
|
||||||
|
|
||||||
|
This function requires a custom MicroPython build as it is typically not
|
||||||
|
present in pre-built firmware (due to it affecting performance). The relevant
|
||||||
|
configuration option is *MICROPY_PY_SYS_SETTRACE*.
|
||||||
|
|
||||||
Constants
|
Constants
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@ -106,6 +115,14 @@ Constants
|
|||||||
|
|
||||||
A mutable list of directories to search for imported modules.
|
A mutable list of directories to search for imported modules.
|
||||||
|
|
||||||
|
.. admonition:: Difference to CPython
|
||||||
|
:class: attention
|
||||||
|
|
||||||
|
On MicroPython, an entry with the value ``".frozen"`` will indicate that import
|
||||||
|
should search :term:`frozen modules <frozen module>` at that point in the search.
|
||||||
|
If no frozen module is found then search will *not* look for a directory called
|
||||||
|
``.frozen``, instead it will continue with the next entry in ``sys.path``.
|
||||||
|
|
||||||
.. data:: platform
|
.. data:: platform
|
||||||
|
|
||||||
The platform that MicroPython is running on. For OS/RTOS ports, this is
|
The platform that MicroPython is running on. For OS/RTOS ports, this is
|
||||||
|
|||||||
@ -68,11 +68,13 @@ Additional functions
|
|||||||
.. function:: wait_for(awaitable, timeout)
|
.. function:: wait_for(awaitable, timeout)
|
||||||
|
|
||||||
Wait for the *awaitable* to complete, but cancel it if it takes longer
|
Wait for the *awaitable* to complete, but cancel it if it takes longer
|
||||||
that *timeout* seconds. If *awaitable* is not a task then a task will be
|
than *timeout* seconds. If *awaitable* is not a task then a task will be
|
||||||
created from it.
|
created from it.
|
||||||
|
|
||||||
If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``:
|
If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``:
|
||||||
this should be trapped by the caller.
|
this should be trapped by the caller. The task receives
|
||||||
|
``asyncio.CancelledError`` which may be ignored or trapped using ``try...except``
|
||||||
|
or ``try...finally`` to run cleanup code.
|
||||||
|
|
||||||
Returns the return value of *awaitable*.
|
Returns the return value of *awaitable*.
|
||||||
|
|
||||||
@ -106,8 +108,9 @@ class Task
|
|||||||
|
|
||||||
.. method:: Task.cancel()
|
.. method:: Task.cancel()
|
||||||
|
|
||||||
Cancel the task by injecting a ``CancelledError`` into it. The task may
|
Cancel the task by injecting ``asyncio.CancelledError`` into it. The task may
|
||||||
or may not ignore this exception.
|
ignore this exception. Cleanup code may be run by trapping it, or via
|
||||||
|
``try ... finally``.
|
||||||
|
|
||||||
class Event
|
class Event
|
||||||
-----------
|
-----------
|
||||||
|
|||||||
@ -5,7 +5,7 @@ REM Command file for Sphinx documentation
|
|||||||
if "%SPHINXBUILD%" == "" (
|
if "%SPHINXBUILD%" == "" (
|
||||||
set SPHINXBUILD=sphinx-build
|
set SPHINXBUILD=sphinx-build
|
||||||
)
|
)
|
||||||
set BUILDDIR=_build
|
set BUILDDIR=build
|
||||||
set SPHINXOPTS=-W --keep-going
|
set SPHINXOPTS=-W --keep-going
|
||||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||||
|
|||||||
@ -8,8 +8,8 @@ To do this we must first edit the ``boot.py`` file to change the USB
|
|||||||
configuration. If you have not yet touched your ``boot.py`` file then it
|
configuration. If you have not yet touched your ``boot.py`` file then it
|
||||||
will look something like this::
|
will look something like this::
|
||||||
|
|
||||||
# boot.py -- run on boot-up
|
# boot.py -- run on boot to configure USB and filesystem
|
||||||
# can run arbitrary Python, but best to keep it minimal
|
# Put app code in main.py
|
||||||
|
|
||||||
import pyb
|
import pyb
|
||||||
#pyb.main('main.py') # main script to run after this one
|
#pyb.main('main.py') # main script to run after this one
|
||||||
|
|||||||
@ -219,15 +219,6 @@ resistant to filesystem corruption.
|
|||||||
situations, for details see `littlefs issue 347`_ and
|
situations, for details see `littlefs issue 347`_ and
|
||||||
`littlefs issue 295`_.
|
`littlefs issue 295`_.
|
||||||
|
|
||||||
Note: It can be still be accessed over USB MSC using the `littlefs FUSE
|
|
||||||
driver`_. Note that you must use the ``-b=4096`` option to override the block
|
|
||||||
size.
|
|
||||||
|
|
||||||
.. _littlefs FUSE driver: https://github.com/ARMmbed/littlefs-fuse/tree/master/littlefs
|
|
||||||
.. _Littlefs: https://github.com/ARMmbed/littlefs
|
|
||||||
.. _littlefs issue 295: https://github.com/ARMmbed/littlefs/issues/295
|
|
||||||
.. _littlefs issue 347: https://github.com/ARMmbed/littlefs/issues/347
|
|
||||||
|
|
||||||
To format the entire flash using littlefs v2::
|
To format the entire flash using littlefs v2::
|
||||||
|
|
||||||
# ESP8266 and ESP32
|
# ESP8266 and ESP32
|
||||||
@ -243,6 +234,27 @@ To format the entire flash using littlefs v2::
|
|||||||
os.mount(pyb.Flash(start=0), '/flash')
|
os.mount(pyb.Flash(start=0), '/flash')
|
||||||
os.chdir('/flash')
|
os.chdir('/flash')
|
||||||
|
|
||||||
|
A littlefs filesystem can be still be accessed on a PC over USB MSC using the
|
||||||
|
`littlefs FUSE driver`_. Note that you must specify both the ``--block_size``
|
||||||
|
and ``--block_count`` options to override the defaults. For example (after
|
||||||
|
building the littlefs-fuse executable)::
|
||||||
|
|
||||||
|
$ ./lfs --block_size=4096 --block_count=512 -o allow_other /dev/sdb1 mnt
|
||||||
|
|
||||||
|
This will allow the board's littlefs filesystem to be accessed at the ``mnt``
|
||||||
|
directory. To get the correct values of ``block_size`` and ``block_count`` use::
|
||||||
|
|
||||||
|
import pyb
|
||||||
|
f = pyb.Flash(start=0)
|
||||||
|
f.ioctl(1, 1) # initialise flash in littlefs raw-block mode
|
||||||
|
block_count = f.ioctl(4, 0)
|
||||||
|
block_size = f.ioctl(5, 0)
|
||||||
|
|
||||||
|
.. _littlefs FUSE driver: https://github.com/littlefs-project/littlefs-fuse
|
||||||
|
.. _Littlefs: https://github.com/littlefs-project/littlefs
|
||||||
|
.. _littlefs issue 295: https://github.com/littlefs-project/littlefs/issues/295
|
||||||
|
.. _littlefs issue 347: https://github.com/littlefs-project/littlefs/issues/347
|
||||||
|
|
||||||
Hybrid (STM32)
|
Hybrid (STM32)
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
@ -21,10 +21,12 @@ implementation and the best practices to use them.
|
|||||||
|
|
||||||
glossary.rst
|
glossary.rst
|
||||||
repl.rst
|
repl.rst
|
||||||
|
mpremote.rst
|
||||||
mpyfiles.rst
|
mpyfiles.rst
|
||||||
isr_rules.rst
|
isr_rules.rst
|
||||||
speed_python.rst
|
speed_python.rst
|
||||||
constrained.rst
|
constrained.rst
|
||||||
|
manifest.rst
|
||||||
packages.rst
|
packages.rst
|
||||||
asm_thumb2_index.rst
|
asm_thumb2_index.rst
|
||||||
filesystem.rst
|
filesystem.rst
|
||||||
|
|||||||
145
docs/reference/manifest.rst
Normal file
145
docs/reference/manifest.rst
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
MicroPython manifest files
|
||||||
|
==========================
|
||||||
|
|
||||||
|
When building firmware for a device the following components are included in
|
||||||
|
the compilation process:
|
||||||
|
|
||||||
|
- the core MicroPython virtual machine and runtime
|
||||||
|
- port-specific system code and drivers to interface with the
|
||||||
|
microcontroller/device that the firmware is targeting
|
||||||
|
- standard built-in modules, like ``sys``
|
||||||
|
- extended built-in modules, like ``json`` and ``machine``
|
||||||
|
- extra modules written in C/C++
|
||||||
|
- extra modules written in Python
|
||||||
|
|
||||||
|
All the modules included in the firmware are available via ``import`` from
|
||||||
|
Python code. The extra modules written in Python that are included in a build
|
||||||
|
(the last point above) are called *frozen modules*, and are specified by a
|
||||||
|
``manifest.py`` file. Changing this manifest requires rebuilding the firmware.
|
||||||
|
|
||||||
|
It's also possible to add additional modules to the filesystem of the device
|
||||||
|
once it is up and running. Adding and removing modules to/from the filesystem
|
||||||
|
does not require rebuilding the firmware so is a simpler process than rebuilding
|
||||||
|
firmware. The benefit of using a manifest is that frozen modules are more
|
||||||
|
efficient: they are faster to import and take up less RAM once imported.
|
||||||
|
|
||||||
|
MicroPython manifest files are Python files and can contain arbitrary Python
|
||||||
|
code. There are also a set of commands (predefined functions) which are used
|
||||||
|
to specify the Python source files to include. These commands are described
|
||||||
|
below.
|
||||||
|
|
||||||
|
Freezing source code
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
.. function:: freeze(path, script=None, opt=0)
|
||||||
|
|
||||||
|
Freeze the input specified by *path*, automatically determining its type. A
|
||||||
|
``.py`` script will be compiled to a ``.mpy`` first then frozen, and a
|
||||||
|
``.mpy`` file will be frozen directly.
|
||||||
|
|
||||||
|
*path* must be a directory, which is the base directory to begin searching
|
||||||
|
for files. When importing the resulting frozen modules, the name of the
|
||||||
|
module will start after *path*, i.e. *path* is excluded from the module
|
||||||
|
name.
|
||||||
|
|
||||||
|
If *path* is relative, it is resolved to the current ``manifest.py``. Use
|
||||||
|
``$(MPY_DIR)``, ``$(MPY_LIB_DIR)``, ``$(PORT_DIR)``, ``$(BOARD_DIR)`` if you
|
||||||
|
need to access specific paths.
|
||||||
|
|
||||||
|
If *script* is None, all files in *path* will be frozen.
|
||||||
|
|
||||||
|
If *script* is an iterable then ``freeze()`` is called on all items of the
|
||||||
|
iterable (with the same *path* and *opt* passed through).
|
||||||
|
|
||||||
|
If *script* is a string then it specifies the file or directory to freeze,
|
||||||
|
and can include extra directories before the file or last directory. The
|
||||||
|
file or directory will be searched for in *path*. If *script* is a
|
||||||
|
directory then all files in that directory will be frozen.
|
||||||
|
|
||||||
|
*opt* is the optimisation level to pass to mpy-cross when compiling ``.py``
|
||||||
|
to ``.mpy``.
|
||||||
|
|
||||||
|
.. function:: freeze_as_str(path)
|
||||||
|
|
||||||
|
Freeze the given *path* and all ``.py`` scripts within it as a string, which
|
||||||
|
will be compiled upon import.
|
||||||
|
|
||||||
|
.. function:: freeze_as_mpy(path, script=None, opt=0)
|
||||||
|
|
||||||
|
Freeze the input by first compiling the ``.py`` scripts to ``.mpy`` files,
|
||||||
|
then freezing the resulting ``.mpy`` files. See ``freeze()`` for further
|
||||||
|
details on the arguments.
|
||||||
|
|
||||||
|
.. function:: freeze_mpy(path, script=None, opt=0)
|
||||||
|
|
||||||
|
Freeze the input, which must be ``.mpy`` files that are frozen directly.
|
||||||
|
See ``freeze()`` for further details on the arguments.
|
||||||
|
|
||||||
|
|
||||||
|
Including other manifest files
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. function:: include(manifest, **kwargs)
|
||||||
|
|
||||||
|
Include another manifest.
|
||||||
|
|
||||||
|
The *manifest* argument can be a string (filename) or an iterable of
|
||||||
|
strings.
|
||||||
|
|
||||||
|
Relative paths are resolved with respect to the current manifest file.
|
||||||
|
|
||||||
|
Optional *kwargs* can be provided which will be available to the included
|
||||||
|
script via the *options* variable.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
include("path.py", extra_features=True)
|
||||||
|
|
||||||
|
then in path.py:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
options.defaults(standard_features=True)
|
||||||
|
# freeze minimal modules.
|
||||||
|
if options.standard_features:
|
||||||
|
# freeze standard modules.
|
||||||
|
if options.extra_features:
|
||||||
|
# freeze extra modules.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
To freeze a single file which is available as ``import mydriver``, use:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
freeze(".", "mydriver.py")
|
||||||
|
|
||||||
|
To freeze a set of files which are available as ``import test1`` and
|
||||||
|
``import test2``, and which are compiled with optimisation level 3, use:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
freeze("/path/to/tests", ("test1.py", "test2.py"), opt=3)
|
||||||
|
|
||||||
|
To freeze a module which can be imported as ``import mymodule``, use:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
freeze(
|
||||||
|
"../relative/path",
|
||||||
|
(
|
||||||
|
"mymodule/__init__.py",
|
||||||
|
"mymodule/core.py",
|
||||||
|
"mymodule/extra.py",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
To include a manifest from the MicroPython repository, use:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
include("$(MPY_DIR)/extmod/uasyncio/manifest.py")
|
||||||
196
docs/reference/mpremote.rst
Normal file
196
docs/reference/mpremote.rst
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
MicroPython remote control: mpremote
|
||||||
|
====================================
|
||||||
|
|
||||||
|
The ``mpremote`` command line tool provides an integrated set of utilities to
|
||||||
|
remotely interact with and automate a MicroPython device over a serial
|
||||||
|
connection.
|
||||||
|
|
||||||
|
To use mpremote install it via ``pip``:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ pip install mpremote
|
||||||
|
|
||||||
|
The simplest way to use this tool is just by invoking it without any arguments:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mpremote
|
||||||
|
|
||||||
|
This command automatically detects and connects to the first available serial
|
||||||
|
device and provides an interactive REPL. Serial ports are opened in exclusive
|
||||||
|
mode, so running a second (or third, etc) instance of ``mpremote`` will connect
|
||||||
|
to subsequent serial devices, if any are available.
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
|
--------
|
||||||
|
|
||||||
|
For REPL access, running ``mpremote`` without any arguments is usually all that
|
||||||
|
is needed. ``mpremote`` also supports a set of commands given at the command
|
||||||
|
line which will perform various actions on remote MicroPython devices.
|
||||||
|
|
||||||
|
The full list of supported commands are:
|
||||||
|
|
||||||
|
- connect to a specified device via a device-name shortcut:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote <device-shortcut>
|
||||||
|
|
||||||
|
- connect to specified device via name:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote connect <device>
|
||||||
|
|
||||||
|
``<device>`` may be one of:
|
||||||
|
|
||||||
|
- ``list``: list available devices
|
||||||
|
- ``auto``: connect to the first available device
|
||||||
|
- ``id:<serial>``: connect to the device with USB serial number
|
||||||
|
``<serial>`` (the second entry in the output from the ``connect list``
|
||||||
|
command)
|
||||||
|
- ``port:<path>``: connect to the device with the given path
|
||||||
|
- any valid device name/path, to connect to that device
|
||||||
|
|
||||||
|
- disconnect current device:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote disconnect
|
||||||
|
|
||||||
|
- enter the REPL on the connected device:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote repl [options]
|
||||||
|
|
||||||
|
Options are:
|
||||||
|
|
||||||
|
- ``--capture <file>``, to capture output of the REPL session to the given
|
||||||
|
file
|
||||||
|
- ``--inject-code <string>``, to specify characters to inject at the REPL when
|
||||||
|
Ctrl-J is pressed
|
||||||
|
- ``--inject-file <file>``, to specify a file to inject at the REPL when
|
||||||
|
Ctrl-K is pressed
|
||||||
|
|
||||||
|
- evaluate and print the result of a Python expression:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote eval <string>
|
||||||
|
|
||||||
|
- execute the given Python code:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote exec <string>
|
||||||
|
|
||||||
|
- run a script from the local filesystem:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote run <file>
|
||||||
|
|
||||||
|
- execute filesystem commands on the device:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote fs <command>
|
||||||
|
|
||||||
|
``<command>`` may be:
|
||||||
|
|
||||||
|
- ``cat <file..>`` to show the contents of a file or files on the device
|
||||||
|
- ``ls`` to list the current directory
|
||||||
|
- ``ls <dirs...>`` to list the given directories
|
||||||
|
- ``cp [-r] <src...> <dest>`` to copy files; use ":" as a prefix to specify
|
||||||
|
a file on the device
|
||||||
|
- ``rm <src...>`` to remove files on the device
|
||||||
|
- ``mkdir <dirs...>`` to create directories on the device
|
||||||
|
- ``rmdir <dirs...>`` to remove directories on the device
|
||||||
|
|
||||||
|
- mount the local directory on the remote device:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ mpremote mount <local-dir>
|
||||||
|
|
||||||
|
Multiple commands can be specified and they will be run sequentially.
|
||||||
|
Connection and disconnection will be done automatically at the start and end of
|
||||||
|
the execution of the tool, if such commands are not explicitly given. Automatic
|
||||||
|
connection will search for the first available serial device. If no action is
|
||||||
|
specified then the REPL will be entered.
|
||||||
|
|
||||||
|
Shortcuts
|
||||||
|
---------
|
||||||
|
|
||||||
|
Shortcuts can be defined using the macro system. Built-in shortcuts are::
|
||||||
|
|
||||||
|
- ``devs``: list available devices (shortcut for ``connect list``)
|
||||||
|
|
||||||
|
- ``a0``, ``a1``, ``a2``, ``a3``: connect to /dev/ttyACM?
|
||||||
|
|
||||||
|
- ``u0``, ``u1``, ``u2``, ``u3``: connect to /dev/ttyUSB?
|
||||||
|
|
||||||
|
- ``c0``, ``c1``, ``c2``, ``c3``: connect to COM?
|
||||||
|
|
||||||
|
- ``cat``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``df``: filesystem
|
||||||
|
commands
|
||||||
|
|
||||||
|
- ``reset``: reset the device
|
||||||
|
|
||||||
|
- ``bootloader``: make the device enter its bootloader
|
||||||
|
|
||||||
|
Any user configuration, including user-defined shortcuts, can be placed in the file
|
||||||
|
``.config/mpremote/config.py``. For example:
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
commands = {
|
||||||
|
"c33": "connect id:334D335C3138",
|
||||||
|
"bl": "bootloader",
|
||||||
|
"double x=4": "eval x*2", # x is an argument, with default 4
|
||||||
|
"wl_scan": ["exec", """
|
||||||
|
import network
|
||||||
|
wl = network.WLAN()
|
||||||
|
wl.active(1)
|
||||||
|
for ap in wl.scan():
|
||||||
|
print(ap)
|
||||||
|
""",],
|
||||||
|
"test": ["mount", ".", "exec", "import test"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mpremote
|
||||||
|
|
||||||
|
mpremote a1
|
||||||
|
|
||||||
|
mpremote connect /dev/ttyUSB0 repl
|
||||||
|
|
||||||
|
mpremote ls
|
||||||
|
|
||||||
|
mpremote a1 ls
|
||||||
|
|
||||||
|
mpremote exec "import micropython; micropython.mem_info()"
|
||||||
|
|
||||||
|
mpremote eval 1/2 eval 3/4
|
||||||
|
|
||||||
|
mpremote mount .
|
||||||
|
|
||||||
|
mpremote mount . exec "import local_script"
|
||||||
|
|
||||||
|
mpremote ls
|
||||||
|
|
||||||
|
mpremote cat boot.py
|
||||||
|
|
||||||
|
mpremote cp :main.py .
|
||||||
|
|
||||||
|
mpremote cp main.py :
|
||||||
|
|
||||||
|
mpremote cp -r dir/ :
|
||||||
@ -66,8 +66,6 @@ If importing an .mpy file fails then try the following:
|
|||||||
print('mpy flags:', end='')
|
print('mpy flags:', end='')
|
||||||
if arch:
|
if arch:
|
||||||
print(' -march=' + arch, end='')
|
print(' -march=' + arch, end='')
|
||||||
if sys_mpy & 0x100:
|
|
||||||
print(' -mcache-lookup-bc', end='')
|
|
||||||
if not sys_mpy & 0x200:
|
if not sys_mpy & 0x200:
|
||||||
print(' -mno-unicode', end='')
|
print(' -mno-unicode', end='')
|
||||||
print()
|
print()
|
||||||
|
|||||||
@ -92,6 +92,37 @@ Use the :ref:`machine.Pin <machine.Pin>` class::
|
|||||||
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
||||||
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
||||||
|
|
||||||
|
Programmable IO (PIO)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
PIO is useful to build low-level IO interfaces from scratch. See the :mod:`rp2` module
|
||||||
|
for detailed explaination of the assembly instructions.
|
||||||
|
|
||||||
|
Example using PIO to blink an LED at 1Hz::
|
||||||
|
|
||||||
|
from machine import Pin
|
||||||
|
import rp2
|
||||||
|
|
||||||
|
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
|
||||||
|
def blink_1hz():
|
||||||
|
# Cycles: 1 + 7 + 32 * (30 + 1) = 1000
|
||||||
|
set(pins, 1)
|
||||||
|
set(x, 31) [6]
|
||||||
|
label("delay_high")
|
||||||
|
nop() [29]
|
||||||
|
jmp(x_dec, "delay_high")
|
||||||
|
|
||||||
|
# Cycles: 1 + 7 + 32 * (30 + 1) = 1000
|
||||||
|
set(pins, 0)
|
||||||
|
set(x, 31) [6]
|
||||||
|
label("delay_low")
|
||||||
|
nop() [29]
|
||||||
|
jmp(x_dec, "delay_low")
|
||||||
|
|
||||||
|
# Create and start a StateMachine with blink_1hz, outputting on Pin(25)
|
||||||
|
sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
|
||||||
|
sm.active(1)
|
||||||
|
|
||||||
UART (serial bus)
|
UART (serial bus)
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@ -219,6 +250,26 @@ has the same methods as software I2C above::
|
|||||||
i2c = I2C(0) # default assignment: scl=Pin(9), sda=Pin(8)
|
i2c = I2C(0) # default assignment: scl=Pin(9), sda=Pin(8)
|
||||||
i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400_000)
|
i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=400_000)
|
||||||
|
|
||||||
|
I2S bus
|
||||||
|
-------
|
||||||
|
|
||||||
|
See :ref:`machine.I2S <machine.I2S>`. ::
|
||||||
|
|
||||||
|
from machine import I2S, Pin
|
||||||
|
|
||||||
|
i2s = I2S(0, sck=Pin(16), ws=Pin(17), sd=Pin(18), mode=I2S.TX, bits=16, format=I2S.STEREO, rate=44100, ibuf=40000) # create I2S object
|
||||||
|
i2s.write(buf) # write buffer of audio samples to I2S device
|
||||||
|
|
||||||
|
i2s = I2S(1, sck=Pin(0), ws=Pin(1), sd=Pin(2), mode=I2S.RX, bits=16, format=I2S.MONO, rate=22050, ibuf=40000) # create I2S object
|
||||||
|
i2s.readinto(buf) # fill buffer with audio samples from I2S device
|
||||||
|
|
||||||
|
The ``ws`` pin number must be one greater than the ``sck`` pin number.
|
||||||
|
|
||||||
|
The I2S class is currently available as a Technical Preview. During the preview period, feedback from
|
||||||
|
users is encouraged. Based on this feedback, the I2S class API and implementation may be changed.
|
||||||
|
|
||||||
|
Two I2S buses are supported with id=0 and id=1.
|
||||||
|
|
||||||
Real time clock (RTC)
|
Real time clock (RTC)
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|||||||
@ -4,3 +4,8 @@ Getting started with MicroPython on the RP2xxx
|
|||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
Let's get started!
|
Let's get started!
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
pio.rst
|
||||||
|
|||||||
123
docs/rp2/tutorial/pio.rst
Normal file
123
docs/rp2/tutorial/pio.rst
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
Programmable IO
|
||||||
|
===============
|
||||||
|
|
||||||
|
The RP2040 has hardware support for standard communication protocols like I2C,
|
||||||
|
SPI and UART. For protocols where there is no hardware support, or where there
|
||||||
|
is a requirement of custom I/O behaviour, Programmable Input Output (PIO) comes
|
||||||
|
into play. Also, some MicroPython applications make use of a technique called
|
||||||
|
bit banging in which pins are rapidly turned on and off to transmit data. This
|
||||||
|
can make the entire process slow as the processor concentrates on bit banging
|
||||||
|
rather than executing other logic. However, PIO allows bit banging to happen
|
||||||
|
in the background while the CPU is executing the main work.
|
||||||
|
|
||||||
|
Along with the two central Cortex-M0+ processing cores, the RP2040 has two PIO
|
||||||
|
blocks each of which has four independent state machines. These state machines
|
||||||
|
can transfer data to/from other entities using First-In-First-Out (FIFO) buffers,
|
||||||
|
which allow the state machine and main processor to work independently yet also
|
||||||
|
synchronise their data. Each FIFO has four words (each of 32 bits) which can be
|
||||||
|
linked to the DMA to transfer larger amounts of data.
|
||||||
|
|
||||||
|
All PIO instructions follow a common pattern::
|
||||||
|
|
||||||
|
<instruction> .side(<side_set_value>) [<delay_value>]
|
||||||
|
|
||||||
|
The side-set ``.side(...)`` and delay ``[...]`` parts are both optional, and if
|
||||||
|
specified allow the instruction to perform more than one operation. This keeps
|
||||||
|
PIO programs small and efficient.
|
||||||
|
|
||||||
|
There are nine instructions which perform the following tasks:
|
||||||
|
|
||||||
|
- ``jmp()`` transfers control to a different part of the code
|
||||||
|
- ``wait()`` pauses until a particular action happens
|
||||||
|
- ``in_()`` shifts the bits from a source (scratch register or set of pins) to the
|
||||||
|
input shift register
|
||||||
|
- ``out()`` shifts the bits from the output shift register to a destination
|
||||||
|
- ``push()`` sends data to the RX FIFO
|
||||||
|
- ``pull()`` receives data from the TX FIFO
|
||||||
|
- ``mov()`` moves data from a source to a destination
|
||||||
|
- ``irq()`` sets or clears an IRQ flag
|
||||||
|
- ``set()`` writes a literal value to a destination
|
||||||
|
|
||||||
|
The instruction modifiers are:
|
||||||
|
|
||||||
|
- ``.side()`` sets the side-set pins at the start of the instruction
|
||||||
|
- ``[]`` delays for a certain number of cycles after execution of the instruction
|
||||||
|
|
||||||
|
There are also directives:
|
||||||
|
|
||||||
|
- ``wrap_target()`` specifies where the program execution will get continued from
|
||||||
|
- ``wrap()`` specifies the instruction where the control flow of the program will
|
||||||
|
get wrapped from
|
||||||
|
- ``label()`` sets a label for use with ``jmp()`` instructions
|
||||||
|
- ``word()`` emits a raw 16-bit value which acts as an instruction in the program
|
||||||
|
|
||||||
|
An example
|
||||||
|
----------
|
||||||
|
|
||||||
|
Take the ``pio_1hz.py`` example for a simple understanding of how to use the PIO
|
||||||
|
and state machines. Below is the code for reference.
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
# Example using PIO to blink an LED and raise an IRQ at 1Hz.
|
||||||
|
|
||||||
|
import time
|
||||||
|
from machine import Pin
|
||||||
|
import rp2
|
||||||
|
|
||||||
|
|
||||||
|
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
|
||||||
|
def blink_1hz():
|
||||||
|
# Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
|
||||||
|
irq(rel(0))
|
||||||
|
set(pins, 1)
|
||||||
|
set(x, 31) [5]
|
||||||
|
label("delay_high")
|
||||||
|
nop() [29]
|
||||||
|
jmp(x_dec, "delay_high")
|
||||||
|
|
||||||
|
# Cycles: 1 + 7 + 32 * (30 + 1) = 1000
|
||||||
|
set(pins, 0)
|
||||||
|
set(x, 31) [6]
|
||||||
|
label("delay_low")
|
||||||
|
nop() [29]
|
||||||
|
jmp(x_dec, "delay_low")
|
||||||
|
|
||||||
|
|
||||||
|
# Create the StateMachine with the blink_1hz program, outputting on Pin(25).
|
||||||
|
sm = rp2.StateMachine(0, blink_1hz, freq=2000, set_base=Pin(25))
|
||||||
|
|
||||||
|
# Set the IRQ handler to print the millisecond timestamp.
|
||||||
|
sm.irq(lambda p: print(time.ticks_ms()))
|
||||||
|
|
||||||
|
# Start the StateMachine.
|
||||||
|
sm.active(1)
|
||||||
|
|
||||||
|
This creates an instance of class :class:`rp2.StateMachine` which runs the
|
||||||
|
``blink_1hz`` program at 2000Hz, and connects to pin 25. The ``blink_1hz``
|
||||||
|
program uses the PIO to blink an LED connected to this pin at 1Hz, and also
|
||||||
|
raises an IRQ as the LED turns on. This IRQ then calls the ``lambda`` function
|
||||||
|
which prints out a millisecond timestamp.
|
||||||
|
|
||||||
|
The ``blink_1hz`` program is a PIO assembler routine. It connects to a single
|
||||||
|
pin which is configured as an output and starts out low. The instructions do
|
||||||
|
the following:
|
||||||
|
|
||||||
|
- ``irq(rel(0))`` raises the IRQ associated with the state machine.
|
||||||
|
- The LED is turned on via the ``set(pins, 1)`` instruction.
|
||||||
|
- The value 31 is put into register X, and then there is a delay for 5 more
|
||||||
|
cycles, specified by the ``[5]``.
|
||||||
|
- The ``nop() [29]`` instruction waits for 30 cycles.
|
||||||
|
- The ``jmp(x_dec, "delay_high")`` will keep looping to the ``delay_high`` label
|
||||||
|
as long as the register X is non-zero, and will also post-decrement X. Since
|
||||||
|
X starts with the value 31 this jump will happen 31 times, so the ``nop() [29]``
|
||||||
|
runs 32 times in total (note there is also one instruction cycle taken by the
|
||||||
|
``jmp`` for each of these 32 loops).
|
||||||
|
- ``set(pins, 0)`` will turn the LED off by setting pin 25 low.
|
||||||
|
- Another 32 loops of ``nop() [29]`` and ``jmp(...)`` will execute.
|
||||||
|
- Because ``wrap_target()`` and ``wrap()`` are not specified, their default will
|
||||||
|
be used and execution of the program will wrap around from the bottom to the
|
||||||
|
top. This wrapping does not cost any execution cycles.
|
||||||
|
|
||||||
|
The entire routine takes exactly 2000 cycles of the state machine. Setting the
|
||||||
|
frequency of the state machine to 2000Hz makes the LED blink at 1Hz.
|
||||||
@ -31,8 +31,8 @@ With your serial program open (PuTTY, screen, picocom, etc) you may see a
|
|||||||
blank screen with a flashing cursor. Press Enter (or reset the board) and
|
blank screen with a flashing cursor. Press Enter (or reset the board) and
|
||||||
you should be presented with the following text::
|
you should be presented with the following text::
|
||||||
|
|
||||||
*** Booting Zephyr OS build v2.6.0-rc1-416-g3056c5ec30ad ***
|
*** Booting Zephyr OS build zephyr-v2.7.0 ***
|
||||||
MicroPython v2.6.0-rc1-416-g3056c5ec30 on 2021-06-24; zephyr-frdm_k64f with mk64f12
|
MicroPython v1.17-288-gb695f5a70-dirty on 2022-01-03; zephyr-frdm_k64f with mk64f12
|
||||||
Type "help()" for more information.
|
Type "help()" for more information.
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
# DHT11/DHT22 driver for MicroPython on ESP8266
|
# DHT11/DHT22 driver for MicroPython on ESP8266
|
||||||
# MIT license; Copyright (c) 2016 Damien P. George
|
# MIT license; Copyright (c) 2016 Damien P. George
|
||||||
|
|
||||||
try:
|
import sys
|
||||||
|
|
||||||
|
if sys.platform.startswith("esp"):
|
||||||
from esp import dht_readinto
|
from esp import dht_readinto
|
||||||
except:
|
elif sys.platform == "mimxrt":
|
||||||
|
from mimxrt import dht_readinto
|
||||||
|
elif sys.platform == "rp2":
|
||||||
|
from rp2 import dht_readinto
|
||||||
|
else:
|
||||||
from pyb import dht_readinto
|
from pyb import dht_readinto
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
234
drivers/lsm6dsox/lsm6dsox.py
Normal file
234
drivers/lsm6dsox/lsm6dsox.py
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
"""
|
||||||
|
LSM6DSOX STMicro driver for MicroPython based on LSM9DS1:
|
||||||
|
Source repo: https://github.com/hoihu/projects/tree/master/raspi-hat
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2021 Damien P. George
|
||||||
|
Copyright (c) 2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Basic example usage:
|
||||||
|
|
||||||
|
import time
|
||||||
|
from lsm6dsox import LSM6DSOX
|
||||||
|
|
||||||
|
from machine import Pin, I2C
|
||||||
|
lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
|
||||||
|
|
||||||
|
while (True):
|
||||||
|
print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
|
||||||
|
print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
|
||||||
|
print("")
|
||||||
|
time.sleep_ms(100)
|
||||||
|
"""
|
||||||
|
import array
|
||||||
|
from micropython import const
|
||||||
|
|
||||||
|
|
||||||
|
class LSM6DSOX:
|
||||||
|
_CTRL3_C = const(0x12)
|
||||||
|
_CTRL1_XL = const(0x10)
|
||||||
|
_CTRL8_XL = const(0x17)
|
||||||
|
_CTRL9_XL = const(0x18)
|
||||||
|
|
||||||
|
_CTRL2_G = const(0x11)
|
||||||
|
_CTRL7_G = const(0x16)
|
||||||
|
|
||||||
|
_OUTX_L_G = const(0x22)
|
||||||
|
_OUTX_L_XL = const(0x28)
|
||||||
|
_MLC_STATUS = const(0x38)
|
||||||
|
|
||||||
|
_DEFAULT_ADDR = const(0x6A)
|
||||||
|
_WHO_AM_I_REG = const(0x0F)
|
||||||
|
|
||||||
|
_FUNC_CFG_ACCESS = const(0x01)
|
||||||
|
_FUNC_CFG_BANK_USER = const(0)
|
||||||
|
_FUNC_CFG_BANK_HUB = const(1)
|
||||||
|
_FUNC_CFG_BANK_EMBED = const(2)
|
||||||
|
|
||||||
|
_MLC0_SRC = const(0x70)
|
||||||
|
_MLC_INT1 = const(0x0D)
|
||||||
|
_TAP_CFG0 = const(0x56)
|
||||||
|
|
||||||
|
_EMB_FUNC_EN_A = const(0x04)
|
||||||
|
_EMB_FUNC_EN_B = const(0x05)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
i2c,
|
||||||
|
address=_DEFAULT_ADDR,
|
||||||
|
gyro_odr=104,
|
||||||
|
accel_odr=104,
|
||||||
|
gyro_scale=2000,
|
||||||
|
accel_scale=4,
|
||||||
|
ucf=None,
|
||||||
|
):
|
||||||
|
"""Initalizes Gyro and Accelerator.
|
||||||
|
accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
|
||||||
|
gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
|
||||||
|
gyro_scale: (245dps, 500dps, 1000dps, 2000dps)
|
||||||
|
accel_scale: (+/-2g, +/-4g, +/-8g, +-16g)
|
||||||
|
ucf: MLC program to load.
|
||||||
|
"""
|
||||||
|
self.i2c = i2c
|
||||||
|
self.address = address
|
||||||
|
|
||||||
|
# check the id of the Accelerometer/Gyro
|
||||||
|
if self.__read_reg(_WHO_AM_I_REG) != 108:
|
||||||
|
raise OSError("No LSM6DS device was found at address 0x%x" % (self.address))
|
||||||
|
|
||||||
|
# allocate scratch buffer for efficient conversions and memread op's
|
||||||
|
self.scratch_int = array.array("h", [0, 0, 0])
|
||||||
|
|
||||||
|
SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3}
|
||||||
|
SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1}
|
||||||
|
# XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default.
|
||||||
|
ODR = {
|
||||||
|
0: 0x00,
|
||||||
|
1.6: 0x08,
|
||||||
|
3.33: 0x09,
|
||||||
|
6.66: 0x0A,
|
||||||
|
12.5: 0x01,
|
||||||
|
26: 0x02,
|
||||||
|
52: 0x03,
|
||||||
|
104: 0x04,
|
||||||
|
208: 0x05,
|
||||||
|
416: 0x06,
|
||||||
|
888: 0x07,
|
||||||
|
}
|
||||||
|
|
||||||
|
gyro_odr = round(gyro_odr, 2)
|
||||||
|
accel_odr = round(accel_odr, 2)
|
||||||
|
|
||||||
|
# Sanity checks
|
||||||
|
if not gyro_odr in ODR:
|
||||||
|
raise ValueError("Invalid sampling rate: %d" % accel_odr)
|
||||||
|
if not gyro_scale in SCALE_GYRO:
|
||||||
|
raise ValueError("invalid gyro scaling: %d" % gyro_scale)
|
||||||
|
if not accel_odr in ODR:
|
||||||
|
raise ValueError("Invalid sampling rate: %d" % accel_odr)
|
||||||
|
if not accel_scale in SCALE_ACCEL:
|
||||||
|
raise ValueError("invalid accelerometer scaling: %d" % accel_scale)
|
||||||
|
|
||||||
|
# Soft-reset the device.
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
# Load and configure MLC if UCF file is provided
|
||||||
|
if ucf != None:
|
||||||
|
self.load_mlc(ucf)
|
||||||
|
|
||||||
|
# Set Gyroscope datarate and scale.
|
||||||
|
# Note output from LPF2 second filtering stage is selected. See Figure 18.
|
||||||
|
self.__write_reg(_CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2)
|
||||||
|
|
||||||
|
# Enable LPF2 and HPF fast-settling mode, ODR/4
|
||||||
|
self.__write_reg(_CTRL8_XL, 0x09)
|
||||||
|
|
||||||
|
# Set Gyroscope datarate and scale.
|
||||||
|
self.__write_reg(_CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0)
|
||||||
|
|
||||||
|
self.gyro_scale = 32768 / gyro_scale
|
||||||
|
self.accel_scale = 32768 / accel_scale
|
||||||
|
|
||||||
|
def __read_reg(self, reg, size=1):
|
||||||
|
buf = self.i2c.readfrom_mem(self.address, reg, size)
|
||||||
|
if size == 1:
|
||||||
|
return int(buf[0])
|
||||||
|
return [int(x) for x in buf]
|
||||||
|
|
||||||
|
def __write_reg(self, reg, val):
|
||||||
|
self.i2c.writeto_mem(self.address, reg, bytes([val]))
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x1)
|
||||||
|
for i in range(0, 10):
|
||||||
|
if (self.__read_reg(_CTRL3_C) & 0x01) == 0:
|
||||||
|
return
|
||||||
|
time.sleep_ms(10)
|
||||||
|
raise OSError("Failed to reset LSM6DS device.")
|
||||||
|
|
||||||
|
def set_mem_bank(self, bank):
|
||||||
|
cfg = self.__read_reg(_FUNC_CFG_ACCESS) & 0x3F
|
||||||
|
self.__write_reg(_FUNC_CFG_ACCESS, cfg | (bank << 6))
|
||||||
|
|
||||||
|
def set_embedded_functions(self, enable, emb_ab=None):
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
|
||||||
|
if enable:
|
||||||
|
self.__write_reg(_EMB_FUNC_EN_A, emb_ab[0])
|
||||||
|
self.__write_reg(_EMB_FUNC_EN_B, emb_ab[1])
|
||||||
|
else:
|
||||||
|
emb_a = self.__read_reg(_EMB_FUNC_EN_A)
|
||||||
|
emb_b = self.__read_reg(_EMB_FUNC_EN_B)
|
||||||
|
self.__write_reg(_EMB_FUNC_EN_A, (emb_a & 0xC7))
|
||||||
|
self.__write_reg(_EMB_FUNC_EN_B, (emb_b & 0xE6))
|
||||||
|
emb_ab = (emb_a, emb_b)
|
||||||
|
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_USER)
|
||||||
|
return emb_ab
|
||||||
|
|
||||||
|
def load_mlc(self, ucf):
|
||||||
|
# Load MLC config from file
|
||||||
|
with open(ucf, "r") as ucf_file:
|
||||||
|
for l in ucf_file:
|
||||||
|
if l.startswith("Ac"):
|
||||||
|
v = [int(v, 16) for v in l.strip().split(" ")[1:3]]
|
||||||
|
self.__write_reg(v[0], v[1])
|
||||||
|
|
||||||
|
emb_ab = self.set_embedded_functions(False)
|
||||||
|
|
||||||
|
# Disable I3C interface
|
||||||
|
self.__write_reg(_CTRL9_XL, self.__read_reg(_CTRL9_XL) | 0x01)
|
||||||
|
|
||||||
|
# Enable Block Data Update
|
||||||
|
self.__write_reg(_CTRL3_C, self.__read_reg(_CTRL3_C) | 0x40)
|
||||||
|
|
||||||
|
# Route signals on interrupt pin 1
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
|
||||||
|
self.__write_reg(_MLC_INT1, self.__read_reg(_MLC_INT1) & 0x01)
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_USER)
|
||||||
|
|
||||||
|
# Configure interrupt pin mode
|
||||||
|
self.__write_reg(_TAP_CFG0, self.__read_reg(_TAP_CFG0) | 0x41)
|
||||||
|
|
||||||
|
self.set_embedded_functions(True, emb_ab)
|
||||||
|
|
||||||
|
def read_mlc_output(self):
|
||||||
|
buf = None
|
||||||
|
if self.__read_reg(_MLC_STATUS) & 0x1:
|
||||||
|
self.__read_reg(0x1A, size=12)
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_EMBED)
|
||||||
|
buf = self.__read_reg(_MLC0_SRC, 8)
|
||||||
|
self.set_mem_bank(_FUNC_CFG_BANK_USER)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def read_gyro(self):
|
||||||
|
"""Returns gyroscope vector in degrees/sec."""
|
||||||
|
mv = memoryview(self.scratch_int)
|
||||||
|
f = self.gyro_scale
|
||||||
|
self.i2c.readfrom_mem_into(self.address, _OUTX_L_G, mv)
|
||||||
|
return (mv[0] / f, mv[1] / f, mv[2] / f)
|
||||||
|
|
||||||
|
def read_accel(self):
|
||||||
|
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
|
||||||
|
mv = memoryview(self.scratch_int)
|
||||||
|
f = self.accel_scale
|
||||||
|
self.i2c.readfrom_mem_into(self.address, _OUTX_L_XL, mv)
|
||||||
|
return (mv[0] / f, mv[1] / f, mv[2] / f)
|
||||||
13
drivers/lsm6dsox/lsm6dsox_basic.py
Normal file
13
drivers/lsm6dsox/lsm6dsox_basic.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# LSM6DSOX Basic Example.
|
||||||
|
import time
|
||||||
|
from lsm6dsox import LSM6DSOX
|
||||||
|
|
||||||
|
from machine import Pin, I2C
|
||||||
|
|
||||||
|
lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_accel()))
|
||||||
|
print("Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_gyro()))
|
||||||
|
print("")
|
||||||
|
time.sleep_ms(100)
|
||||||
48
drivers/lsm6dsox/lsm6dsox_mlc.py
Normal file
48
drivers/lsm6dsox/lsm6dsox_mlc.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# LSM6DSOX IMU MLC (Machine Learning Core) Example.
|
||||||
|
# Download the raw UCF file, copy to storage and reset.
|
||||||
|
|
||||||
|
# NOTE: The pre-trained models (UCF files) for the examples can be found here:
|
||||||
|
# https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox
|
||||||
|
|
||||||
|
import time
|
||||||
|
from lsm6dsox import LSM6DSOX
|
||||||
|
from machine import Pin, I2C
|
||||||
|
|
||||||
|
INT_MODE = True # Run in interrupt mode.
|
||||||
|
INT_FLAG = False # Set True on interrupt.
|
||||||
|
|
||||||
|
|
||||||
|
def imu_int_handler(pin):
|
||||||
|
global INT_FLAG
|
||||||
|
INT_FLAG = True
|
||||||
|
|
||||||
|
|
||||||
|
if INT_MODE == True:
|
||||||
|
int_pin = Pin(24)
|
||||||
|
int_pin.irq(handler=imu_int_handler, trigger=Pin.IRQ_RISING)
|
||||||
|
|
||||||
|
i2c = I2C(0, scl=Pin(13), sda=Pin(12))
|
||||||
|
|
||||||
|
# Vibration detection example
|
||||||
|
UCF_FILE = "lsm6dsox_vibration_monitoring.ucf"
|
||||||
|
UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"}
|
||||||
|
# NOTE: Selected data rate and scale must match the MLC data rate and scale.
|
||||||
|
lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=2000, accel_scale=4, ucf=UCF_FILE)
|
||||||
|
|
||||||
|
# Head gestures example
|
||||||
|
# UCF_FILE = "lsm6dsox_head_gestures.ucf"
|
||||||
|
# UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"}
|
||||||
|
# NOTE: Selected data rate and scale must match the MLC data rate and scale.
|
||||||
|
# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE)
|
||||||
|
|
||||||
|
print("MLC configured...")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if INT_MODE:
|
||||||
|
if INT_FLAG:
|
||||||
|
INT_FLAG = False
|
||||||
|
print(UCF_LABELS[lsm.read_mlc_output()[0]])
|
||||||
|
else:
|
||||||
|
buf = lsm.read_mlc_output()
|
||||||
|
if buf != None:
|
||||||
|
print(UCF_LABELS[buf[0]])
|
||||||
@ -36,10 +36,14 @@ class NeoPixel:
|
|||||||
|
|
||||||
def fill(self, v):
|
def fill(self, v):
|
||||||
b = self.buf
|
b = self.buf
|
||||||
for i in range(self.bpp):
|
l = len(self.buf)
|
||||||
|
bpp = self.bpp
|
||||||
|
for i in range(bpp):
|
||||||
c = v[i]
|
c = v[i]
|
||||||
for j in range(self.ORDER[i], len(self.buf), self.bpp):
|
j = self.ORDER[i]
|
||||||
|
while j < l:
|
||||||
b[j] = c
|
b[j] = c
|
||||||
|
j += bpp
|
||||||
|
|
||||||
def write(self):
|
def write(self):
|
||||||
# BITSTREAM_TYPE_HIGH_LOW = 0
|
# BITSTREAM_TYPE_HIGH_LOW = 0
|
||||||
|
|||||||
39
drivers/ninaw10/nina_bsp.h
Normal file
39
drivers/ninaw10/nina_bsp.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project, https://openmv.io.
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 driver BSP.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
|
||||||
|
#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
|
||||||
|
|
||||||
|
int nina_bsp_init(void);
|
||||||
|
int nina_bsp_deinit(void);
|
||||||
|
int nina_bsp_read_irq(void);
|
||||||
|
int nina_bsp_spi_slave_select(uint32_t timeout);
|
||||||
|
int nina_bsp_spi_slave_deselect(void);
|
||||||
|
int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_BSP_H
|
||||||
150
drivers/ninaw10/nina_bt_hci.c
Normal file
150
drivers/ninaw10/nina_bt_hci.c
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project, https://openmv.io.
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 Bluetooth HCI driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "extmod/mpbthci.h"
|
||||||
|
|
||||||
|
#define HCI_COMMAND_PACKET (0x01)
|
||||||
|
#define HCI_ACLDATA_PACKET (0x02)
|
||||||
|
#define HCI_EVENT_PACKET (0x04)
|
||||||
|
|
||||||
|
#define HCI_COMMAND_COMPLETE (0x0e)
|
||||||
|
#define HCI_COMMAND_TIMEOUT (3000)
|
||||||
|
|
||||||
|
#define OGF_LINK_CTL (0x01)
|
||||||
|
#define OGF_HOST_CTL (0x03)
|
||||||
|
|
||||||
|
#define OCF_SET_EVENT_MASK (0x0001)
|
||||||
|
#define OCF_RESET (0x0003)
|
||||||
|
|
||||||
|
#define error_printf(...) mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
|
||||||
|
#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bt_hci.c: " __VA_ARGS__)
|
||||||
|
|
||||||
|
// Provided by the port, and also possibly shared with the stack.
|
||||||
|
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
||||||
|
|
||||||
|
static int nina_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_buf) {
|
||||||
|
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
|
||||||
|
|
||||||
|
buf[0] = HCI_COMMAND_PACKET;
|
||||||
|
buf[1] = ocf;
|
||||||
|
buf[2] = ogf << 2 | ocf >> 8;
|
||||||
|
buf[3] = param_len;
|
||||||
|
|
||||||
|
if (param_len) {
|
||||||
|
memcpy(buf + 4, param_buf, param_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_printf("HCI Command: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
|
||||||
|
|
||||||
|
mp_bluetooth_hci_uart_write(buf, 4 + param_len);
|
||||||
|
|
||||||
|
// Receive HCI event packet, initially reading 3 bytes (HCI Event, Event code, Plen).
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(), size = 3, i = 0; i < size;) {
|
||||||
|
while (!mp_bluetooth_hci_uart_any()) {
|
||||||
|
MICROPY_EVENT_POLL_HOOK
|
||||||
|
// Timeout.
|
||||||
|
if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
|
||||||
|
error_printf("timeout waiting for HCI packet\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = mp_bluetooth_hci_uart_readchar();
|
||||||
|
|
||||||
|
// There seems to be a sync issue with this fw/module.
|
||||||
|
if (i == 0 && buf[0] == 0xFF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for packet type.
|
||||||
|
if (i == 0 && buf[0] != HCI_EVENT_PACKET) {
|
||||||
|
error_printf("unexpected HCI packet: %02x\n", buf[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check the packet parameters length.
|
||||||
|
if (i == 2 && ((size += buf[2]) > sizeof(mp_bluetooth_hci_cmd_buf))) {
|
||||||
|
error_printf("unexpected event packet length: %d\n", size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're only looking for command complete events.
|
||||||
|
if (buf[1] != HCI_COMMAND_COMPLETE || buf[4] != ocf || buf[5] != (ogf << 2 | ocf >> 8)) {
|
||||||
|
error_printf("response mismatch: %02x %02x\n", buf[4], buf[5]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log event.
|
||||||
|
debug_printf("HCI Event packet: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
|
||||||
|
|
||||||
|
// Status code.
|
||||||
|
return buf[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
int mp_bluetooth_hci_controller_init(void) {
|
||||||
|
// This is called immediately after the UART is initialised during stack initialisation.
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
|
||||||
|
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
|
||||||
|
mp_hal_delay_ms(100);
|
||||||
|
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
|
||||||
|
mp_hal_delay_ms(750);
|
||||||
|
|
||||||
|
// The UART must be re-initialize here because the GPIO1/RX pin is used initially
|
||||||
|
// to reset the module in Bluetooth mode. This will change back the pin to UART RX.
|
||||||
|
mp_bluetooth_hci_uart_init(0, 0);
|
||||||
|
|
||||||
|
// Send reset command
|
||||||
|
return nina_hci_cmd(OGF_HOST_CTL, OCF_RESET, 0, NULL);
|
||||||
|
// It seems that nothing else is needed for now.
|
||||||
|
}
|
||||||
|
|
||||||
|
int mp_bluetooth_hci_controller_deinit(void) {
|
||||||
|
// Reset module
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
139
drivers/ninaw10/nina_wifi_bsp.c
Normal file
139
drivers/ninaw10/nina_wifi_bsp.c
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project, https://openmv.io.
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 driver BSP implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK_NINAW10
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "modmachine.h"
|
||||||
|
#include "extmod/machine_spi.h"
|
||||||
|
#include "mpconfigboard.h"
|
||||||
|
|
||||||
|
#include "nina_bsp.h"
|
||||||
|
#include "nina_wifi_drv.h"
|
||||||
|
|
||||||
|
#if NINA_DEBUG
|
||||||
|
#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug_printf(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int nina_bsp_init(void) {
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
|
||||||
|
mp_hal_pin_input(MICROPY_HW_NINA_ACK);
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
|
||||||
|
|
||||||
|
// Reset module in WiFi mode
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
|
||||||
|
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
|
||||||
|
mp_hal_delay_ms(100);
|
||||||
|
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 1);
|
||||||
|
mp_hal_delay_ms(750);
|
||||||
|
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 0);
|
||||||
|
mp_hal_pin_input(MICROPY_HW_NINA_GPIO0);
|
||||||
|
|
||||||
|
// Initialize SPI.
|
||||||
|
mp_obj_t args[] = {
|
||||||
|
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_ID),
|
||||||
|
MP_OBJ_NEW_SMALL_INT(MICROPY_HW_WIFI_SPI_BAUDRATE),
|
||||||
|
};
|
||||||
|
|
||||||
|
MP_STATE_PORT(mp_wifi_spi) = machine_spi_type.make_new((mp_obj_t)&machine_spi_type, 2, 0, args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_bsp_deinit(void) {
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_GPIO1);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
|
||||||
|
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_RESET);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_RESET, 0);
|
||||||
|
mp_hal_delay_ms(100);
|
||||||
|
|
||||||
|
mp_hal_pin_output(MICROPY_HW_NINA_GPIO0);
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO0, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_bsp_read_irq(void) {
|
||||||
|
return mp_hal_pin_read(MICROPY_HW_NINA_GPIO0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_bsp_spi_slave_select(uint32_t timeout) {
|
||||||
|
// Wait for ACK to go low.
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 1; mp_hal_delay_ms(1)) {
|
||||||
|
if ((mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chip select.
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 0);
|
||||||
|
|
||||||
|
// Wait for ACK to go high.
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); mp_hal_pin_read(MICROPY_HW_NINA_ACK) == 0; mp_hal_delay_ms(1)) {
|
||||||
|
if ((mp_hal_ticks_ms() - start) >= 100) {
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_bsp_spi_slave_deselect(void) {
|
||||||
|
mp_hal_pin_write(MICROPY_HW_NINA_GPIO1, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_bsp_spi_transfer(const uint8_t *tx_buf, uint8_t *rx_buf, uint32_t size) {
|
||||||
|
mp_obj_t mp_wifi_spi = MP_STATE_PORT(mp_wifi_spi);
|
||||||
|
((mp_machine_spi_p_t *)machine_spi_type.protocol)->transfer(mp_wifi_spi, size, tx_buf, rx_buf);
|
||||||
|
#if NINA_DEBUG
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (tx_buf) {
|
||||||
|
debug_printf("0x%x ", tx_buf[i]);
|
||||||
|
} else {
|
||||||
|
debug_printf("0x%x ", rx_buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_NETWORK_NINAW10
|
||||||
931
drivers/ninaw10/nina_wifi_drv.c
Normal file
931
drivers/ninaw10/nina_wifi_drv.c
Normal file
@ -0,0 +1,931 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project, https://openmv.io.
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 WiFi driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK_NINAW10
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "nina_bsp.h"
|
||||||
|
#include "nina_wifi_drv.h"
|
||||||
|
|
||||||
|
#define SPI_ACK (1)
|
||||||
|
#define SPI_ERR (0xFF)
|
||||||
|
|
||||||
|
#define NO_SOCKET_AVAIL (255)
|
||||||
|
|
||||||
|
#define CMD_START (0xE0)
|
||||||
|
#define CMD_END (0xEE)
|
||||||
|
#define CMD_ERROR (0xEF)
|
||||||
|
#define CMD_REPLY (1 << 7)
|
||||||
|
|
||||||
|
#define ARG_8BITS (1)
|
||||||
|
#define ARG_16BITS (2)
|
||||||
|
|
||||||
|
#define ARG_STR(x) {strlen(x), (const void *)x}
|
||||||
|
#define ARG_BYTE(x) {1, (uint8_t [1]) {x}}
|
||||||
|
#define ARG_SHORT(x) {2, (uint16_t [1]) {x}}
|
||||||
|
#define ARG_WORD(x) {4, (uint32_t [1]) {x}}
|
||||||
|
|
||||||
|
#define NINA_ARGS(...) (nina_args_t []) {__VA_ARGS__}
|
||||||
|
#define NINA_VALS(...) (nina_vals_t []) {__VA_ARGS__}
|
||||||
|
|
||||||
|
#define NINA_SSELECT_TIMEOUT (10000)
|
||||||
|
#define NINA_RESPONSE_TIMEOUT (1000)
|
||||||
|
#define NINA_CONNECT_TIMEOUT (10000)
|
||||||
|
|
||||||
|
#if NINA_DEBUG
|
||||||
|
#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug_printf(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __REVSH
|
||||||
|
#define __REVSH(x) ((((uint16_t)x) << 8) | (((uint16_t)x) >> 8))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t size;
|
||||||
|
const void *data;
|
||||||
|
} nina_args_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t *size;
|
||||||
|
void *data;
|
||||||
|
} nina_vals_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
// STA mode commands.
|
||||||
|
NINA_CMD_CONNECT_OPEN = 0x10,
|
||||||
|
NINA_CMD_CONNECT_WEP = 0x11,
|
||||||
|
NINA_CMD_CONNECT_WPA = 0x12,
|
||||||
|
NINA_CMD_GET_SSID = 0x23,
|
||||||
|
NINA_CMD_GET_BSSID = 0x24,
|
||||||
|
NINA_CMD_GET_RSSI = 0x25,
|
||||||
|
NINA_CMD_GET_ENCRYPT = 0x26,
|
||||||
|
|
||||||
|
// AP mode commands.
|
||||||
|
NINA_CMD_START_AP_OPEN = 0x18,
|
||||||
|
NINA_CMD_START_AP_WEP = 0x19,
|
||||||
|
|
||||||
|
// AP mode scan commands.
|
||||||
|
NINA_CMD_AP_START_SCAN = 0x36,
|
||||||
|
NINA_CMD_AP_SCAN_RESULT = 0x27,
|
||||||
|
NINA_CMD_AP_GET_RSSI = 0x32,
|
||||||
|
NINA_CMD_AP_GET_ENCRYPT = 0x33,
|
||||||
|
NINA_CMD_AP_GET_BSSID = 0x3C,
|
||||||
|
NINA_CMD_AP_GET_CHANNEL = 0x3D,
|
||||||
|
|
||||||
|
// Disonnect/status commands.
|
||||||
|
NINA_CMD_DISCONNECT = 0x30,
|
||||||
|
NINA_CMD_CONN_STATUS = 0x20,
|
||||||
|
|
||||||
|
// Interface config commands.
|
||||||
|
NINA_CMD_SET_IF_CONFIG = 0x14,
|
||||||
|
NINA_CMD_GET_IF_CONFIG = 0x21,
|
||||||
|
NINA_CMD_SET_DNS_CONFIG = 0x15,
|
||||||
|
|
||||||
|
// Hostname/Resolv commands.
|
||||||
|
NINA_CMD_SET_HOSTNAME = 0x16,
|
||||||
|
NINA_CMD_HOST_BY_NAME = 0x34,
|
||||||
|
NINA_CMD_GET_HOST_BY_NAME = 0x35,
|
||||||
|
|
||||||
|
// Misc commands.
|
||||||
|
NINA_CMD_SET_POWER = 0x17,
|
||||||
|
NINA_CMD_PING = 0x3E,
|
||||||
|
NINA_CMD_GET_TIME = 0x3B,
|
||||||
|
NINA_CMD_GET_FW_VERSION = 0x37,
|
||||||
|
NINA_CMD_DEBUG_MODE = 0x1A,
|
||||||
|
NINA_CMD_TEMP_SENSOR = 0x1B,
|
||||||
|
NINA_CMD_GET_MAC_ADDR = 0x22,
|
||||||
|
|
||||||
|
// Sockets commands.
|
||||||
|
NINA_CMD_SOCKET_OPEN = 0x3F,
|
||||||
|
NINA_CMD_SOCKET_CLOSE = 0x2E,
|
||||||
|
NINA_CMD_SOCKET_CONNECT = 0x2D,
|
||||||
|
NINA_CMD_SOCKET_ACCEPT = 0x2B,
|
||||||
|
NINA_CMD_SOCKET_BIND = 0x28,
|
||||||
|
NINA_CMD_SOCKET_STATE = 0x2F,
|
||||||
|
NINA_CMD_SOCKET_REMOTE_ADDR = 0x3A,
|
||||||
|
|
||||||
|
// TCP commands
|
||||||
|
NINA_CMD_TCP_SEND = 0x44,
|
||||||
|
NINA_CMD_TCP_RECV = 0x45,
|
||||||
|
NINA_CMD_TCP_ACK = 0x2A,
|
||||||
|
|
||||||
|
// UDP commands.
|
||||||
|
NINA_CMD_UDP_SEND = 0x46,
|
||||||
|
NINA_CMD_UDP_RECV = 0x45,
|
||||||
|
NINA_CMD_UDP_ACK = 0x39,
|
||||||
|
|
||||||
|
// Pin control commands.
|
||||||
|
NINA_CMD_SET_PIN_MODE = 0x50,
|
||||||
|
NINA_CMD_SET_DIGITAL_WRITE = 0x51,
|
||||||
|
NINA_CMD_GET_DIGITAL_READ = 0x53,
|
||||||
|
NINA_CMD_SET_ANALOG_WRITE = 0x52,
|
||||||
|
NINA_CMD_GET_ANALOG_READ = 0x54,
|
||||||
|
|
||||||
|
// File send/recv commands.
|
||||||
|
NINA_CMD_CMD_WRITE_FILE = 0x60,
|
||||||
|
NINA_CMD_CMD_READ_FILE = 0x61,
|
||||||
|
NINA_CMD_CMD_DELETE_FILE = 0x62,
|
||||||
|
NINA_CMD_CMD_EXISTS_FILE = 0x63,
|
||||||
|
NINA_CMD_CMD_DOWNLOAD_FILE = 0x64,
|
||||||
|
|
||||||
|
// OTA upgrade commands.
|
||||||
|
NINA_CMD_CMD_APPLY_OTA = 0x65,
|
||||||
|
NINA_CMD_CMD_RENAME_FILE = 0x66,
|
||||||
|
NINA_CMD_CMD_DOWNLOAD_OTA = 0x67,
|
||||||
|
} nina_cmd_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NINA_STATUS_IDLE = 0,
|
||||||
|
NINA_STATUS_NO_SSID_AVAIL,
|
||||||
|
NINA_STATUS_SCAN_COMPLETED,
|
||||||
|
NINA_STATUS_CONNECTED,
|
||||||
|
NINA_STATUS_CONNECT_FAILED,
|
||||||
|
NINA_STATUS_CONNECTION_LOST,
|
||||||
|
NINA_STATUS_DISCONNECTED,
|
||||||
|
NINA_STATUS_AP_LISTENING,
|
||||||
|
NINA_STATUS_AP_CONNECTED,
|
||||||
|
NINA_STATUS_AP_FAILED
|
||||||
|
} nina_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SOCKET_STATE_CLOSED = 0,
|
||||||
|
SOCKET_STATE_LISTEN,
|
||||||
|
SOCKET_STATE_SYN_SENT,
|
||||||
|
SOCKET_STATE_SYN_RCVD,
|
||||||
|
SOCKET_STATE_ESTABLISHED,
|
||||||
|
SOCKET_STATE_FIN_WAIT_1,
|
||||||
|
SOCKET_STATE_FIN_WAIT_2,
|
||||||
|
SOCKET_STATE_CLOSE_WAIT,
|
||||||
|
SOCKET_STATE_CLOSING,
|
||||||
|
SOCKET_STATE_LAST_ACK,
|
||||||
|
SOCKET_STATE_TIME_WAIT
|
||||||
|
} nina_sock_state_t;
|
||||||
|
|
||||||
|
static uint8_t nina_bsp_spi_read_byte(void) {
|
||||||
|
uint8_t byte = 0;
|
||||||
|
nina_bsp_spi_transfer(NULL, &byte, 1);
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_wait_for_cmd(uint8_t cmd, uint32_t timeout) {
|
||||||
|
uint8_t buf = 0;
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
|
||||||
|
buf = nina_bsp_spi_read_byte();
|
||||||
|
if (buf == CMD_ERROR || buf == cmd
|
||||||
|
|| ((mp_hal_ticks_ms() - start) >= timeout)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mp_hal_delay_ms(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (buf == cmd) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_send_command(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
|
||||||
|
int ret = -1;
|
||||||
|
uint32_t length = 4; // 3 bytes header + 1 end byte
|
||||||
|
|
||||||
|
debug_printf("nina_send_command (cmd 0x%x nargs %d width %d): ", cmd, nargs, width);
|
||||||
|
|
||||||
|
if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send command header.
|
||||||
|
uint8_t cmdbuf_hdr[3] = {CMD_START, cmd, nargs};
|
||||||
|
if (nina_bsp_spi_transfer(cmdbuf_hdr, NULL, sizeof(cmdbuf_hdr)) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send command arg(s).
|
||||||
|
for (uint32_t i = 0; i < nargs; i++) {
|
||||||
|
// Send size MSB first if 2 bytes.
|
||||||
|
uint16_t size = (width == ARG_8BITS) ? args[i].size : __REVSH(args[i].size);
|
||||||
|
|
||||||
|
// Send arg length.
|
||||||
|
if (nina_bsp_spi_transfer((uint8_t *)&size, NULL, width) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send arg value.
|
||||||
|
if (nina_bsp_spi_transfer(args[i].data, NULL, args[i].size) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
length += args[i].size + width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send END byte + padding to multiple of 4.
|
||||||
|
uint8_t cmdbuf_end[4] = {CMD_END, 0xFF, 0xFF, 0xFF};
|
||||||
|
if (nina_bsp_spi_transfer(cmdbuf_end, NULL, 1 + (length % 4)) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All good
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
debug_printf("\n");
|
||||||
|
nina_bsp_spi_slave_deselect();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_read_response(uint32_t cmd, uint32_t nvals, uint32_t width, nina_vals_t *vals) {
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
debug_printf("nina_read_response(cmd 0x%x nvals %d width %d): ", cmd, nvals, width);
|
||||||
|
|
||||||
|
// Read reply
|
||||||
|
if (nina_bsp_spi_slave_select(NINA_SSELECT_TIMEOUT) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for CMD_START
|
||||||
|
if (nina_wait_for_cmd(CMD_START, NINA_RESPONSE_TIMEOUT) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should return CMD + REPLY flag.
|
||||||
|
if (nina_bsp_spi_read_byte() != (cmd | CMD_REPLY)) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check the number of returned values.
|
||||||
|
// NOTE: This is to handle the special case for the scan command.
|
||||||
|
uint32_t rvals = nina_bsp_spi_read_byte();
|
||||||
|
if (nvals > rvals) {
|
||||||
|
nvals = rvals;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read return value(s).
|
||||||
|
for (uint32_t i = 0; i < nvals; i++) {
|
||||||
|
// Read return value size.
|
||||||
|
uint16_t bytes = nina_bsp_spi_read_byte();
|
||||||
|
if (width == ARG_16BITS) {
|
||||||
|
bytes = (bytes << 8) | nina_bsp_spi_read_byte();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the val fits the buffer.
|
||||||
|
if (*(vals[i].size) < bytes) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the returned value.
|
||||||
|
if (nina_bsp_spi_transfer(NULL, vals[i].data, bytes) != 0) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the size.
|
||||||
|
*(vals[i].size) = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_bsp_spi_read_byte() != CMD_END) {
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All good
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
debug_printf("\n");
|
||||||
|
nina_bsp_spi_slave_deselect();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_send_command_read_ack(uint32_t cmd, uint32_t nargs, uint32_t width, nina_args_t *args) {
|
||||||
|
uint16_t size = 1;
|
||||||
|
uint8_t rval = SPI_ERR;
|
||||||
|
if (nina_send_command(cmd, nargs, width, args) != 0 ||
|
||||||
|
nina_read_response(cmd, 1, ARG_8BITS, NINA_VALS({&size, &rval})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_send_command_read_vals(uint32_t cmd, uint32_t nargs,
|
||||||
|
uint32_t argsw, nina_args_t *args, uint32_t nvals, uint32_t valsw, nina_vals_t *vals) {
|
||||||
|
|
||||||
|
if (nina_send_command(cmd, nargs, argsw, args) != 0 ||
|
||||||
|
nina_read_response(cmd, nvals, valsw, vals) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nina_fix_mac_addr(uint8_t *mac) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
uint8_t b = mac[i];
|
||||||
|
mac[i] = mac[5 - i];
|
||||||
|
mac[5 - i] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_init(void) {
|
||||||
|
// Initialize the BSP.
|
||||||
|
nina_bsp_init();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_deinit(void) {
|
||||||
|
return nina_bsp_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_connection_status() {
|
||||||
|
return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_socket_status(uint8_t fd) {
|
||||||
|
return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nina_server_socket_status(uint8_t fd) {
|
||||||
|
return nina_send_command_read_ack(NINA_CMD_SOCKET_STATE & 0xF9,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
|
||||||
|
uint8_t status = NINA_STATUS_CONNECT_FAILED;
|
||||||
|
|
||||||
|
if (key == NULL && security != NINA_SEC_OPEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (security) {
|
||||||
|
case NINA_SEC_OPEN:
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_CONNECT_OPEN,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_STR(ssid))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NINA_SEC_WEP:
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_CONNECT_WEP,
|
||||||
|
2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NINA_SEC_WPA_PSK:
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_CONNECT_WPA,
|
||||||
|
3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(0), ARG_STR(key))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
|
||||||
|
status = nina_connection_status();
|
||||||
|
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (status == NINA_STATUS_CONNECTED) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
|
||||||
|
uint8_t status = NINA_STATUS_AP_FAILED;
|
||||||
|
|
||||||
|
if ((key == NULL && security != NINA_SEC_OPEN) ||
|
||||||
|
(security != NINA_SEC_OPEN && security != NINA_SEC_WEP)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (security) {
|
||||||
|
case NINA_SEC_OPEN:
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_START_AP_OPEN,
|
||||||
|
2, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_BYTE(channel))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NINA_SEC_WEP:
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_START_AP_WEP,
|
||||||
|
3, ARG_8BITS, NINA_ARGS(ARG_STR(ssid), ARG_STR(key), ARG_BYTE(channel))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
|
||||||
|
status = nina_connection_status();
|
||||||
|
if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (status == NINA_STATUS_AP_LISTENING) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_disconnect(void) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_DISCONNECT,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_isconnected(void) {
|
||||||
|
int status = nina_connection_status();
|
||||||
|
if (status == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return status == NINA_STATUS_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_connected_sta(uint32_t *sta_ip) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set) {
|
||||||
|
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
uint16_t sub_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
uint16_t gw_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
uint16_t dns_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
|
||||||
|
if (set) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SET_IF_CONFIG,
|
||||||
|
4, ARG_8BITS,
|
||||||
|
NINA_ARGS(
|
||||||
|
ARG_BYTE(3), // Valid number of args.
|
||||||
|
{ip_len, ifconfig->ip_addr},
|
||||||
|
{gw_len, ifconfig->gateway_addr},
|
||||||
|
{sub_len, ifconfig->subnet_addr})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t dns2[4] = {8, 8, 8, 8};
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SET_DNS_CONFIG,
|
||||||
|
3, ARG_8BITS,
|
||||||
|
NINA_ARGS(
|
||||||
|
ARG_BYTE(1), // Valid number of args.
|
||||||
|
{dns_len, ifconfig->dns_addr},
|
||||||
|
{dns_len, dns2})) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_IF_CONFIG,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
3, ARG_8BITS,
|
||||||
|
NINA_VALS(
|
||||||
|
{&ip_len, ifconfig->ip_addr},
|
||||||
|
{&sub_len, ifconfig->subnet_addr},
|
||||||
|
{&gw_len, ifconfig->gateway_addr})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// No command to get DNS ?
|
||||||
|
memcpy(ifconfig->dns_addr, ifconfig->gateway_addr, NINA_IPV4_ADDR_LEN);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_netinfo(nina_netinfo_t *netinfo) {
|
||||||
|
uint16_t rssi_len = 4;
|
||||||
|
uint16_t sec_len = 1;
|
||||||
|
uint16_t ssid_len = NINA_MAX_SSID_LEN;
|
||||||
|
uint16_t bssid_len = NINA_MAC_ADDR_LEN;
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&rssi_len, &netinfo->rssi})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_ENCRYPT,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&sec_len, &netinfo->security})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_SSID,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&ssid_len, &netinfo->ssid})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Null terminate SSID.
|
||||||
|
netinfo->ssid[MIN((NINA_MAX_SSID_LEN - 1), ssid_len)] = 0;
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_BSSID,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&bssid_len, &netinfo->bssid})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The MAC address is read in reverse from the firmware.
|
||||||
|
nina_fix_mac_addr(netinfo->bssid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout) {
|
||||||
|
uint16_t sizes[NINA_MAX_NETWORK_LIST];
|
||||||
|
char ssids[NINA_MAX_NETWORK_LIST][NINA_MAX_SSID_LEN];
|
||||||
|
nina_vals_t vals[NINA_MAX_NETWORK_LIST];
|
||||||
|
|
||||||
|
// Initialize the values list.
|
||||||
|
for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
|
||||||
|
sizes[i] = NINA_MAX_SSID_LEN - 1;
|
||||||
|
memset(ssids[i], 0, NINA_MAX_SSID_LEN);
|
||||||
|
vals[i].size = &sizes[i];
|
||||||
|
vals[i].data = ssids[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_AP_START_SCAN,
|
||||||
|
0, ARG_8BITS, NULL) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_AP_SCAN_RESULT,
|
||||||
|
0, ARG_8BITS, NULL,
|
||||||
|
NINA_MAX_NETWORK_LIST, ARG_8BITS, vals) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssids[0][0] != 0) {
|
||||||
|
// Found at least 1 network.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
// Timeout, no networks.
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_hal_delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < NINA_MAX_NETWORK_LIST; i++) {
|
||||||
|
uint16_t rssi_len = 4;
|
||||||
|
uint16_t sec_len = 1;
|
||||||
|
uint16_t chan_len = 1;
|
||||||
|
uint16_t bssid_len = NINA_MAC_ADDR_LEN;
|
||||||
|
nina_scan_result_t scan_result;
|
||||||
|
|
||||||
|
if (ssids[i][0] == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set AP SSID
|
||||||
|
strncpy(scan_result.ssid, ssids[i], NINA_MAX_SSID_LEN);
|
||||||
|
|
||||||
|
// Read AP RSSI
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_AP_GET_RSSI,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&rssi_len, &scan_result.rssi})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read AP encryption type
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_AP_GET_ENCRYPT,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&sec_len, &scan_result.security})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read AP channel
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_AP_GET_CHANNEL,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&chan_len, &scan_result.channel})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read AP bssid
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_AP_GET_BSSID,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(i)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&bssid_len, scan_result.bssid})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The MAC address is read in reverse from the firmware.
|
||||||
|
nina_fix_mac_addr(scan_result.bssid);
|
||||||
|
|
||||||
|
scan_callback(&scan_result, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_get_rssi(void) {
|
||||||
|
uint16_t size = 4;
|
||||||
|
int32_t rssi = 0;
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_RSSI,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(0xFF)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, &rssi})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_fw_version(uint8_t *fw_ver) {
|
||||||
|
uint16_t size = NINA_FW_VER_LEN;
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_FW_VERSION,
|
||||||
|
0, ARG_8BITS, NULL,
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, fw_ver})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_set_hostname(const char *hostname) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SET_HOSTNAME,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_STR(hostname))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_gethostbyname(const char *name, uint8_t *out_ip) {
|
||||||
|
uint16_t size = 4;
|
||||||
|
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_HOST_BY_NAME,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_STR(name))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_GET_HOST_BY_NAME,
|
||||||
|
0, ARG_8BITS, NULL,
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, out_ip})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_socket(uint8_t type) {
|
||||||
|
uint16_t size = 1;
|
||||||
|
uint8_t sock = 0;
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_SOCKET_OPEN,
|
||||||
|
0, ARG_8BITS, NULL,
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_close(int fd) {
|
||||||
|
if (fd > 0 && fd < 255) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CLOSE,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
|
||||||
|
if (nina_socket_status(fd) == SOCKET_STATE_CLOSED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((mp_hal_ticks_ms() - start) >= 5000) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SOCKET_BIND,
|
||||||
|
3, ARG_8BITS,
|
||||||
|
NINA_ARGS(
|
||||||
|
ARG_SHORT(__REVSH(port)),
|
||||||
|
ARG_BYTE(fd),
|
||||||
|
ARG_BYTE(type))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only TCP sockets' states should be checked.
|
||||||
|
if (type == NINA_SOCKET_TYPE_TCP &&
|
||||||
|
nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_listen(int fd, uint32_t backlog) {
|
||||||
|
return 0; // No listen ?
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout) {
|
||||||
|
uint16_t size = 2;
|
||||||
|
uint16_t sock = NO_SOCKET_AVAIL;
|
||||||
|
|
||||||
|
if (nina_server_socket_status(fd) != SOCKET_STATE_LISTEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); sock == 0 || sock == NO_SOCKET_AVAIL; mp_hal_delay_ms(10)) {
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_SOCKET_ACCEPT,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, &sock})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t port_len = 2;
|
||||||
|
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(sock)),
|
||||||
|
2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*fd_out = sock;
|
||||||
|
*port = __REVSH(*port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout) {
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
|
||||||
|
4, ARG_8BITS,
|
||||||
|
NINA_ARGS(
|
||||||
|
ARG_WORD((*(uint32_t *)ip)),
|
||||||
|
ARG_SHORT(__REVSH(port)),
|
||||||
|
ARG_BYTE(fd),
|
||||||
|
ARG_BYTE(NINA_SOCKET_TYPE_TCP))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
|
||||||
|
int state = nina_socket_status(fd);
|
||||||
|
if (state == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == SOCKET_STATE_ESTABLISHED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout) {
|
||||||
|
uint16_t size = 2;
|
||||||
|
uint16_t bytes = 0;
|
||||||
|
|
||||||
|
if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_TCP_SEND,
|
||||||
|
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf}),
|
||||||
|
1, ARG_8BITS, NINA_VALS({&size, &bytes})) != 0 || bytes <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); ;) {
|
||||||
|
int resp = nina_send_command_read_ack(NINA_CMD_TCP_ACK,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)));
|
||||||
|
|
||||||
|
if (resp == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp == SPI_ACK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
mp_hal_delay_ms(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout) {
|
||||||
|
uint16_t bytes = 0;
|
||||||
|
|
||||||
|
if (nina_socket_status(fd) != SOCKET_STATE_ESTABLISHED) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
|
||||||
|
bytes = len;
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_TCP_RECV,
|
||||||
|
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
|
||||||
|
1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check from the upper layer if the socket is bound, if not then auto-bind it first.
|
||||||
|
int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout) {
|
||||||
|
// TODO do we need to split the packet somewhere?
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_SOCKET_CONNECT,
|
||||||
|
4, ARG_8BITS,
|
||||||
|
NINA_ARGS(
|
||||||
|
ARG_WORD((*(uint32_t *)ip)),
|
||||||
|
ARG_SHORT(__REVSH(port)),
|
||||||
|
ARG_BYTE(fd),
|
||||||
|
ARG_BYTE(NINA_SOCKET_TYPE_UDP))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer length and socket number are passed as 16bits.
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_UDP_SEND,
|
||||||
|
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), {len, buf})) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nina_send_command_read_ack(NINA_CMD_UDP_ACK,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd))) != SPI_ACK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check from the upper layer if the socket is bound, if not then auto-bind it first.
|
||||||
|
int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout) {
|
||||||
|
uint16_t bytes = 0;
|
||||||
|
uint16_t port_len = 2;
|
||||||
|
uint16_t ip_len = NINA_IPV4_ADDR_LEN;
|
||||||
|
|
||||||
|
for (mp_uint_t start = mp_hal_ticks_ms(); bytes == 0; mp_hal_delay_ms(1)) {
|
||||||
|
bytes = len;
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_UDP_RECV,
|
||||||
|
2, ARG_16BITS, NINA_ARGS(ARG_BYTE(fd), ARG_SHORT(bytes)),
|
||||||
|
1, ARG_16BITS, NINA_VALS({&bytes, buf})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout && (mp_hal_ticks_ms() - start) >= timeout) {
|
||||||
|
return NINA_ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nina_send_command_read_vals(NINA_CMD_SOCKET_REMOTE_ADDR,
|
||||||
|
1, ARG_8BITS, NINA_ARGS(ARG_BYTE(fd)),
|
||||||
|
2, ARG_8BITS, NINA_VALS({&ip_len, ip}, {&port_len, port})) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_NINAW10
|
||||||
120
drivers/ninaw10/nina_wifi_drv.h
Normal file
120
drivers/ninaw10/nina_wifi_drv.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project, https://openmv.io.
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
* Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 WiFi driver.
|
||||||
|
*/
|
||||||
|
#ifndef MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
|
||||||
|
#define MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
|
||||||
|
|
||||||
|
#define NINA_FW_VER_LEN (6)
|
||||||
|
#define NINA_IPV4_ADDR_LEN (4)
|
||||||
|
#define NINA_MAC_ADDR_LEN (6)
|
||||||
|
#define NINA_MAX_SSID_LEN (32)
|
||||||
|
#define NINA_MAX_WEP_LEN (13)
|
||||||
|
#define NINA_MAX_WPA_LEN (63)
|
||||||
|
#define NINA_MAX_NETWORK_LIST (10)
|
||||||
|
#define NINA_MAX_SOCKET (10)
|
||||||
|
|
||||||
|
#define NINA_FW_VER_MAJOR (1)
|
||||||
|
#define NINA_FW_VER_MINOR (4)
|
||||||
|
#define NINA_FW_VER_PATCH (8)
|
||||||
|
|
||||||
|
#define NINA_FW_VER_MAJOR_OFFS (0)
|
||||||
|
#define NINA_FW_VER_MINOR_OFFS (2)
|
||||||
|
#define NINA_FW_VER_PATCH_OFFS (4)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NINA_SEC_INVALID = 0,
|
||||||
|
NINA_SEC_OPEN,
|
||||||
|
NINA_SEC_WPA_PSK,
|
||||||
|
NINA_SEC_WEP
|
||||||
|
} nina_security_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NINA_SOCKET_TYPE_TCP = 0,
|
||||||
|
NINA_SOCKET_TYPE_UDP,
|
||||||
|
NINA_SOCKET_TYPE_TLS,
|
||||||
|
NINA_SOCKET_TYPE_UDP_MULTICAST,
|
||||||
|
NINA_SOCKET_TYPE_TLS_BEARSSL
|
||||||
|
} nina_socket_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NINA_ERROR_IO = -1,
|
||||||
|
NINA_ERROR_TIMEOUT = -2,
|
||||||
|
} nina_error_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t ip_addr[NINA_IPV4_ADDR_LEN];
|
||||||
|
uint8_t subnet_addr[NINA_IPV4_ADDR_LEN];
|
||||||
|
uint8_t gateway_addr[NINA_IPV4_ADDR_LEN];
|
||||||
|
uint8_t dns_addr[NINA_IPV4_ADDR_LEN];
|
||||||
|
} nina_ifconfig_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t rssi;
|
||||||
|
uint8_t security;
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t bssid[NINA_MAC_ADDR_LEN];
|
||||||
|
char ssid[NINA_MAX_SSID_LEN];
|
||||||
|
} nina_scan_result_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t rssi;
|
||||||
|
uint8_t security;
|
||||||
|
char ssid[NINA_MAX_SSID_LEN];
|
||||||
|
uint8_t bssid[NINA_MAC_ADDR_LEN];
|
||||||
|
} nina_netinfo_t;
|
||||||
|
|
||||||
|
typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *);
|
||||||
|
|
||||||
|
int nina_init(void);
|
||||||
|
int nina_deinit(void);
|
||||||
|
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel);
|
||||||
|
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel);
|
||||||
|
int nina_disconnect(void);
|
||||||
|
int nina_isconnected(void);
|
||||||
|
int nina_connected_sta(uint32_t *sta_ip);
|
||||||
|
int nina_wait_for_sta(uint32_t *sta_ip, uint32_t timeout);
|
||||||
|
int nina_ifconfig(nina_ifconfig_t *ifconfig, bool set);
|
||||||
|
int nina_netinfo(nina_netinfo_t *netinfo);
|
||||||
|
int nina_scan(nina_scan_callback_t scan_callback, void *arg, uint32_t timeout);
|
||||||
|
int nina_get_rssi(void);
|
||||||
|
int nina_fw_version(uint8_t *fw_ver);
|
||||||
|
int nina_set_hostname(const char *name);
|
||||||
|
int nina_gethostbyname(const char *name, uint8_t *out_ip);
|
||||||
|
int nina_socket_socket(uint8_t type);
|
||||||
|
int nina_socket_close(int fd);
|
||||||
|
int nina_socket_bind(int fd, uint8_t *ip, uint16_t port, int type);
|
||||||
|
int nina_socket_listen(int fd, uint32_t backlog);
|
||||||
|
int nina_socket_accept(int fd, uint8_t *ip, uint16_t *port, int *fd_out, uint32_t timeout);
|
||||||
|
int nina_socket_connect(int fd, uint8_t *ip, uint16_t port, uint32_t timeout);
|
||||||
|
int nina_socket_send(int fd, const uint8_t *buf, uint32_t len, uint32_t timeout);
|
||||||
|
int nina_socket_recv(int fd, uint8_t *buf, uint32_t len, uint32_t timeout);
|
||||||
|
int nina_socket_sendto(int fd, const uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t port, uint32_t timeout);
|
||||||
|
int nina_socket_recvfrom(int fd, uint8_t *buf, uint32_t len, uint8_t *ip, uint16_t *port, uint32_t timeout);
|
||||||
|
int nina_socket_setsockopt(int fd, uint32_t level, uint32_t opt, const void *optval, uint32_t optlen);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_DRIVERS_NINAW10_NINA_WIFI_DRV_H
|
||||||
@ -45,7 +45,6 @@
|
|||||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||||
#define MICROPY_STREAMS_NON_BLOCK (0)
|
#define MICROPY_STREAMS_NON_BLOCK (0)
|
||||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
|
||||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
|
#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
|
||||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
||||||
#define MICROPY_CPYTHON_COMPAT (0)
|
#define MICROPY_CPYTHON_COMPAT (0)
|
||||||
|
|||||||
@ -1265,13 +1265,13 @@ int mp_bluetooth_gap_scan_stop(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
|
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) {
|
||||||
DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
|
DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
|
||||||
|
|
||||||
uint16_t conn_scan_interval = 60000 / 625;
|
uint16_t conn_scan_interval = 60000 / 625;
|
||||||
uint16_t conn_scan_window = 30000 / 625;
|
uint16_t conn_scan_window = 30000 / 625;
|
||||||
uint16_t conn_interval_min = 10000 / 1250;
|
uint16_t conn_interval_min = (min_conn_interval_us ? min_conn_interval_us : 10000) / 1250;
|
||||||
uint16_t conn_interval_max = 30000 / 1250;
|
uint16_t conn_interval_max = (max_conn_interval_us ? max_conn_interval_us : 30000) / 1250;
|
||||||
uint16_t conn_latency = 4;
|
uint16_t conn_latency = 4;
|
||||||
uint16_t supervision_timeout = duration_ms / 10; // default = 720
|
uint16_t supervision_timeout = duration_ms / 10; // default = 720
|
||||||
uint16_t min_ce_length = 10000 / 625;
|
uint16_t min_ce_length = 10000 / 625;
|
||||||
@ -1284,6 +1284,11 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
|
|||||||
return btstack_error_to_errno(gap_connect(btstack_addr, addr_type));
|
return btstack_error_to_errno(gap_connect(btstack_addr, addr_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mp_bluetooth_gap_peripheral_connect_cancel(void) {
|
||||||
|
DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n");
|
||||||
|
return btstack_error_to_errno(gap_connect_cancel());
|
||||||
|
}
|
||||||
|
|
||||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
||||||
|
|||||||
@ -10,11 +10,13 @@ set(MICROPY_SOURCE_EXTMOD
|
|||||||
${MICROPY_EXTMOD_DIR}/machine_i2c.c
|
${MICROPY_EXTMOD_DIR}/machine_i2c.c
|
||||||
${MICROPY_EXTMOD_DIR}/machine_mem.c
|
${MICROPY_EXTMOD_DIR}/machine_mem.c
|
||||||
${MICROPY_EXTMOD_DIR}/machine_pulse.c
|
${MICROPY_EXTMOD_DIR}/machine_pulse.c
|
||||||
|
${MICROPY_EXTMOD_DIR}/machine_pwm.c
|
||||||
${MICROPY_EXTMOD_DIR}/machine_signal.c
|
${MICROPY_EXTMOD_DIR}/machine_signal.c
|
||||||
${MICROPY_EXTMOD_DIR}/machine_spi.c
|
${MICROPY_EXTMOD_DIR}/machine_spi.c
|
||||||
${MICROPY_EXTMOD_DIR}/modbluetooth.c
|
${MICROPY_EXTMOD_DIR}/modbluetooth.c
|
||||||
${MICROPY_EXTMOD_DIR}/modbtree.c
|
${MICROPY_EXTMOD_DIR}/modbtree.c
|
||||||
${MICROPY_EXTMOD_DIR}/modframebuf.c
|
${MICROPY_EXTMOD_DIR}/modframebuf.c
|
||||||
|
${MICROPY_EXTMOD_DIR}/modnetwork.c
|
||||||
${MICROPY_EXTMOD_DIR}/modonewire.c
|
${MICROPY_EXTMOD_DIR}/modonewire.c
|
||||||
${MICROPY_EXTMOD_DIR}/moduasyncio.c
|
${MICROPY_EXTMOD_DIR}/moduasyncio.c
|
||||||
${MICROPY_EXTMOD_DIR}/modubinascii.c
|
${MICROPY_EXTMOD_DIR}/modubinascii.c
|
||||||
@ -23,9 +25,11 @@ set(MICROPY_SOURCE_EXTMOD
|
|||||||
${MICROPY_EXTMOD_DIR}/moduhashlib.c
|
${MICROPY_EXTMOD_DIR}/moduhashlib.c
|
||||||
${MICROPY_EXTMOD_DIR}/moduheapq.c
|
${MICROPY_EXTMOD_DIR}/moduheapq.c
|
||||||
${MICROPY_EXTMOD_DIR}/modujson.c
|
${MICROPY_EXTMOD_DIR}/modujson.c
|
||||||
|
${MICROPY_EXTMOD_DIR}/moduplatform.c
|
||||||
${MICROPY_EXTMOD_DIR}/modurandom.c
|
${MICROPY_EXTMOD_DIR}/modurandom.c
|
||||||
${MICROPY_EXTMOD_DIR}/modure.c
|
${MICROPY_EXTMOD_DIR}/modure.c
|
||||||
${MICROPY_EXTMOD_DIR}/moduselect.c
|
${MICROPY_EXTMOD_DIR}/moduselect.c
|
||||||
|
${MICROPY_EXTMOD_DIR}/modusocket.c
|
||||||
${MICROPY_EXTMOD_DIR}/modussl_axtls.c
|
${MICROPY_EXTMOD_DIR}/modussl_axtls.c
|
||||||
${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
|
${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
|
||||||
${MICROPY_EXTMOD_DIR}/modutimeq.c
|
${MICROPY_EXTMOD_DIR}/modutimeq.c
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "extmod/machine_i2c.h"
|
#include "extmod/machine_i2c.h"
|
||||||
|
|
||||||
#if MICROPY_PY_MACHINE_I2C
|
#if MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t;
|
typedef mp_machine_soft_i2c_obj_t machine_i2c_obj_t;
|
||||||
|
|
||||||
@ -240,9 +240,13 @@ int mp_machine_soft_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n
|
|||||||
return transfer_ret;
|
return transfer_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// Generic helper functions
|
// Generic helper functions
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
// For use by ports that require a single buffer of data for a read/write transfer
|
// For use by ports that require a single buffer of data for a read/write transfer
|
||||||
int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
|
int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags) {
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -628,9 +632,13 @@ STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = {
|
|||||||
};
|
};
|
||||||
MP_DEFINE_CONST_DICT(mp_machine_i2c_locals_dict, machine_i2c_locals_dict_table);
|
MP_DEFINE_CONST_DICT(mp_machine_i2c_locals_dict, machine_i2c_locals_dict_table);
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_MACHINE_I2C || MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// Implementation of soft I2C
|
// Implementation of soft I2C
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|
||||||
STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void mp_machine_soft_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_machine_soft_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)",
|
mp_printf(print, "SoftI2C(scl=" MP_HAL_PIN_FMT ", sda=" MP_HAL_PIN_FMT ", freq=%u)",
|
||||||
@ -711,4 +719,4 @@ const mp_obj_type_t mp_machine_soft_i2c_type = {
|
|||||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
.locals_dict = (mp_obj_dict_t *)&mp_machine_i2c_locals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MICROPY_PY_MACHINE_I2C
|
#endif // MICROPY_PY_MACHINE_SOFTI2C
|
||||||
|
|||||||
143
extmod/machine_pwm.c
Normal file
143
extmod/machine_pwm.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-2021 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_PWM
|
||||||
|
|
||||||
|
#include "extmod/machine_pwm.h"
|
||||||
|
|
||||||
|
#ifdef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||||
|
#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_INIT
|
||||||
|
STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
|
mp_machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// PWM.deinit()
|
||||||
|
STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) {
|
||||||
|
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
mp_machine_pwm_deinit(self);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit);
|
||||||
|
|
||||||
|
// PWM.freq([value])
|
||||||
|
STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *args) {
|
||||||
|
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
if (n_args == 1) {
|
||||||
|
// Get frequency.
|
||||||
|
return mp_machine_pwm_freq_get(self);
|
||||||
|
} else {
|
||||||
|
// Set the frequency.
|
||||||
|
mp_int_t freq = mp_obj_get_int(args[1]);
|
||||||
|
mp_machine_pwm_freq_set(self, freq);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_freq_obj, 1, 2, machine_pwm_freq);
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_DUTY
|
||||||
|
// PWM.duty([duty])
|
||||||
|
STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) {
|
||||||
|
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
if (n_args == 1) {
|
||||||
|
// Get duty cycle.
|
||||||
|
return mp_machine_pwm_duty_get(self);
|
||||||
|
} else {
|
||||||
|
// Set duty cycle.
|
||||||
|
mp_int_t duty = mp_obj_get_int(args[1]);
|
||||||
|
mp_machine_pwm_duty_set(self, duty);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_obj, 1, 2, machine_pwm_duty);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
|
||||||
|
|
||||||
|
// PWM.duty_u16([value])
|
||||||
|
STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) {
|
||||||
|
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
if (n_args == 1) {
|
||||||
|
// Get duty cycle.
|
||||||
|
return mp_machine_pwm_duty_get_u16(self);
|
||||||
|
} else {
|
||||||
|
// Set duty cycle.
|
||||||
|
mp_int_t duty_u16 = mp_obj_get_int(args[1]);
|
||||||
|
mp_machine_pwm_duty_set_u16(self, duty_u16);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_u16_obj, 1, 2, machine_pwm_duty_u16);
|
||||||
|
|
||||||
|
// PWM.duty_ns([value])
|
||||||
|
STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) {
|
||||||
|
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
if (n_args == 1) {
|
||||||
|
// Get duty cycle.
|
||||||
|
return mp_machine_pwm_duty_get_ns(self);
|
||||||
|
} else {
|
||||||
|
// Set duty cycle.
|
||||||
|
mp_int_t duty_ns = mp_obj_get_int(args[1]);
|
||||||
|
mp_machine_pwm_duty_set_ns(self, duty_ns);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_INIT
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) },
|
||||||
|
#endif
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) },
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_DUTY
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&machine_pwm_duty_obj) },
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table);
|
||||||
|
|
||||||
|
const mp_obj_type_t machine_pwm_type = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_PWM,
|
||||||
|
.print = mp_machine_pwm_print,
|
||||||
|
.make_new = mp_machine_pwm_make_new,
|
||||||
|
.locals_dict = (mp_obj_dict_t *)&machine_pwm_locals_dict,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_MACHINE_PWM
|
||||||
55
extmod/machine_pwm.h
Normal file
55
extmod/machine_pwm.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Damien P. George
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
||||||
|
#define MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
||||||
|
|
||||||
|
#include "py/obj.h"
|
||||||
|
|
||||||
|
// A port must provide this type, but it's otherwise opaque.
|
||||||
|
typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
|
||||||
|
|
||||||
|
// This PWM class is implemented by machine_pwm.c.
|
||||||
|
extern const mp_obj_type_t machine_pwm_type;
|
||||||
|
|
||||||
|
// A port must provide implementations of these low-level PWM functions, either as global
|
||||||
|
// linker symbols, or included directly if MICROPY_PY_MACHINE_PWM_INCLUDEFILE is defined.
|
||||||
|
#ifndef MICROPY_PY_MACHINE_PWM_INCLUDEFILE
|
||||||
|
void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||||
|
mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||||
|
void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||||
|
void mp_machine_pwm_deinit(machine_pwm_obj_t *self);
|
||||||
|
mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self);
|
||||||
|
void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq);
|
||||||
|
mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self);
|
||||||
|
void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty);
|
||||||
|
mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self);
|
||||||
|
void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty_u16);
|
||||||
|
mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self);
|
||||||
|
void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty_ns);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_PWM_H
|
||||||
@ -30,8 +30,6 @@
|
|||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "extmod/machine_spi.h"
|
#include "extmod/machine_spi.h"
|
||||||
|
|
||||||
#if MICROPY_PY_MACHINE_SPI
|
|
||||||
|
|
||||||
// if a port didn't define MSB/LSB constants then provide them
|
// if a port didn't define MSB/LSB constants then provide them
|
||||||
#ifndef MICROPY_PY_MACHINE_SPI_MSB
|
#ifndef MICROPY_PY_MACHINE_SPI_MSB
|
||||||
#define MICROPY_PY_MACHINE_SPI_MSB (0)
|
#define MICROPY_PY_MACHINE_SPI_MSB (0)
|
||||||
@ -41,6 +39,8 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// MicroPython bindings for generic machine.SPI
|
// MicroPython bindings for generic machine.SPI
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|
||||||
STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
|
||||||
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)s->type->protocol;
|
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)s->type->protocol;
|
||||||
@ -115,12 +115,15 @@ STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) },
|
{ MP_ROM_QSTR(MP_QSTR_MSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_MSB) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) },
|
{ MP_ROM_QSTR(MP_QSTR_LSB), MP_ROM_INT(MICROPY_PY_MACHINE_SPI_LSB) },
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
|
MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// Implementation of soft SPI
|
// Implementation of soft SPI
|
||||||
|
|
||||||
|
#if MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|
||||||
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
|
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
|
||||||
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
#ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
|
||||||
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
|
if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
|
||||||
@ -258,4 +261,4 @@ const mp_obj_type_t mp_machine_soft_spi_type = {
|
|||||||
.locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
|
.locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MICROPY_PY_MACHINE_SPI
|
#endif // MICROPY_PY_MACHINE_SOFTSPI
|
||||||
|
|||||||
@ -215,7 +215,9 @@ STATIC mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bu
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS && MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
||||||
STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
||||||
assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1);
|
assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1);
|
||||||
ringbuf_put(ringbuf, uuid->type);
|
ringbuf_put(ringbuf, uuid->type);
|
||||||
@ -223,7 +225,9 @@ STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid)
|
|||||||
ringbuf_put(ringbuf, uuid->data[i]);
|
ringbuf_put(ringbuf, uuid->data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
||||||
assert(ringbuf_avail(ringbuf) >= 1);
|
assert(ringbuf_avail(ringbuf) >= 1);
|
||||||
uuid->type = ringbuf_get(ringbuf);
|
uuid->type = ringbuf_get(ringbuf);
|
||||||
@ -232,7 +236,9 @@ STATIC void ringbuf_get_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid)
|
|||||||
uuid->data[i] = ringbuf_get(ringbuf);
|
uuid->data[i] = ringbuf_get(ringbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#endif
|
||||||
|
|
||||||
|
#endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
||||||
|
|
||||||
const mp_obj_type_t mp_type_bluetooth_uuid = {
|
const mp_obj_type_t mp_type_bluetooth_uuid = {
|
||||||
{ &mp_type_type },
|
{ &mp_type_type },
|
||||||
@ -630,6 +636,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(bluetooth_ble_gatts_register_services_obj, blue
|
|||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
||||||
STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
|
||||||
|
if (n_args == 2) {
|
||||||
|
if (args[1] == mp_const_none) {
|
||||||
|
int err = mp_bluetooth_gap_peripheral_connect_cancel();
|
||||||
|
return bluetooth_handle_errno(err);
|
||||||
|
}
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("invalid addr"));
|
||||||
|
}
|
||||||
uint8_t addr_type = mp_obj_get_int(args[1]);
|
uint8_t addr_type = mp_obj_get_int(args[1]);
|
||||||
mp_buffer_info_t bufinfo = {0};
|
mp_buffer_info_t bufinfo = {0};
|
||||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
||||||
@ -637,14 +650,22 @@ STATIC mp_obj_t bluetooth_ble_gap_connect(size_t n_args, const mp_obj_t *args) {
|
|||||||
mp_raise_ValueError(MP_ERROR_TEXT("invalid addr"));
|
mp_raise_ValueError(MP_ERROR_TEXT("invalid addr"));
|
||||||
}
|
}
|
||||||
mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS;
|
mp_int_t scan_duration_ms = MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS;
|
||||||
if (n_args == 4) {
|
mp_int_t min_conn_interval_us = 0;
|
||||||
|
mp_int_t max_conn_interval_us = 0;
|
||||||
|
if (n_args >= 4 && args[3] != mp_const_none) {
|
||||||
scan_duration_ms = mp_obj_get_int(args[3]);
|
scan_duration_ms = mp_obj_get_int(args[3]);
|
||||||
}
|
}
|
||||||
|
if (n_args >= 5 && args[4] != mp_const_none) {
|
||||||
|
min_conn_interval_us = mp_obj_get_int(args[4]);
|
||||||
|
}
|
||||||
|
if (n_args >= 6 && args[5] != mp_const_none) {
|
||||||
|
max_conn_interval_us = mp_obj_get_int(args[5]);
|
||||||
|
}
|
||||||
|
|
||||||
int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms);
|
int err = mp_bluetooth_gap_peripheral_connect(addr_type, bufinfo.buf, scan_duration_ms, min_conn_interval_us, max_conn_interval_us);
|
||||||
return bluetooth_handle_errno(err);
|
return bluetooth_handle_errno(err);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 3, 4, bluetooth_ble_gap_connect);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_connect_obj, 2, 6, bluetooth_ble_gap_connect);
|
||||||
|
|
||||||
STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t bluetooth_ble_gap_scan(size_t n_args, const mp_obj_t *args) {
|
||||||
// Default is indefinite scan, with the NimBLE "background scan" interval and window.
|
// Default is indefinite scan, with the NimBLE "background scan" interval and window.
|
||||||
|
|||||||
@ -370,10 +370,14 @@ int mp_bluetooth_gap_scan_start(int32_t duration_ms, int32_t interval_us, int32_
|
|||||||
int mp_bluetooth_gap_scan_stop(void);
|
int mp_bluetooth_gap_scan_stop(void);
|
||||||
|
|
||||||
// Connect to a found peripheral.
|
// Connect to a found peripheral.
|
||||||
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms);
|
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us);
|
||||||
|
|
||||||
|
// Cancel in-progress connection to a peripheral.
|
||||||
|
int mp_bluetooth_gap_peripheral_connect_cancel(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
||||||
|
|
||||||
// Find all primary services on the connected peripheral.
|
// Find all primary services on the connected peripheral.
|
||||||
int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid);
|
int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_obj_bluetooth_uuid_t *uuid);
|
||||||
|
|
||||||
|
|||||||
@ -32,55 +32,16 @@
|
|||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "shared/netutils/netutils.h"
|
#include "shared/netutils/netutils.h"
|
||||||
#include "systick.h"
|
|
||||||
#include "pendsv.h"
|
|
||||||
#include "modnetwork.h"
|
#include "modnetwork.h"
|
||||||
|
|
||||||
#if MICROPY_PY_NETWORK
|
#if MICROPY_PY_NETWORK
|
||||||
|
|
||||||
#if MICROPY_PY_LWIP
|
#if MICROPY_PY_LWIP
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
#include "lwip/netif.h"
|
||||||
#include "lwip/timeouts.h"
|
#include "lwip/timeouts.h"
|
||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
#include "lwip/dhcp.h"
|
#include "lwip/dhcp.h"
|
||||||
#include "lwip/apps/mdns.h"
|
#include "lwip/apps/mdns.h"
|
||||||
#include "extmod/network_cyw43.h"
|
|
||||||
#include "drivers/cyw43/cyw43.h"
|
|
||||||
|
|
||||||
// Poll lwIP every 128ms
|
|
||||||
#define LWIP_TICK(tick) (((tick) & ~(SYSTICK_DISPATCH_NUM_SLOTS - 1) & 0x7f) == 0)
|
|
||||||
|
|
||||||
u32_t sys_now(void) {
|
|
||||||
return mp_hal_ticks_ms();
|
|
||||||
}
|
|
||||||
|
|
||||||
STATIC void pyb_lwip_poll(void) {
|
|
||||||
#if MICROPY_PY_WIZNET5K
|
|
||||||
// Poll the NIC for incoming data
|
|
||||||
wiznet5k_poll();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Run the lwIP internal updates
|
|
||||||
sys_check_timeouts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mod_network_lwip_poll_wrapper(uint32_t ticks_ms) {
|
|
||||||
if (LWIP_TICK(ticks_ms)) {
|
|
||||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, pyb_lwip_poll);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MICROPY_PY_NETWORK_CYW43
|
|
||||||
if (cyw43_poll) {
|
|
||||||
if (cyw43_sleep != 0) {
|
|
||||||
if (--cyw43_sleep == 0) {
|
|
||||||
pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \module network - network configuration
|
/// \module network - network configuration
|
||||||
@ -124,28 +85,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route);
|
|||||||
|
|
||||||
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
|
||||||
|
|
||||||
#if defined(MICROPY_HW_ETH_MDC)
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
|
|
||||||
#endif
|
|
||||||
#if MICROPY_PY_NETWORK_CYW43
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MICROPY_PY_WIZNET5K
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
|
|
||||||
#endif
|
|
||||||
#if MICROPY_PY_CC3K
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_CC3K), MP_ROM_PTR(&mod_network_nic_type_cc3k) },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
|
||||||
|
|
||||||
|
// Defined per port in mpconfigport.h
|
||||||
|
MICROPY_PORT_NETWORK_INTERFACES
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
#if MICROPY_PY_NETWORK_CYW43
|
{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(MOD_NETWORK_STA_IF) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(CYW43_ITF_STA)},
|
{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(MOD_NETWORK_AP_IF) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(CYW43_ITF_AP)},
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
|
STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
|
||||||
@ -23,8 +23,8 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#ifndef MICROPY_INCLUDED_STM32_MODNETWORK_H
|
#ifndef MICROPY_INCLUDED_MODNETWORK_H
|
||||||
#define MICROPY_INCLUDED_STM32_MODNETWORK_H
|
#define MICROPY_INCLUDED_MODNETWORK_H
|
||||||
|
|
||||||
#define MOD_NETWORK_IPADDR_BUF_SIZE (4)
|
#define MOD_NETWORK_IPADDR_BUF_SIZE (4)
|
||||||
|
|
||||||
@ -35,18 +35,13 @@
|
|||||||
#define MOD_NETWORK_SOCK_DGRAM (2)
|
#define MOD_NETWORK_SOCK_DGRAM (2)
|
||||||
#define MOD_NETWORK_SOCK_RAW (3)
|
#define MOD_NETWORK_SOCK_RAW (3)
|
||||||
|
|
||||||
|
#define MOD_NETWORK_STA_IF (0)
|
||||||
|
#define MOD_NETWORK_AP_IF (1)
|
||||||
|
|
||||||
#if MICROPY_PY_LWIP
|
#if MICROPY_PY_LWIP
|
||||||
|
|
||||||
struct netif;
|
struct netif;
|
||||||
|
|
||||||
extern const mp_obj_type_t network_lan_type;
|
|
||||||
extern const mp_obj_type_t mod_network_nic_type_wiznet5k;
|
|
||||||
|
|
||||||
void mod_network_lwip_poll_wrapper(uint32_t ticks_ms);
|
void mod_network_lwip_poll_wrapper(uint32_t ticks_ms);
|
||||||
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);
|
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);
|
||||||
|
|
||||||
void wiznet5k_poll(void);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
struct _mod_network_socket_obj_t;
|
struct _mod_network_socket_obj_t;
|
||||||
@ -77,24 +72,23 @@ typedef struct _mod_network_socket_obj_t {
|
|||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_obj_t nic;
|
mp_obj_t nic;
|
||||||
mod_network_nic_type_t *nic_type;
|
mod_network_nic_type_t *nic_type;
|
||||||
union {
|
uint32_t domain : 5;
|
||||||
struct {
|
uint32_t type : 5;
|
||||||
uint8_t domain;
|
uint32_t proto : 5;
|
||||||
uint8_t type;
|
uint32_t bound : 1;
|
||||||
int8_t fileno;
|
int32_t fileno : 16;
|
||||||
} u_param;
|
#if MICROPY_PY_USOCKET_EXTENDED_STATE
|
||||||
mp_uint_t u_state;
|
// Extended socket state for NICs/ports that need it.
|
||||||
};
|
int32_t timeout;
|
||||||
|
void *state;
|
||||||
|
#endif
|
||||||
} mod_network_socket_obj_t;
|
} mod_network_socket_obj_t;
|
||||||
|
|
||||||
extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k;
|
#endif // MICROPY_PY_LWIP
|
||||||
extern const mod_network_nic_type_t mod_network_nic_type_cc3k;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void mod_network_init(void);
|
void mod_network_init(void);
|
||||||
void mod_network_deinit(void);
|
void mod_network_deinit(void);
|
||||||
void mod_network_register_nic(mp_obj_t nic);
|
void mod_network_register_nic(mp_obj_t nic);
|
||||||
mp_obj_t mod_network_find_nic(const uint8_t *ip);
|
mp_obj_t mod_network_find_nic(const uint8_t *ip);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_STM32_MODNETWORK_H
|
#endif // MICROPY_INCLUDED_MODNETWORK_H
|
||||||
@ -30,6 +30,8 @@
|
|||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_ONEWIRE
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// Low-level 1-Wire routines
|
// Low-level 1-Wire routines
|
||||||
|
|
||||||
@ -160,3 +162,5 @@ const mp_obj_module_t mp_module_onewire = {
|
|||||||
.base = { &mp_type_module },
|
.base = { &mp_type_module },
|
||||||
.globals = (mp_obj_dict_t *)&onewire_module_globals,
|
.globals = (mp_obj_dict_t *)&onewire_module_globals,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_ONEWIRE
|
||||||
|
|||||||
146
extmod/moduplatform.c
Normal file
146
extmod/moduplatform.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "py/objtuple.h"
|
||||||
|
#include "py/objstr.h"
|
||||||
|
#include "py/mphal.h"
|
||||||
|
#include "genhdr/mpversion.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_UPLATFORM
|
||||||
|
|
||||||
|
// platform - Access to underlying platform's identifying data
|
||||||
|
|
||||||
|
// TODO: Add more architectures, compilers and libraries.
|
||||||
|
// See: https://sourceforge.net/p/predef/wiki/Home/
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH)
|
||||||
|
#define PLATFORM_ARCH "arm"
|
||||||
|
#elif defined(__x86_64__) || defined(_WIN64)
|
||||||
|
#define PLATFORM_ARCH "x86_64"
|
||||||
|
#elif defined(__i386__) || defined(_M_IX86)
|
||||||
|
#define PLATFORM_ARCH "x86"
|
||||||
|
#elif defined(__xtensa__) || defined(_M_IX86)
|
||||||
|
#define PLATFORM_ARCH "xtensa"
|
||||||
|
#else
|
||||||
|
#define PLATFORM_ARCH ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define PLATFORM_COMPILER \
|
||||||
|
"GCC " \
|
||||||
|
MP_STRINGIFY(__GNUC__) "." \
|
||||||
|
MP_STRINGIFY(__GNUC_MINOR__) "." \
|
||||||
|
MP_STRINGIFY(__GNUC_PATCHLEVEL__)
|
||||||
|
#elif defined(__ARMCC_VERSION)
|
||||||
|
#define PLATFORM_COMPILER \
|
||||||
|
"ARMCC " \
|
||||||
|
MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
|
||||||
|
MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
|
||||||
|
MP_STRINGIFY((__ARMCC_VERSION % 10000))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#if defined(_WIN64)
|
||||||
|
#define COMPILER_BITS "64 bit"
|
||||||
|
#elif defined(_M_IX86)
|
||||||
|
#define COMPILER_BITS "32 bit"
|
||||||
|
#else
|
||||||
|
#define COMPILER_BITS ""
|
||||||
|
#endif
|
||||||
|
#define PLATFORM_COMPILER \
|
||||||
|
"MSC v." MP_STRINGIFY(_MSC_VER) " " COMPILER_BITS
|
||||||
|
#else
|
||||||
|
#define PLATFORM_COMPILER ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
#define PLATFORM_LIBC_LIB "glibc"
|
||||||
|
#define PLATFORM_LIBC_VER \
|
||||||
|
MP_STRINGIFY(__GLIBC__) "." \
|
||||||
|
MP_STRINGIFY(__GLIBC_MINOR__)
|
||||||
|
#elif defined(__NEWLIB__)
|
||||||
|
#define PLATFORM_LIBC_LIB "newlib"
|
||||||
|
#define PLATFORM_LIBC_VER _NEWLIB_VERSION
|
||||||
|
#else
|
||||||
|
#define PLATFORM_LIBC_LIB ""
|
||||||
|
#define PLATFORM_LIBC_VER ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux)
|
||||||
|
#define PLATFORM_SYSTEM "Linux"
|
||||||
|
#elif defined(__unix__)
|
||||||
|
#define PLATFORM_SYSTEM "Unix"
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
#define PLATFORM_SYSTEM "Cygwin"
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define PLATFORM_SYSTEM "Windows"
|
||||||
|
#else
|
||||||
|
#define PLATFORM_SYSTEM "MicroPython"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MICROPY_PLATFORM_VERSION
|
||||||
|
#define MICROPY_PLATFORM_VERSION ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, PLATFORM_SYSTEM "-" MICROPY_VERSION_STRING "-" \
|
||||||
|
PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" PLATFORM_LIBC_LIB "" PLATFORM_LIBC_VER);
|
||||||
|
STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, PLATFORM_COMPILER);
|
||||||
|
STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, PLATFORM_LIBC_LIB);
|
||||||
|
STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, PLATFORM_LIBC_VER);
|
||||||
|
STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
|
||||||
|
{&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
return MP_OBJ_FROM_PTR(&info_platform_obj);
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
|
||||||
|
|
||||||
|
STATIC mp_obj_t platform_python_compiler(void) {
|
||||||
|
return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
|
||||||
|
|
||||||
|
STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
|
||||||
|
|
||||||
|
STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
|
||||||
|
|
||||||
|
const mp_obj_module_t mp_module_uplatform = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t *)&modplatform_globals,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_UPLATFORM
|
||||||
@ -454,11 +454,16 @@ const mp_obj_module_t mp_module_ure = {
|
|||||||
// only if module is enabled by config setting.
|
// only if module is enabled by config setting.
|
||||||
|
|
||||||
#define re1_5_fatal(x) assert(!x)
|
#define re1_5_fatal(x) assert(!x)
|
||||||
|
|
||||||
#include "lib/re1.5/compilecode.c"
|
#include "lib/re1.5/compilecode.c"
|
||||||
#if MICROPY_PY_URE_DEBUG
|
|
||||||
#include "lib/re1.5/dumpcode.c"
|
|
||||||
#endif
|
|
||||||
#include "lib/re1.5/recursiveloop.c"
|
#include "lib/re1.5/recursiveloop.c"
|
||||||
#include "lib/re1.5/charclass.c"
|
#include "lib/re1.5/charclass.c"
|
||||||
|
|
||||||
|
#if MICROPY_PY_URE_DEBUG
|
||||||
|
// Make sure the output print statements go to the same output as other Python output.
|
||||||
|
#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
|
||||||
|
#include "lib/re1.5/dumpcode.c"
|
||||||
|
#undef printf
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // MICROPY_PY_URE
|
#endif // MICROPY_PY_URE
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
#include "shared/netutils/netutils.h"
|
#include "shared/netutils/netutils.h"
|
||||||
#include "modnetwork.h"
|
#include "modnetwork.h"
|
||||||
|
|
||||||
#if MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
|
#if MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// socket class
|
// socket class
|
||||||
@ -51,19 +51,26 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
|||||||
s->base.type = &socket_type;
|
s->base.type = &socket_type;
|
||||||
s->nic = MP_OBJ_NULL;
|
s->nic = MP_OBJ_NULL;
|
||||||
s->nic_type = NULL;
|
s->nic_type = NULL;
|
||||||
s->u_param.domain = MOD_NETWORK_AF_INET;
|
s->domain = MOD_NETWORK_AF_INET;
|
||||||
s->u_param.type = MOD_NETWORK_SOCK_STREAM;
|
s->type = MOD_NETWORK_SOCK_STREAM;
|
||||||
s->u_param.fileno = -1;
|
s->proto = 0;
|
||||||
|
s->bound = false;
|
||||||
|
s->fileno = -1;
|
||||||
if (n_args >= 1) {
|
if (n_args >= 1) {
|
||||||
s->u_param.domain = mp_obj_get_int(args[0]);
|
s->domain = mp_obj_get_int(args[0]);
|
||||||
if (n_args >= 2) {
|
if (n_args >= 2) {
|
||||||
s->u_param.type = mp_obj_get_int(args[1]);
|
s->type = mp_obj_get_int(args[1]);
|
||||||
if (n_args >= 4) {
|
if (n_args >= 4) {
|
||||||
s->u_param.fileno = mp_obj_get_int(args[3]);
|
s->fileno = mp_obj_get_int(args[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_USOCKET_EXTENDED_STATE
|
||||||
|
s->timeout = 0;
|
||||||
|
s->state = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
return MP_OBJ_FROM_PTR(s);
|
return MP_OBJ_FROM_PTR(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +85,13 @@ STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
|
|||||||
if (self->nic_type->socket(self, &_errno) != 0) {
|
if (self->nic_type->socket(self, &_errno) != 0) {
|
||||||
mp_raise_OSError(_errno);
|
mp_raise_OSError(_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_USOCKET_EXTENDED_STATE
|
||||||
|
// if a timeout was set before binding a NIC, call settimeout to reset it
|
||||||
|
if (self->timeout != 0 && self->nic_type->settimeout(self, self->timeout, &_errno) != 0) {
|
||||||
|
mp_raise_OSError(_errno);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +151,17 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
|||||||
socket2->nic = MP_OBJ_NULL;
|
socket2->nic = MP_OBJ_NULL;
|
||||||
socket2->nic_type = NULL;
|
socket2->nic_type = NULL;
|
||||||
|
|
||||||
|
// set the same address family, socket type and protocol as parent
|
||||||
|
socket2->domain = self->domain;
|
||||||
|
socket2->type = self->type;
|
||||||
|
socket2->proto = self->proto;
|
||||||
|
socket2->bound = false;
|
||||||
|
socket2->fileno = -1;
|
||||||
|
#if MICROPY_PY_USOCKET_EXTENDED_STATE
|
||||||
|
socket2->timeout = 0;
|
||||||
|
socket2->state = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
// accept incoming connection
|
// accept incoming connection
|
||||||
uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
|
uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
|
||||||
mp_uint_t port;
|
mp_uint_t port;
|
||||||
@ -310,10 +335,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_s
|
|||||||
// otherwise, timeout is in seconds
|
// otherwise, timeout is in seconds
|
||||||
STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
||||||
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (self->nic == MP_OBJ_NULL) {
|
|
||||||
// not connected
|
|
||||||
mp_raise_OSError(MP_ENOTCONN);
|
|
||||||
}
|
|
||||||
mp_uint_t timeout;
|
mp_uint_t timeout;
|
||||||
if (timeout_in == mp_const_none) {
|
if (timeout_in == mp_const_none) {
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
@ -324,10 +345,20 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
|||||||
timeout = 1000 * mp_obj_get_int(timeout_in);
|
timeout = 1000 * mp_obj_get_int(timeout_in);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (self->nic == MP_OBJ_NULL) {
|
||||||
|
#if MICROPY_PY_USOCKET_EXTENDED_STATE
|
||||||
|
// store the timeout in the socket state until a NIC is bound
|
||||||
|
self->timeout = timeout;
|
||||||
|
#else
|
||||||
|
// not connected
|
||||||
|
mp_raise_OSError(MP_ENOTCONN);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
int _errno;
|
int _errno;
|
||||||
if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
|
if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
|
||||||
mp_raise_OSError(_errno);
|
mp_raise_OSError(_errno);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
|
||||||
@ -356,10 +387,41 @@ STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
|
|||||||
{ MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
|
||||||
|
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
|
||||||
|
|
||||||
|
mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
|
||||||
|
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
if (self->nic == MP_OBJ_NULL) {
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
|
}
|
||||||
|
mp_int_t ret = self->nic_type->recv(self, (byte *)buf, size, errcode);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = MP_STREAM_ERROR;
|
||||||
|
*errcode = -(*errcode); // expects a positive error code
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
|
||||||
|
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
if (self->nic == MP_OBJ_NULL) {
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
|
}
|
||||||
|
mp_int_t ret = self->nic_type->send(self, buf, size, errcode);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = MP_STREAM_ERROR;
|
||||||
|
*errcode = -(*errcode); // expects a positive error code
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||||
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (request == MP_STREAM_CLOSE) {
|
if (request == MP_STREAM_CLOSE) {
|
||||||
@ -380,6 +442,8 @@ mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC const mp_stream_p_t socket_stream_p = {
|
STATIC const mp_stream_p_t socket_stream_p = {
|
||||||
|
.read = socket_read,
|
||||||
|
.write = socket_write,
|
||||||
.ioctl = socket_ioctl,
|
.ioctl = socket_ioctl,
|
||||||
.is_text = false,
|
.is_text = false,
|
||||||
};
|
};
|
||||||
@ -477,4 +541,4 @@ const mp_obj_module_t mp_module_usocket = {
|
|||||||
.globals = (mp_obj_dict_t *)&mp_module_usocket_globals,
|
.globals = (mp_obj_dict_t *)&mp_module_usocket_globals,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
|
#endif // MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
|
||||||
@ -45,6 +45,7 @@ int mp_bluetooth_hci_controller_wakeup(void);
|
|||||||
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate);
|
int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate);
|
||||||
int mp_bluetooth_hci_uart_deinit(void);
|
int mp_bluetooth_hci_uart_deinit(void);
|
||||||
int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate);
|
int mp_bluetooth_hci_uart_set_baudrate(uint32_t baudrate);
|
||||||
|
int mp_bluetooth_hci_uart_any(void);
|
||||||
int mp_bluetooth_hci_uart_readchar(void);
|
int mp_bluetooth_hci_uart_readchar(void);
|
||||||
int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len);
|
int mp_bluetooth_hci_uart_write(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
|
|||||||
@ -43,8 +43,8 @@ typedef struct _network_cyw43_obj_t {
|
|||||||
int itf;
|
int itf;
|
||||||
} network_cyw43_obj_t;
|
} network_cyw43_obj_t;
|
||||||
|
|
||||||
STATIC const network_cyw43_obj_t network_cyw43_wl0 = { { &mp_network_cyw43_type }, &cyw43_state, 0 };
|
STATIC const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA };
|
||||||
STATIC const network_cyw43_obj_t network_cyw43_wl1 = { { &mp_network_cyw43_type }, &cyw43_state, 1 };
|
STATIC const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP };
|
||||||
|
|
||||||
STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
@ -65,7 +65,7 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
|
|||||||
status_str = "fail";
|
status_str = "fail";
|
||||||
}
|
}
|
||||||
mp_printf(print, "<CYW43 %s %s %u.%u.%u.%u>",
|
mp_printf(print, "<CYW43 %s %s %u.%u.%u.%u>",
|
||||||
self->itf == 0 ? "STA" : "AP",
|
self->itf == CYW43_ITF_STA ? "STA" : "AP",
|
||||||
status_str,
|
status_str,
|
||||||
netif->ip_addr.addr & 0xff,
|
netif->ip_addr.addr & 0xff,
|
||||||
netif->ip_addr.addr >> 8 & 0xff,
|
netif->ip_addr.addr >> 8 & 0xff,
|
||||||
@ -76,10 +76,10 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
|
|||||||
|
|
||||||
STATIC mp_obj_t network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
STATIC mp_obj_t network_cyw43_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
if (n_args == 0 || mp_obj_get_int(args[0]) == 0) {
|
if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) {
|
||||||
return MP_OBJ_FROM_PTR(&network_cyw43_wl0);
|
return MP_OBJ_FROM_PTR(&network_cyw43_wl_sta);
|
||||||
} else {
|
} else {
|
||||||
return MP_OBJ_FROM_PTR(&network_cyw43_wl1);
|
return MP_OBJ_FROM_PTR(&network_cyw43_wl_ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
595
extmod/network_ninaw10.c
Normal file
595
extmod/network_ninaw10.c
Normal file
@ -0,0 +1,595 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* NINA-W10 Python module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "py/mphal.h"
|
||||||
|
|
||||||
|
#if MICROPY_PY_NETWORK && MICROPY_PY_NETWORK_NINAW10
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "py/objtuple.h"
|
||||||
|
#include "py/objlist.h"
|
||||||
|
#include "py/stream.h"
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "py/misc.h"
|
||||||
|
#include "py/mperrno.h"
|
||||||
|
#include "shared/netutils/netutils.h"
|
||||||
|
#include "extmod/modnetwork.h"
|
||||||
|
|
||||||
|
#include "nina_wifi_drv.h"
|
||||||
|
|
||||||
|
typedef struct _nina_obj_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
bool active;
|
||||||
|
uint32_t itf;
|
||||||
|
} nina_obj_t;
|
||||||
|
|
||||||
|
// For auto-binding UDP sockets
|
||||||
|
#define BIND_PORT_RANGE_MIN (65000)
|
||||||
|
#define BIND_PORT_RANGE_MAX (65535)
|
||||||
|
|
||||||
|
static uint16_t bind_port = BIND_PORT_RANGE_MIN;
|
||||||
|
const mod_network_nic_type_t mod_network_nic_type_nina;
|
||||||
|
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
|
||||||
|
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||||
|
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||||
|
mp_obj_t nina_obj;
|
||||||
|
if (n_args == 0 || mp_obj_get_int(args[0]) == MOD_NETWORK_STA_IF) {
|
||||||
|
nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_sta);
|
||||||
|
} else {
|
||||||
|
nina_obj = MP_OBJ_FROM_PTR(&network_nina_wl_ap);
|
||||||
|
}
|
||||||
|
// Register with network module
|
||||||
|
mod_network_register_nic(nina_obj);
|
||||||
|
return nina_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) {
|
||||||
|
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
if (n_args == 2) {
|
||||||
|
bool active = mp_obj_is_true(args[1]);
|
||||||
|
if (active) {
|
||||||
|
int error = 0;
|
||||||
|
if ((error = nina_init()) != 0) {
|
||||||
|
mp_raise_msg_varg(&mp_type_OSError,
|
||||||
|
MP_ERROR_TEXT("Failed to initialize Nina-W10 module, error: %d\n"), error);
|
||||||
|
}
|
||||||
|
// check firmware version
|
||||||
|
uint8_t fw_ver[NINA_FW_VER_LEN];
|
||||||
|
if (nina_fw_version(fw_ver) != 0) {
|
||||||
|
nina_deinit();
|
||||||
|
mp_raise_msg_varg(&mp_type_OSError,
|
||||||
|
MP_ERROR_TEXT("Failed to read firmware version, error: %d\n"), error);
|
||||||
|
}
|
||||||
|
// Check fw version matches the driver.
|
||||||
|
if ((fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48) != NINA_FW_VER_MAJOR ||
|
||||||
|
(fw_ver[NINA_FW_VER_MINOR_OFFS] - 48) != NINA_FW_VER_MINOR ||
|
||||||
|
(fw_ver[NINA_FW_VER_PATCH_OFFS] - 48) != NINA_FW_VER_PATCH) {
|
||||||
|
mp_printf(&mp_plat_print,
|
||||||
|
"Warning: firmware version mismatch, expected %d.%d.%d found: %d.%d.%d\n",
|
||||||
|
NINA_FW_VER_MAJOR, NINA_FW_VER_MINOR, NINA_FW_VER_PATCH,
|
||||||
|
fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48,
|
||||||
|
fw_ver[NINA_FW_VER_MINOR_OFFS] - 48,
|
||||||
|
fw_ver[NINA_FW_VER_PATCH_OFFS] - 48);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nina_deinit();
|
||||||
|
}
|
||||||
|
self->active = active;
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
return mp_obj_new_bool(self->active);
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, network_ninaw10_active);
|
||||||
|
|
||||||
|
STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) {
|
||||||
|
mp_obj_t scan_list = (mp_obj_t)arg;
|
||||||
|
mp_obj_t ap[6] = {
|
||||||
|
mp_obj_new_bytes((uint8_t *)scan_result->ssid, strlen(scan_result->ssid)),
|
||||||
|
mp_obj_new_bytes(scan_result->bssid, sizeof(scan_result->bssid)),
|
||||||
|
mp_obj_new_int(scan_result->channel),
|
||||||
|
mp_obj_new_int(scan_result->rssi),
|
||||||
|
mp_obj_new_int(scan_result->security),
|
||||||
|
MP_OBJ_NEW_SMALL_INT(1), // N
|
||||||
|
};
|
||||||
|
mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) {
|
||||||
|
mp_obj_t scan_list;
|
||||||
|
scan_list = mp_obj_new_list(0, NULL);
|
||||||
|
nina_scan(nina_scan_callback, scan_list, 10000);
|
||||||
|
return scan_list;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum { ARG_essid, ARG_key, ARG_security, ARG_channel };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_essid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||||
|
{ MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NINA_SEC_WPA_PSK} },
|
||||||
|
{ MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||||
|
};
|
||||||
|
|
||||||
|
// parse args
|
||||||
|
nina_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
// get ssid
|
||||||
|
const char *ssid = mp_obj_str_get_str(args[ARG_essid].u_obj);
|
||||||
|
|
||||||
|
if (strlen(ssid) == 0) {
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get key and sec
|
||||||
|
const char *key = NULL;
|
||||||
|
mp_uint_t security = NINA_SEC_OPEN;
|
||||||
|
|
||||||
|
if (args[ARG_key].u_obj != mp_const_none) {
|
||||||
|
key = mp_obj_str_get_str(args[ARG_key].u_obj);
|
||||||
|
security = args[ARG_security].u_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (security != NINA_SEC_OPEN && strlen(key) == 0) {
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect active connections first.
|
||||||
|
if (nina_isconnected()) {
|
||||||
|
nina_disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->itf == MOD_NETWORK_STA_IF) {
|
||||||
|
// Initialize WiFi in Station mode.
|
||||||
|
if (nina_connect(ssid, security, key, 0) != 0) {
|
||||||
|
mp_raise_msg_varg(&mp_type_OSError,
|
||||||
|
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mp_uint_t channel = args[ARG_channel].u_int;
|
||||||
|
|
||||||
|
if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) {
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize WiFi in AP mode.
|
||||||
|
if (nina_start_ap(ssid, security, key, channel) != 0) {
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_disconnect(mp_obj_t self_in) {
|
||||||
|
nina_disconnect();
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_disconnect_obj, network_ninaw10_disconnect);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_isconnected(mp_obj_t self_in) {
|
||||||
|
return mp_obj_new_bool(nina_isconnected());
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_isconnected_obj, network_ninaw10_isconnected);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_ifconfig(size_t n_args, const mp_obj_t *args) {
|
||||||
|
nina_ifconfig_t ifconfig;
|
||||||
|
if (n_args == 1) {
|
||||||
|
// get ifconfig info
|
||||||
|
nina_ifconfig(&ifconfig, false);
|
||||||
|
mp_obj_t tuple[4] = {
|
||||||
|
netutils_format_ipv4_addr(ifconfig.ip_addr, NETUTILS_BIG),
|
||||||
|
netutils_format_ipv4_addr(ifconfig.subnet_addr, NETUTILS_BIG),
|
||||||
|
netutils_format_ipv4_addr(ifconfig.gateway_addr, NETUTILS_BIG),
|
||||||
|
netutils_format_ipv4_addr(ifconfig.dns_addr, NETUTILS_BIG),
|
||||||
|
};
|
||||||
|
return mp_obj_new_tuple(4, tuple);
|
||||||
|
} else {
|
||||||
|
// set ifconfig info
|
||||||
|
mp_obj_t *items;
|
||||||
|
mp_obj_get_array_fixed_n(args[1], 4, &items);
|
||||||
|
netutils_parse_ipv4_addr(items[0], ifconfig.ip_addr, NETUTILS_BIG);
|
||||||
|
netutils_parse_ipv4_addr(items[1], ifconfig.subnet_addr, NETUTILS_BIG);
|
||||||
|
netutils_parse_ipv4_addr(items[2], ifconfig.gateway_addr, NETUTILS_BIG);
|
||||||
|
netutils_parse_ipv4_addr(items[3], ifconfig.dns_addr, NETUTILS_BIG);
|
||||||
|
nina_ifconfig(&ifconfig, true);
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_ifconfig_obj, 1, 2, network_ninaw10_ifconfig);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||||
|
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
(void)self;
|
||||||
|
|
||||||
|
if (kwargs->used == 0) {
|
||||||
|
// Get config value
|
||||||
|
if (n_args != 2) {
|
||||||
|
mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mp_obj_str_get_qstr(args[1])) {
|
||||||
|
case MP_QSTR_essid: {
|
||||||
|
nina_netinfo_t netinfo;
|
||||||
|
nina_netinfo(&netinfo);
|
||||||
|
return mp_obj_new_str(netinfo.ssid, strlen(netinfo.ssid));
|
||||||
|
}
|
||||||
|
case MP_QSTR_security: {
|
||||||
|
nina_netinfo_t netinfo;
|
||||||
|
nina_netinfo(&netinfo);
|
||||||
|
return mp_obj_new_int(netinfo.security);
|
||||||
|
}
|
||||||
|
case MP_QSTR_mac:
|
||||||
|
case MP_QSTR_bssid: {
|
||||||
|
nina_netinfo_t netinfo;
|
||||||
|
nina_netinfo(&netinfo);
|
||||||
|
return mp_obj_new_bytes(netinfo.bssid, 6);
|
||||||
|
}
|
||||||
|
case MP_QSTR_fw_version: {
|
||||||
|
uint8_t fwver[NINA_FW_VER_LEN];
|
||||||
|
nina_fw_version(fwver);
|
||||||
|
return mp_obj_new_tuple(3, (mp_obj_t []) {
|
||||||
|
mp_obj_new_int(fwver[NINA_FW_VER_MAJOR_OFFS] - 48),
|
||||||
|
mp_obj_new_int(fwver[NINA_FW_VER_MINOR_OFFS] - 48),
|
||||||
|
mp_obj_new_int(fwver[NINA_FW_VER_PATCH_OFFS] - 48)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (self->itf != MOD_NETWORK_AP_IF) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
|
||||||
|
}
|
||||||
|
// Call connect to set WiFi access point.
|
||||||
|
return network_ninaw10_connect(n_args, args, kwargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_config_obj, 1, network_ninaw10_config);
|
||||||
|
|
||||||
|
STATIC mp_obj_t network_ninaw10_status(size_t n_args, const mp_obj_t *args) {
|
||||||
|
nina_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
(void)self;
|
||||||
|
|
||||||
|
if (n_args == 1) {
|
||||||
|
// no arguments: return link status
|
||||||
|
return mp_obj_new_bool(nina_isconnected());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query parameter.
|
||||||
|
switch (mp_obj_str_get_qstr(args[1])) {
|
||||||
|
case MP_QSTR_rssi: {
|
||||||
|
nina_netinfo_t netinfo;
|
||||||
|
nina_netinfo(&netinfo);
|
||||||
|
return mp_obj_new_int(netinfo.rssi);
|
||||||
|
}
|
||||||
|
case MP_QSTR_stations: {
|
||||||
|
if (self->itf != MOD_NETWORK_AP_IF) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("AP required"));
|
||||||
|
}
|
||||||
|
uint32_t sta_ip = 0;
|
||||||
|
mp_obj_t sta_list = mp_obj_new_list(0, NULL);
|
||||||
|
if (nina_connected_sta(&sta_ip) == 0) {
|
||||||
|
mp_obj_list_append(sta_list,
|
||||||
|
netutils_format_inet_addr((uint8_t *)&sta_ip, 0, NETUTILS_BIG));
|
||||||
|
}
|
||||||
|
return sta_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_status_obj, 1, 2, network_ninaw10_status);
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
|
||||||
|
return nina_gethostbyname(name, out_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
if (socket->domain != MOD_NETWORK_AF_INET) {
|
||||||
|
*_errno = MP_EAFNOSUPPORT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (socket->type) {
|
||||||
|
case MOD_NETWORK_SOCK_STREAM:
|
||||||
|
type = NINA_SOCKET_TYPE_TCP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_NETWORK_SOCK_DGRAM:
|
||||||
|
type = NINA_SOCKET_TYPE_UDP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*_errno = MP_EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open socket
|
||||||
|
int fd = nina_socket_socket(type);
|
||||||
|
if (fd < 0) {
|
||||||
|
*_errno = fd;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set socket state
|
||||||
|
socket->fileno = fd;
|
||||||
|
socket->bound = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) {
|
||||||
|
if (socket->fileno >= 0) {
|
||||||
|
nina_socket_close(socket->fileno);
|
||||||
|
socket->fileno = -1; // Mark socket FD as invalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
|
||||||
|
uint8_t type;
|
||||||
|
switch (socket->type) {
|
||||||
|
case MOD_NETWORK_SOCK_STREAM:
|
||||||
|
type = NINA_SOCKET_TYPE_TCP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOD_NETWORK_SOCK_DGRAM:
|
||||||
|
type = NINA_SOCKET_TYPE_UDP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*_errno = MP_EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = nina_socket_bind(socket->fileno, ip, port, type);
|
||||||
|
if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark socket as bound to avoid auto-binding.
|
||||||
|
socket->bound = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
|
||||||
|
int ret = nina_socket_listen(socket->fileno, backlog);
|
||||||
|
if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket,
|
||||||
|
mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
|
||||||
|
int fd = 0;
|
||||||
|
// Call accept.
|
||||||
|
int ret = nina_socket_accept(socket->fileno, ip, (uint16_t *)port, &fd, socket->timeout);
|
||||||
|
if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set socket state
|
||||||
|
socket2->fileno = fd;
|
||||||
|
socket2->bound = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
|
||||||
|
int ret = nina_socket_connect(socket->fileno, ip, port, socket->timeout);
|
||||||
|
if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
|
||||||
|
int ret = nina_socket_send(socket->fileno, buf, len, socket->timeout);
|
||||||
|
if (ret == NINA_ERROR_TIMEOUT) {
|
||||||
|
// The socket is Not closed on timeout when calling functions that accept a timeout.
|
||||||
|
*_errno = MP_ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
// Close the socket on any other errors.
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
|
||||||
|
int ret = 0;
|
||||||
|
if (socket->type == MOD_NETWORK_SOCK_DGRAM) {
|
||||||
|
byte ip[4];
|
||||||
|
uint16_t port;
|
||||||
|
ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, &port, socket->timeout);
|
||||||
|
} else {
|
||||||
|
ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == NINA_ERROR_TIMEOUT) {
|
||||||
|
// The socket is Not closed on timeout when calling functions that accept a timeout.
|
||||||
|
*_errno = MP_ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
// Close the socket on any other errors.
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t network_ninaw10_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) {
|
||||||
|
if (socket->bound == false) {
|
||||||
|
if (network_ninaw10_socket_bind(socket, NULL, bind_port, _errno) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bind_port++;
|
||||||
|
bind_port = MIN(MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket,
|
||||||
|
const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
|
||||||
|
// Auto-bind the socket first if the socket is unbound.
|
||||||
|
if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = nina_socket_sendto(socket->fileno, buf, len, ip, port, socket->timeout);
|
||||||
|
if (ret == NINA_ERROR_TIMEOUT) {
|
||||||
|
// The socket is Not closed on timeout when calling functions that accept a timeout.
|
||||||
|
*_errno = MP_ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket,
|
||||||
|
byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
|
||||||
|
int ret = 0;
|
||||||
|
if (socket->type == MOD_NETWORK_SOCK_STREAM) {
|
||||||
|
*port = 0;
|
||||||
|
*((uint32_t *)ip) = 0;
|
||||||
|
ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout);
|
||||||
|
} else {
|
||||||
|
// Auto-bind the socket first if the socket is unbound.
|
||||||
|
if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout);
|
||||||
|
}
|
||||||
|
if (ret == NINA_ERROR_TIMEOUT) {
|
||||||
|
// The socket is Not closed on timeout when calling functions that accept a timeout.
|
||||||
|
*_errno = MP_ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
// Close the socket on any other errors.
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t
|
||||||
|
level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
|
||||||
|
int ret = nina_socket_setsockopt(socket->fileno, level, opt, optval, optlen);
|
||||||
|
if (ret < 0) {
|
||||||
|
*_errno = ret;
|
||||||
|
network_ninaw10_socket_close(socket);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
|
||||||
|
if (timeout_ms == UINT32_MAX) {
|
||||||
|
// no timeout is given, set the socket to blocking mode.
|
||||||
|
timeout_ms = 0;
|
||||||
|
}
|
||||||
|
socket->timeout = timeout_ms;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
|
||||||
|
*_errno = MP_EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const mp_rom_map_elem_t nina_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_ninaw10_disconnect_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_ninaw10_isconnected_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_ninaw10_ifconfig_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_ninaw10_config_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_ninaw10_status_obj) },
|
||||||
|
|
||||||
|
// Network is not secured.
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(NINA_SEC_OPEN) },
|
||||||
|
// Security type WEP (40 or 104).
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(NINA_SEC_WEP) },
|
||||||
|
// Network secured with WPA/WPA2 personal(PSK).
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) },
|
||||||
|
};
|
||||||
|
|
||||||
|
static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
|
||||||
|
|
||||||
|
const mod_network_nic_type_t mod_network_nic_type_nina = {
|
||||||
|
.base = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_nina,
|
||||||
|
.make_new = network_ninaw10_make_new,
|
||||||
|
.locals_dict = (mp_obj_t)&nina_locals_dict,
|
||||||
|
},
|
||||||
|
.gethostbyname = network_ninaw10_gethostbyname,
|
||||||
|
.socket = network_ninaw10_socket_socket,
|
||||||
|
.close = network_ninaw10_socket_close,
|
||||||
|
.bind = network_ninaw10_socket_bind,
|
||||||
|
.listen = network_ninaw10_socket_listen,
|
||||||
|
.accept = network_ninaw10_socket_accept,
|
||||||
|
.connect = network_ninaw10_socket_connect,
|
||||||
|
.send = network_ninaw10_socket_send,
|
||||||
|
.recv = network_ninaw10_socket_recv,
|
||||||
|
.sendto = network_ninaw10_socket_sendto,
|
||||||
|
.recvfrom = network_ninaw10_socket_recvfrom,
|
||||||
|
.setsockopt = network_ninaw10_socket_setsockopt,
|
||||||
|
.settimeout = network_ninaw10_socket_settimeout,
|
||||||
|
.ioctl = network_ninaw10_socket_ioctl,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10
|
||||||
@ -138,9 +138,9 @@ STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_e
|
|||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
||||||
// Bonding store.
|
// Bonding store.
|
||||||
STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value);
|
STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value);
|
||||||
STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val);
|
STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val);
|
||||||
STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key);
|
STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC int ble_hs_err_to_errno(int err) {
|
STATIC int ble_hs_err_to_errno(int err) {
|
||||||
@ -604,6 +604,12 @@ int mp_bluetooth_init(void) {
|
|||||||
ble_hs_cfg.gatts_register_cb = gatts_register_cb;
|
ble_hs_cfg.gatts_register_cb = gatts_register_cb;
|
||||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
||||||
|
ble_hs_cfg.store_read_cb = ble_secret_store_read;
|
||||||
|
ble_hs_cfg.store_write_cb = ble_secret_store_write;
|
||||||
|
ble_hs_cfg.store_delete_cb = ble_secret_store_delete;
|
||||||
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
||||||
|
|
||||||
MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1);
|
MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1);
|
||||||
mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db);
|
mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db);
|
||||||
|
|
||||||
@ -1202,7 +1208,7 @@ STATIC int peripheral_gap_event_cb(struct ble_gap_event *event, void *arg) {
|
|||||||
return commmon_gap_event_cb(event, arg);
|
return commmon_gap_event_cb(event, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms) {
|
int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr, int32_t duration_ms, int32_t min_conn_interval_us, int32_t max_conn_interval_us) {
|
||||||
DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
|
DEBUG_printf("mp_bluetooth_gap_peripheral_connect\n");
|
||||||
if (!mp_bluetooth_is_active()) {
|
if (!mp_bluetooth_is_active()) {
|
||||||
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||||
@ -1211,12 +1217,14 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
|
|||||||
mp_bluetooth_gap_scan_stop();
|
mp_bluetooth_gap_scan_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This is the same as ble_gap_conn_params_dflt (i.e. passing NULL).
|
uint16_t conn_interval_min = min_conn_interval_us ? min_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MIN;
|
||||||
STATIC const struct ble_gap_conn_params params = {
|
uint16_t conn_interval_max = max_conn_interval_us ? max_conn_interval_us / BLE_HCI_CONN_ITVL : BLE_GAP_INITIAL_CONN_ITVL_MAX;
|
||||||
|
|
||||||
|
const struct ble_gap_conn_params params = {
|
||||||
.scan_itvl = 0x0010,
|
.scan_itvl = 0x0010,
|
||||||
.scan_window = 0x0010,
|
.scan_window = 0x0010,
|
||||||
.itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN,
|
.itvl_min = conn_interval_min,
|
||||||
.itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX,
|
.itvl_max = conn_interval_max,
|
||||||
.latency = BLE_GAP_INITIAL_CONN_LATENCY,
|
.latency = BLE_GAP_INITIAL_CONN_LATENCY,
|
||||||
.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT,
|
.supervision_timeout = BLE_GAP_INITIAL_SUPERVISION_TIMEOUT,
|
||||||
.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
|
.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN,
|
||||||
@ -1228,6 +1236,15 @@ int mp_bluetooth_gap_peripheral_connect(uint8_t addr_type, const uint8_t *addr,
|
|||||||
return ble_hs_err_to_errno(err);
|
return ble_hs_err_to_errno(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mp_bluetooth_gap_peripheral_connect_cancel(void) {
|
||||||
|
DEBUG_printf("mp_bluetooth_gap_peripheral_connect_cancel\n");
|
||||||
|
if (!mp_bluetooth_is_active()) {
|
||||||
|
return ERRNO_BLUETOOTH_NOT_ACTIVE;
|
||||||
|
}
|
||||||
|
int err = ble_gap_conn_cancel();
|
||||||
|
return ble_hs_err_to_errno(err);
|
||||||
|
}
|
||||||
|
|
||||||
STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
STATIC int ble_gattc_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) {
|
||||||
DEBUG_printf("ble_gattc_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1);
|
DEBUG_printf("ble_gattc_service_cb: conn_handle=%d status=%d start_handle=%d\n", conn_handle, error->status, service ? service->start_handle : -1);
|
||||||
if (!mp_bluetooth_is_active()) {
|
if (!mp_bluetooth_is_active()) {
|
||||||
@ -1739,12 +1756,6 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b
|
|||||||
*stalled = true;
|
*stalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes we see what looks like BLE_HS_EAGAIN (but it's actually
|
|
||||||
// OS_ENOMEM in disguise). Fixed in NimBLE v1.4.
|
|
||||||
if (err == OS_ENOMEM) {
|
|
||||||
err = BLE_HS_ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other error codes such as BLE_HS_EBUSY (we're stalled) or BLE_HS_EBADDATA (bigger than MTU).
|
// Other error codes such as BLE_HS_EBUSY (we're stalled) or BLE_HS_EBADDATA (bigger than MTU).
|
||||||
return ble_hs_err_to_errno(err);
|
return ble_hs_err_to_errno(err);
|
||||||
}
|
}
|
||||||
@ -1824,8 +1835,8 @@ int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t
|
|||||||
|
|
||||||
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
||||||
|
|
||||||
STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {
|
STATIC int ble_secret_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {
|
||||||
DEBUG_printf("ble_store_ram_read: %d\n", obj_type);
|
DEBUG_printf("ble_secret_store_read: %d\n", obj_type);
|
||||||
const uint8_t *key_data;
|
const uint8_t *key_data;
|
||||||
size_t key_data_len;
|
size_t key_data_len;
|
||||||
|
|
||||||
@ -1859,7 +1870,7 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
|
|||||||
}
|
}
|
||||||
case BLE_STORE_OBJ_TYPE_CCCD: {
|
case BLE_STORE_OBJ_TYPE_CCCD: {
|
||||||
// TODO: Implement CCCD persistence.
|
// TODO: Implement CCCD persistence.
|
||||||
DEBUG_printf("ble_store_ram_read: CCCD not supported.\n");
|
DEBUG_printf("ble_secret_store_read: CCCD not supported.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -1869,18 +1880,18 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
|
|||||||
const uint8_t *value_data;
|
const uint8_t *value_data;
|
||||||
size_t value_data_len;
|
size_t value_data_len;
|
||||||
if (!mp_bluetooth_gap_on_get_secret(obj_type, key->sec.idx, key_data, key_data_len, &value_data, &value_data_len)) {
|
if (!mp_bluetooth_gap_on_get_secret(obj_type, key->sec.idx, key_data, key_data_len, &value_data, &value_data_len)) {
|
||||||
DEBUG_printf("ble_store_ram_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len);
|
DEBUG_printf("ble_secret_store_read: Key not found: type=%d, index=%u, key=0x%p, len=" UINT_FMT "\n", obj_type, key->sec.idx, key_data, key_data_len);
|
||||||
return BLE_HS_ENOENT;
|
return BLE_HS_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_data_len != sizeof(struct ble_store_value_sec)) {
|
if (value_data_len != sizeof(struct ble_store_value_sec)) {
|
||||||
DEBUG_printf("ble_store_ram_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec));
|
DEBUG_printf("ble_secret_store_read: Invalid key data: actual=" UINT_FMT " expected=" UINT_FMT "\n", value_data_len, sizeof(struct ble_store_value_sec));
|
||||||
return BLE_HS_ENOENT;
|
return BLE_HS_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((uint8_t *)&value->sec, value_data, sizeof(struct ble_store_value_sec));
|
memcpy((uint8_t *)&value->sec, value_data, sizeof(struct ble_store_value_sec));
|
||||||
|
|
||||||
DEBUG_printf("ble_store_ram_read: found secret\n");
|
DEBUG_printf("ble_secret_store_read: found secret\n");
|
||||||
|
|
||||||
if (obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC) {
|
if (obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC) {
|
||||||
// TODO: Verify ediv_rand matches.
|
// TODO: Verify ediv_rand matches.
|
||||||
@ -1889,8 +1900,8 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
|
STATIC int ble_secret_store_write(int obj_type, const union ble_store_value *val) {
|
||||||
DEBUG_printf("ble_store_ram_write: %d\n", obj_type);
|
DEBUG_printf("ble_secret_store_write: %d\n", obj_type);
|
||||||
switch (obj_type) {
|
switch (obj_type) {
|
||||||
case BLE_STORE_OBJ_TYPE_PEER_SEC:
|
case BLE_STORE_OBJ_TYPE_PEER_SEC:
|
||||||
case BLE_STORE_OBJ_TYPE_OUR_SEC: {
|
case BLE_STORE_OBJ_TYPE_OUR_SEC: {
|
||||||
@ -1908,13 +1919,13 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
|
|||||||
return BLE_HS_ESTORE_CAP;
|
return BLE_HS_ESTORE_CAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_printf("ble_store_ram_write: wrote secret\n");
|
DEBUG_printf("ble_secret_store_write: wrote secret\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case BLE_STORE_OBJ_TYPE_CCCD: {
|
case BLE_STORE_OBJ_TYPE_CCCD: {
|
||||||
// TODO: Implement CCCD persistence.
|
// TODO: Implement CCCD persistence.
|
||||||
DEBUG_printf("ble_store_ram_write: CCCD not supported.\n");
|
DEBUG_printf("ble_secret_store_write: CCCD not supported.\n");
|
||||||
// Just pretend we wrote it.
|
// Just pretend we wrote it.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1923,8 +1934,8 @@ STATIC int ble_store_ram_write(int obj_type, const union ble_store_value *val) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
|
STATIC int ble_secret_store_delete(int obj_type, const union ble_store_key *key) {
|
||||||
DEBUG_printf("ble_store_ram_delete: %d\n", obj_type);
|
DEBUG_printf("ble_secret_store_delete: %d\n", obj_type);
|
||||||
switch (obj_type) {
|
switch (obj_type) {
|
||||||
case BLE_STORE_OBJ_TYPE_PEER_SEC:
|
case BLE_STORE_OBJ_TYPE_PEER_SEC:
|
||||||
case BLE_STORE_OBJ_TYPE_OUR_SEC: {
|
case BLE_STORE_OBJ_TYPE_OUR_SEC: {
|
||||||
@ -1938,13 +1949,13 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
|
|||||||
return BLE_HS_ENOENT;
|
return BLE_HS_ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_printf("ble_store_ram_delete: deleted secret\n");
|
DEBUG_printf("ble_secret_store_delete: deleted secret\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case BLE_STORE_OBJ_TYPE_CCCD: {
|
case BLE_STORE_OBJ_TYPE_CCCD: {
|
||||||
// TODO: Implement CCCD persistence.
|
// TODO: Implement CCCD persistence.
|
||||||
DEBUG_printf("ble_store_ram_delete: CCCD not supported.\n");
|
DEBUG_printf("ble_secret_store_delete: CCCD not supported.\n");
|
||||||
// Just pretend it wasn't there.
|
// Just pretend it wasn't there.
|
||||||
return BLE_HS_ENOENT;
|
return BLE_HS_ENOENT;
|
||||||
}
|
}
|
||||||
@ -1953,15 +1964,6 @@ STATIC int ble_store_ram_delete(int obj_type, const union ble_store_key *key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nimble_port_init always calls ble_store_ram_init. We provide this alternative
|
|
||||||
// implementation rather than the one in nimble/store/ram/src/ble_store_ram.c.
|
|
||||||
// TODO: Consider re-implementing nimble_port_init instead.
|
|
||||||
void ble_store_ram_init(void) {
|
|
||||||
ble_hs_cfg.store_read_cb = ble_store_ram_read;
|
|
||||||
ble_hs_cfg.store_write_cb = ble_store_ram_write;
|
|
||||||
ble_hs_cfg.store_delete_cb = ble_store_ram_delete;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
|
||||||
|
|
||||||
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
|
#endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_NIMBLE
|
||||||
|
|||||||
80
extmod/nimble/nimble.cmake
Normal file
80
extmod/nimble/nimble.cmake
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
set(NIMBLE_LIB_DIR "${MICROPY_DIR}/lib/mynewt-nimble")
|
||||||
|
set(NIMBLE_EXTMOD_DIR "${MICROPY_DIR}/extmod/nimble")
|
||||||
|
|
||||||
|
add_library(micropy_extmod_nimble INTERFACE)
|
||||||
|
|
||||||
|
target_include_directories(micropy_extmod_nimble INTERFACE
|
||||||
|
${MICROPY_DIR}/
|
||||||
|
${MICROPY_PORT_DIR}/
|
||||||
|
${NIMBLE_EXTMOD_DIR}/
|
||||||
|
${NIMBLE_LIB_DIR}/
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/services/gap/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/services/gatt/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/store/ram/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/util/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/include
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/transport/uart/include
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(micropy_extmod_nimble INTERFACE
|
||||||
|
${NIMBLE_EXTMOD_DIR}/hal/hal_uart.c
|
||||||
|
${NIMBLE_EXTMOD_DIR}/nimble/nimble_npl_os.c
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/src/aes_encrypt.c
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/src/cmac_mode.c
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc.c
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/src/ecc_dh.c
|
||||||
|
${NIMBLE_LIB_DIR}/ext/tinycrypt/src/utils.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/services/gap/src/ble_svc_gap.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/services/gatt/src/ble_svc_gatt.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_att.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_clt.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_cmd.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_att_svr.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_eddystone.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_gap.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_gattc.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_gatts.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_adv.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_atomic.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_cfg.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_conn.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_flow.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_cmd.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_evt.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_hci_util.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_id.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_log.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mbuf.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_misc.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_mqueue.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_pvcy.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_startup.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_hs_stop.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_ibeacon.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_coc.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_l2cap_sig_cmd.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_monitor.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_alg.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_cmd.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_lgcy.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_sm_sc.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_store.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_store_util.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/src/ble_uuid.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/host/util/src/addr.c
|
||||||
|
${NIMBLE_LIB_DIR}/nimble/transport/uart/src/ble_hci_uart.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/endian.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/mem.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/nimble_port.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/os_mbuf.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/os_mempool.c
|
||||||
|
${NIMBLE_LIB_DIR}/porting/nimble/src/os_msys_init.c
|
||||||
|
)
|
||||||
@ -35,7 +35,11 @@
|
|||||||
// --- Configuration of NimBLE data structures --------------------------------
|
// --- Configuration of NimBLE data structures --------------------------------
|
||||||
|
|
||||||
// This is used at runtime to align allocations correctly.
|
// This is used at runtime to align allocations correctly.
|
||||||
#define BLE_NPL_OS_ALIGNMENT (sizeof(uintptr_t))
|
#if __WORDSIZE == 64
|
||||||
|
#define BLE_NPL_OS_ALIGNMENT 8
|
||||||
|
#else
|
||||||
|
#define BLE_NPL_OS_ALIGNMENT 4
|
||||||
|
#endif
|
||||||
#define BLE_NPL_TIME_FOREVER (0xffffffff)
|
#define BLE_NPL_TIME_FOREVER (0xffffffff)
|
||||||
|
|
||||||
// This is used at compile time to force struct member alignment. See
|
// This is used at compile time to force struct member alignment. See
|
||||||
|
|||||||
@ -57,6 +57,5 @@ try:
|
|||||||
yield core._io_queue.queue_read(self)
|
yield core._io_queue.queue_read(self)
|
||||||
self._flag = 0
|
self._flag = 0
|
||||||
|
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -66,7 +66,7 @@ async def gather(*aws, return_exceptions=False):
|
|||||||
# # cancel all waiting tasks
|
# # cancel all waiting tasks
|
||||||
# raise er
|
# raise er
|
||||||
ts[i] = await ts[i]
|
ts[i] = await ts[i]
|
||||||
except Exception as er:
|
except (core.CancelledError, Exception) as er:
|
||||||
if return_exceptions:
|
if return_exceptions:
|
||||||
ts[i] = er
|
ts[i] = er
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define fsync _commit
|
#define fsync _commit
|
||||||
|
#else
|
||||||
|
#include <poll.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _mp_obj_vfs_posix_file_t {
|
typedef struct _mp_obj_vfs_posix_file_t {
|
||||||
@ -206,6 +208,32 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
|||||||
return 0;
|
return 0;
|
||||||
case MP_STREAM_GET_FILENO:
|
case MP_STREAM_GET_FILENO:
|
||||||
return o->fd;
|
return o->fd;
|
||||||
|
#if MICROPY_PY_USELECT
|
||||||
|
case MP_STREAM_POLL: {
|
||||||
|
#ifdef _WIN32
|
||||||
|
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
|
||||||
|
#else
|
||||||
|
mp_uint_t ret = 0;
|
||||||
|
uint8_t pollevents = 0;
|
||||||
|
if (arg & MP_STREAM_POLL_RD) {
|
||||||
|
pollevents |= POLLIN;
|
||||||
|
}
|
||||||
|
if (arg & MP_STREAM_POLL_WR) {
|
||||||
|
pollevents |= POLLOUT;
|
||||||
|
}
|
||||||
|
struct pollfd pfd = { .fd = o->fd, .events = pollevents };
|
||||||
|
if (poll(&pfd, 1, 0) > 0) {
|
||||||
|
if (pfd.revents & POLLIN) {
|
||||||
|
ret |= MP_STREAM_POLL_RD;
|
||||||
|
}
|
||||||
|
if (pfd.revents & POLLOUT) {
|
||||||
|
ret |= MP_STREAM_POLL_WR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
*errcode = EINVAL;
|
*errcode = EINVAL;
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
|
|||||||
2
lib/asf4
2
lib/asf4
@ -1 +1 @@
|
|||||||
Subproject commit d270f79aa16dd8fd4ae3b6c14544283dcb992e9c
|
Subproject commit 84f56af13292d8f32c40acbd949bde698ddd4507
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 620a3de2408d2ccb283c2e710c77c6cf006b42e3
|
Subproject commit 8d890d834364548f93c5a56797c427625027d7aa
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 97ce3eacaaa79e8ed6cf71717149ced4f5328ee7
|
Subproject commit 42849560ba7906f023f61e5f7ff3709ba2c1dfca
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7
|
Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 302c52794d2f579903f4e49cbad1f5d3a7f401ad
|
Subproject commit c1b7a415778247dd3881a1f3d11ea02190cbc94d
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit d49938d0f5052bce70e55c652b657c0a6a7e84fe
|
Subproject commit 4bfab30c02279a0530e1a56f4a7c539f2d35a293
|
||||||
@ -17,10 +17,7 @@ by the target MicroPython runtime (eg onto a pyboard's filesystem), and then
|
|||||||
imported like any other Python module using `import foo`.
|
imported like any other Python module using `import foo`.
|
||||||
|
|
||||||
Different target runtimes may require a different format of the compiled
|
Different target runtimes may require a different format of the compiled
|
||||||
bytecode, and such options can be passed to the cross compiler. For example,
|
bytecode, and such options can be passed to the cross compiler.
|
||||||
the unix port of MicroPython requires the following:
|
|
||||||
|
|
||||||
$ ./mpy-cross -mcache-lookup-bc foo.py
|
|
||||||
|
|
||||||
If the Python code contains `@native` or `@viper` annotations, then you must
|
If the Python code contains `@native` or `@viper` annotations, then you must
|
||||||
specify `-march` to match the target architecture.
|
specify `-march` to match the target architecture.
|
||||||
|
|||||||
@ -108,7 +108,6 @@ STATIC int usage(char **argv) {
|
|||||||
"Target specific options:\n"
|
"Target specific options:\n"
|
||||||
"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
|
"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
|
||||||
"-mno-unicode : don't support unicode in compiled strings\n"
|
"-mno-unicode : don't support unicode in compiled strings\n"
|
||||||
"-mcache-lookup-bc : cache map lookups in the bytecode\n"
|
|
||||||
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
|
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Implementation specific options:\n", argv[0]
|
"Implementation specific options:\n", argv[0]
|
||||||
@ -193,8 +192,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
set_fmode_binary();
|
set_fmode_binary();
|
||||||
#endif
|
#endif
|
||||||
mp_obj_list_init(mp_sys_path, 0);
|
|
||||||
mp_obj_list_init(mp_sys_argv, 0);
|
|
||||||
|
|
||||||
#if MICROPY_EMIT_NATIVE
|
#if MICROPY_EMIT_NATIVE
|
||||||
// Set default emitter options
|
// Set default emitter options
|
||||||
@ -205,7 +202,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
|||||||
|
|
||||||
// set default compiler configuration
|
// set default compiler configuration
|
||||||
mp_dynamic_compiler.small_int_bits = 31;
|
mp_dynamic_compiler.small_int_bits = 31;
|
||||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
|
|
||||||
mp_dynamic_compiler.py_builtins_str_unicode = 1;
|
mp_dynamic_compiler.py_builtins_str_unicode = 1;
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
|
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
|
||||||
@ -264,10 +260,6 @@ MP_NOINLINE int main_(int argc, char **argv) {
|
|||||||
return usage(argv);
|
return usage(argv);
|
||||||
}
|
}
|
||||||
// TODO check that small_int_bits is within range of host's capabilities
|
// TODO check that small_int_bits is within range of host's capabilities
|
||||||
} else if (strcmp(argv[a], "-mno-cache-lookup-bc") == 0) {
|
|
||||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 0;
|
|
||||||
} else if (strcmp(argv[a], "-mcache-lookup-bc") == 0) {
|
|
||||||
mp_dynamic_compiler.opt_cache_map_lookup_in_bytecode = 1;
|
|
||||||
} else if (strcmp(argv[a], "-mno-unicode") == 0) {
|
} else if (strcmp(argv[a], "-mno-unicode") == 0) {
|
||||||
mp_dynamic_compiler.py_builtins_str_unicode = 0;
|
mp_dynamic_compiler.py_builtins_str_unicode = 0;
|
||||||
} else if (strcmp(argv[a], "-municode") == 0) {
|
} else if (strcmp(argv[a], "-municode") == 0) {
|
||||||
|
|||||||
@ -57,8 +57,6 @@
|
|||||||
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1)
|
||||||
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
#define MICROPY_COMP_RETURN_IF_EXPR (1)
|
||||||
|
|
||||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
|
||||||
|
|
||||||
#define MICROPY_READER_POSIX (1)
|
#define MICROPY_READER_POSIX (1)
|
||||||
#define MICROPY_ENABLE_RUNTIME (0)
|
#define MICROPY_ENABLE_RUNTIME (0)
|
||||||
#define MICROPY_ENABLE_GC (1)
|
#define MICROPY_ENABLE_GC (1)
|
||||||
|
|||||||
@ -18,4 +18,4 @@ compiled and executed when the firmware starts. They produce output on the
|
|||||||
system's stdout.
|
system's stdout.
|
||||||
|
|
||||||
The size of the firmware (the machine code that is programmed to the
|
The size of the firmware (the machine code that is programmed to the
|
||||||
microcontroller's flash/ROM) is currently around 57900 bytes.
|
microcontroller's flash/ROM) is currently around 56500 bytes.
|
||||||
|
|||||||
@ -28,38 +28,14 @@
|
|||||||
|
|
||||||
// Options to control how MicroPython is built
|
// Options to control how MicroPython is built
|
||||||
|
|
||||||
// Memory allocation policy
|
// Use the minimal starting configuration (disables all optional features).
|
||||||
#define MICROPY_QSTR_BYTES_IN_HASH (1)
|
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM)
|
||||||
|
|
||||||
// Compiler configuration
|
// Compiler configuration
|
||||||
#define MICROPY_COMP_CONST (0)
|
#define MICROPY_ENABLE_COMPILER (1)
|
||||||
#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0)
|
|
||||||
|
|
||||||
// Python internal features
|
// Python internal features
|
||||||
#define MICROPY_ENABLE_EXTERNAL_IMPORT (0)
|
|
||||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NONE)
|
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NONE)
|
||||||
#define MICROPY_CPYTHON_COMPAT (0)
|
|
||||||
#define MICROPY_MODULE_GETATTR (0)
|
|
||||||
#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
|
|
||||||
|
|
||||||
// Fine control over Python builtins, classes, modules, etc
|
|
||||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
|
||||||
#define MICROPY_PY_ASSIGN_EXPR (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_STR_COUNT (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_STR_OP_MODULO (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_DICT_FROMKEYS (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_SET (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_SLICE (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_PROPERTY (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_ENUMERATE (0)
|
|
||||||
#define MICROPY_PY_BUILTINS_REVERSED (0)
|
|
||||||
#define MICROPY_PY___FILE__ (0)
|
|
||||||
#define MICROPY_PY_ARRAY (0)
|
|
||||||
#define MICROPY_PY_COLLECTIONS (0)
|
|
||||||
#define MICROPY_PY_IO (0)
|
|
||||||
#define MICROPY_PY_STRUCT (0)
|
|
||||||
#define MICROPY_PY_SYS (0)
|
|
||||||
|
|
||||||
// Type definitions for the specific machine
|
// Type definitions for the specific machine
|
||||||
|
|
||||||
|
|||||||
23
ports/cc3200/boards/WIPY/board.json
Normal file
23
ports/cc3200/boards/WIPY/board.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"deploy": [
|
||||||
|
"deploy.md"
|
||||||
|
],
|
||||||
|
"docs": "https://docs.pycom.io/datasheets/development/wipy3/",
|
||||||
|
"features": [
|
||||||
|
"BLE",
|
||||||
|
"Breadboard Friendly",
|
||||||
|
"MicroSD",
|
||||||
|
"RGB LED",
|
||||||
|
"SPI Flash",
|
||||||
|
"WiFi"
|
||||||
|
],
|
||||||
|
"id": "wipy",
|
||||||
|
"images": [
|
||||||
|
"wipy.jpg"
|
||||||
|
],
|
||||||
|
"mcu": "cc3200",
|
||||||
|
"product": "WiPy Module",
|
||||||
|
"thumbnail": "",
|
||||||
|
"url": "https://pycom.io/product/wipy-3-0/",
|
||||||
|
"vendor": "Pycom"
|
||||||
|
}
|
||||||
2
ports/cc3200/boards/WIPY/deploy.md
Normal file
2
ports/cc3200/boards/WIPY/deploy.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
The following files are firmware for the WiPy. The zip file contains mcuimg.bin
|
||||||
|
which should be copied via ftp to the /flash/sys directory on the WiPy.
|
||||||
@ -53,7 +53,6 @@
|
|||||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||||
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
#define MICROPY_OPT_COMPUTED_GOTO (0)
|
||||||
#define MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE (0)
|
|
||||||
#define MICROPY_READER_VFS (1)
|
#define MICROPY_READER_VFS (1)
|
||||||
#ifndef DEBUG // we need ram on the launchxl while debugging
|
#ifndef DEBUG // we need ram on the launchxl while debugging
|
||||||
#define MICROPY_CPYTHON_COMPAT (1)
|
#define MICROPY_CPYTHON_COMPAT (1)
|
||||||
|
|||||||
@ -99,8 +99,8 @@ OsiTaskHandle svTaskHandle;
|
|||||||
static fs_user_mount_t *sflash_vfs_fat;
|
static fs_user_mount_t *sflash_vfs_fat;
|
||||||
|
|
||||||
static const char fresh_main_py[] = "# main.py -- put your code here!\r\n";
|
static const char fresh_main_py[] = "# main.py -- put your code here!\r\n";
|
||||||
static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n"
|
static const char fresh_boot_py[] = "# boot.py -- run on boot to configure USB and filesystem\r\n"
|
||||||
"# can run arbitrary Python, but best to keep it minimal\r\n"
|
"# Put app code in main.py\r\n"
|
||||||
#if MICROPY_STDIO_UART
|
#if MICROPY_STDIO_UART
|
||||||
"import os, machine\r\n"
|
"import os, machine\r\n"
|
||||||
"os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n"
|
"os.dupterm(machine.UART(0, " MP_STRINGIFY(MICROPY_STDIO_UART_BAUD) "))\r\n"
|
||||||
@ -139,9 +139,6 @@ soft_reset:
|
|||||||
|
|
||||||
// MicroPython init
|
// MicroPython init
|
||||||
mp_init();
|
mp_init();
|
||||||
mp_obj_list_init(mp_sys_path, 0);
|
|
||||||
mp_obj_list_init(mp_sys_argv, 0);
|
|
||||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
|
||||||
|
|
||||||
// execute all basic initializations
|
// execute all basic initializations
|
||||||
mp_irq_init0();
|
mp_irq_init0();
|
||||||
|
|||||||
@ -75,6 +75,12 @@ $ source export.sh # (or export.bat on Windows)
|
|||||||
The `install.sh` step only needs to be done once. You will need to source
|
The `install.sh` step only needs to be done once. You will need to source
|
||||||
`export.sh` for every new session.
|
`export.sh` for every new session.
|
||||||
|
|
||||||
|
**Note:** If you are building MicroPython for the ESP32-S2, ESP32-C3 or ESP32-S3,
|
||||||
|
please ensure you are using the following required IDF versions:
|
||||||
|
- ESP32-S3 currently requires latest `master`, but eventually `v4.4` or later when
|
||||||
|
it's available.
|
||||||
|
- ESP32-S2 and ESP32-C3 require `v4.3.1` or later.
|
||||||
|
|
||||||
Building the firmware
|
Building the firmware
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|||||||
19
ports/esp32/boards/ESP32_S2_WROVER/board.json
Normal file
19
ports/esp32/boards/ESP32_S2_WROVER/board.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"deploy": [
|
||||||
|
"../deploy_s2.md"
|
||||||
|
],
|
||||||
|
"docs": "",
|
||||||
|
"features": [
|
||||||
|
"BLE",
|
||||||
|
"SPIRAM",
|
||||||
|
"WiFi"
|
||||||
|
],
|
||||||
|
"images": [
|
||||||
|
"ESP32-S2-WROVER_L_0.jpg"
|
||||||
|
],
|
||||||
|
"mcu": "esp32s2",
|
||||||
|
"product": "ESP32-S2 WROVER",
|
||||||
|
"thumbnail": "",
|
||||||
|
"url": "https://www.espressif.com/en/products/modules",
|
||||||
|
"vendor": "Espressif"
|
||||||
|
}
|
||||||
12
ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake
Normal file
12
ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.cmake
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
set(IDF_TARGET esp32s2)
|
||||||
|
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.spiram_sx
|
||||||
|
boards/sdkconfig.usb
|
||||||
|
boards/ESP32_S2_WROVER/sdkconfig.board
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MICROPY_FROZEN_MANIFEST)
|
||||||
|
set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
|
||||||
|
endif()
|
||||||
8
ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
Normal file
8
ports/esp32/boards/ESP32_S2_WROVER/mpconfigboard.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#define MICROPY_HW_BOARD_NAME "ESP32-S2-WROVER"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32-S2"
|
||||||
|
|
||||||
|
#define MICROPY_PY_BLUETOOTH (0)
|
||||||
|
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||||
|
|
||||||
|
#define MICROPY_HW_I2C0_SCL (7)
|
||||||
|
#define MICROPY_HW_I2C0_SDA (6)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user