Compare commits
7 Commits
mbl-next
...
ccdecf255d
| Author | SHA1 | Date | |
|---|---|---|---|
| ccdecf255d | |||
|
|
a792c8f3bf | ||
|
|
f4ff9dac89 | ||
|
|
fb05f048e9 | ||
|
|
f6a4651af9 | ||
| 33dc78967d | |||
| 074dd7ac06 |
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
@@ -5,8 +5,6 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- docs/**
|
||||
- py/**
|
||||
- tests/cpydiff/**
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -21,7 +19,5 @@ jobs:
|
||||
- uses: actions/setup-python@v5
|
||||
- name: Install Python packages
|
||||
run: pip install -r docs/requirements.txt
|
||||
- name: Build unix port
|
||||
run: source tools/ci.sh && ci_unix_build_helper
|
||||
- name: Build docs
|
||||
run: make -C docs/ html
|
||||
|
||||
1
.github/workflows/ports_esp32.yml
vendored
1
.github/workflows/ports_esp32.yml
vendored
@@ -25,7 +25,6 @@ jobs:
|
||||
ci_func: # names are functions in ci.sh
|
||||
- esp32_build_cmod_spiram_s2
|
||||
- esp32_build_s3_c3
|
||||
- esp32_build_c2_c6
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
11
.github/workflows/ports_qemu.yml
vendored
11
.github/workflows/ports_qemu.yml
vendored
@@ -20,20 +20,13 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
build_and_test_arm:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
ci_func: # names are functions in ci.sh
|
||||
- bigendian
|
||||
- sabrelite
|
||||
- thumb
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_qemu_setup_arm
|
||||
- name: Build and run test suite ci_qemu_build_arm_${{ matrix.ci_func }}
|
||||
run: source tools/ci.sh && ci_qemu_build_arm_${{ matrix.ci_func }}
|
||||
- name: Build and run test suite
|
||||
run: source tools/ci.sh && ci_qemu_build_arm
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
98
.github/workflows/ports_unix.yml
vendored
98
.github/workflows/ports_unix.yml
vendored
@@ -71,11 +71,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
|
||||
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_coverage_setup
|
||||
- name: Build
|
||||
@@ -134,20 +129,6 @@ jobs:
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
longlong:
|
||||
runs-on: ubuntu-22.04 # use 22.04 to get python2, and libffi-dev:i386
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_32bit_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_longlong_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_longlong_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
float:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -160,18 +141,6 @@ jobs:
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
gil_enabled:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_gil_enabled_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_gil_enabled_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
stackless_clang:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -200,6 +169,23 @@ jobs:
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
settrace:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
|
||||
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_settrace_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_settrace_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
settrace_stackless:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -276,53 +262,3 @@ jobs:
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
sanitize_address:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
|
||||
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_coverage_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_sanitize_address_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_sanitize_address_run_tests
|
||||
- name: Test merging .mpy files
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests
|
||||
- name: Build native mpy modules
|
||||
run: source tools/ci.sh && ci_native_mpy_modules_build
|
||||
- name: Test importing .mpy generated by mpy_ld.py
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
sanitize_undefined:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
# Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests.
|
||||
# Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default.
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_coverage_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_sanitize_undefined_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_sanitize_undefined_run_tests
|
||||
- name: Test merging .mpy files
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests
|
||||
- name: Build native mpy modules
|
||||
run: source tools/ci.sh && ci_native_mpy_modules_build
|
||||
- name: Test importing .mpy generated by mpy_ld.py
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests.py --print-failures
|
||||
|
||||
17
.github/workflows/ports_windows.yml
vendored
17
.github/workflows/ports_windows.yml
vendored
@@ -28,10 +28,13 @@ jobs:
|
||||
visualstudio: ['2017', '2019', '2022']
|
||||
include:
|
||||
- visualstudio: '2017'
|
||||
runner: windows-latest
|
||||
vs_version: '[15, 16)'
|
||||
- visualstudio: '2019'
|
||||
runner: windows-2019
|
||||
vs_version: '[16, 17)'
|
||||
- visualstudio: '2022'
|
||||
runner: windows-2022
|
||||
vs_version: '[17, 18)'
|
||||
# trim down the number of jobs in the matrix
|
||||
exclude:
|
||||
@@ -39,9 +42,9 @@ jobs:
|
||||
configuration: Debug
|
||||
- visualstudio: '2019'
|
||||
configuration: Debug
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CI_BUILD_CONFIGURATION: ${{ matrix.configuration }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
- name: Install Visual Studio 2017
|
||||
if: matrix.visualstudio == '2017'
|
||||
@@ -49,15 +52,13 @@ jobs:
|
||||
choco install visualstudio2017buildtools
|
||||
choco install visualstudio2017-workload-vctools
|
||||
choco install windows-sdk-8.1
|
||||
- name: Install Visual Studio 2019
|
||||
if: matrix.visualstudio == '2019'
|
||||
run: |
|
||||
choco install visualstudio2019buildtools
|
||||
choco install visualstudio2019-workload-vctools
|
||||
choco install windows-sdk-8.1
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: ${{ matrix.vs_version }}
|
||||
- uses: actions/setup-python@v5
|
||||
if: matrix.runner == 'windows-2019'
|
||||
with:
|
||||
python-version: '3.9'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build mpy-cross.exe
|
||||
run: msbuild mpy-cross\mpy-cross.vcxproj -maxcpucount -property:Configuration=${{ matrix.configuration }} -property:Platform=${{ matrix.platform }}
|
||||
@@ -102,7 +103,7 @@ jobs:
|
||||
env: i686
|
||||
- sys: mingw64
|
||||
env: x86_64
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
CHERE_INVOKING: enabled_from_arguments
|
||||
defaults:
|
||||
|
||||
4
.github/workflows/ruff.yml
vendored
4
.github/workflows/ruff.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# ruff version should be kept in sync with .pre-commit-config.yaml & also micropython-lib
|
||||
- run: pipx install ruff==0.11.6
|
||||
# ruff version should be kept in sync with .pre-commit-config.yaml
|
||||
- run: pipx install ruff==0.9.6
|
||||
- run: ruff check --output-format=github .
|
||||
- run: ruff format --diff .
|
||||
|
||||
@@ -12,8 +12,8 @@ repos:
|
||||
verbose: true
|
||||
stages: [commit-msg]
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Version should be kept in sync with .github/workflows/ruff.yml & also micropython-lib
|
||||
rev: v0.11.6
|
||||
# Version should be kept in sync with .github/workflows/ruff.yml
|
||||
rev: v0.9.6
|
||||
hooks:
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
|
||||
@@ -206,21 +206,14 @@ adhere to the existing style and use `tools/codeformat.py` to check any changes.
|
||||
The main conventions, and things not enforceable via the auto-formatter, are
|
||||
described below.
|
||||
|
||||
As the MicroPython code base is over ten years old, not every source file
|
||||
conforms fully to these conventions. If making small changes to existing code,
|
||||
then it's usually acceptable to follow the existing code's style. New code or
|
||||
major changes should follow the conventions described here.
|
||||
|
||||
## White space
|
||||
|
||||
White space:
|
||||
- Expand tabs to 4 spaces.
|
||||
- Don't leave trailing whitespace at the end of a line.
|
||||
- For control blocks (if, for, while), put 1 space between the
|
||||
keyword and the opening parenthesis.
|
||||
- Put 1 space after a comma, and 1 space around operators.
|
||||
|
||||
## Braces
|
||||
|
||||
Braces:
|
||||
- Use braces for all blocks, even no-line and single-line pieces of
|
||||
code.
|
||||
- Put opening braces on the end of the line it belongs to, not on
|
||||
@@ -228,43 +221,18 @@ major changes should follow the conventions described here.
|
||||
- For else-statements, put the else on the same line as the previous
|
||||
closing brace.
|
||||
|
||||
## Header files
|
||||
|
||||
Header files:
|
||||
- Header files should be protected from multiple inclusion with #if
|
||||
directives. See an existing header for naming convention.
|
||||
|
||||
## Names
|
||||
|
||||
Names:
|
||||
- Use underscore_case, not camelCase for all names.
|
||||
- Use CAPS_WITH_UNDERSCORE for enums and macros.
|
||||
- When defining a type use underscore_case and put '_t' after it.
|
||||
|
||||
### Public names (declared in headers)
|
||||
|
||||
- MicroPython-specific names (especially any declared in `py/` and `extmod/`
|
||||
directories) should generally start with `mp_` or `MP_`.
|
||||
- Functions and variables declared in a header should generally share a longer
|
||||
common prefix. Usually the prefix matches the file name (i.e. items defined in
|
||||
`py/obj.c` are declared in `py/obj.h` and should be prefixed `mp_obj_`). There
|
||||
are exceptions, for example where one header file contains declarations
|
||||
implemented in multiple source files for expediency.
|
||||
|
||||
### Private names (specific to a single .c file)
|
||||
|
||||
- For static functions and variables exposed to Python (i.e. a static C function
|
||||
that is wrapped in `MP_DEFINE_CONST_FUN_...` and attached to a module), use
|
||||
the file-level shared common prefix, i.e. name them as if the function or
|
||||
variable was not static.
|
||||
- Other static definitions in source files (i.e. functions or variables defined
|
||||
in a .c file that are only used within that .c file) don't need any prefix
|
||||
(specifically: no `s_` or `_` prefix, and generally avoid adding the
|
||||
file-level common prefix).
|
||||
|
||||
## Integer types
|
||||
|
||||
MicroPython runs on 16, 32, and 64 bit machines, so it's important to use the
|
||||
correctly-sized (and signed) integer types. The general guidelines are:
|
||||
|
||||
Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's
|
||||
important to use the correctly-sized (and signed) integer types. The
|
||||
general guidelines are:
|
||||
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
|
||||
integer values. These are guaranteed to be machine-word sized and
|
||||
therefore big enough to hold the value from a MicroPython small-int
|
||||
@@ -273,13 +241,11 @@ correctly-sized (and signed) integer types. The general guidelines are:
|
||||
- You can use int/uint, but remember that they may be 16-bits wide.
|
||||
- If in doubt, use mp_int_t/mp_uint_t.
|
||||
|
||||
## Comments
|
||||
|
||||
Comments:
|
||||
- Be concise and only write comments for things that are not obvious.
|
||||
- Use `// ` prefix, NOT `/* ... */`. No extra fluff.
|
||||
|
||||
## Memory allocation
|
||||
|
||||
Memory allocation:
|
||||
- Use m_new, m_renew, m_del (and friends) to allocate and free heap memory.
|
||||
These macros are defined in py/misc.h.
|
||||
|
||||
|
||||
@@ -67,9 +67,6 @@ The known limitations are:
|
||||
|
||||
* static BSS variables are not supported; workaround: use global BSS variables
|
||||
|
||||
* thread-local storage variables are not supported on rv32imc; workaround: use
|
||||
global BSS variables or allocate some space on the heap to store them
|
||||
|
||||
So, if your C code has writable data, make sure the data is defined globally,
|
||||
without an initialiser, and only written to within functions.
|
||||
|
||||
@@ -84,14 +81,7 @@ Linker limitation: the native module is not linked against the symbol table of t
|
||||
full MicroPython firmware. Rather, it is linked against an explicit table of exported
|
||||
symbols found in ``mp_fun_table`` (in ``py/nativeglue.h``), that is fixed at firmware
|
||||
build time. It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system
|
||||
function, for example, unless that resides at a fixed address. In that case, the path
|
||||
of a linkerscript containing a series of symbol names and their fixed address can be
|
||||
passed to ``mpy_ld.py`` via the ``--externs`` command line argument. That way symbols
|
||||
appearing in the linkerscript will take precedence over what is provided from object
|
||||
files, but at the moment the object files' implementation will still reside in the
|
||||
final MPY file. The linkerscript parser is limited in its capabilities, and is
|
||||
currently used only for parsing the ESP8266 port ROM symbols list (see
|
||||
``ports/esp8266/boards/eagle.rom.addr.v6.ld``).
|
||||
function, for example.
|
||||
|
||||
New symbols can be added to the end of the table and the firmware rebuilt.
|
||||
The symbols also need to be added to ``tools/mpy_ld.py``'s ``fun_table`` dict in the
|
||||
@@ -228,26 +218,6 @@ other module, for example::
|
||||
print(factorial.factorial(10))
|
||||
# should display 3628800
|
||||
|
||||
Using Picolibc when building modules
|
||||
------------------------------------
|
||||
|
||||
Using `Picolibc <https://github.com/picolibc/picolibc>`_ as your C standard
|
||||
library is not only supported, but in fact it is the default for the rv32imc
|
||||
platform. However, there are a couple of things worth mentioning to make sure
|
||||
you don't run into problems later when building code.
|
||||
|
||||
Some pre-built Picolibc versions (for example, those provided by Ubuntu Linux
|
||||
as the ``picolibc-arm-none-eabi``, ``picolibc-riscv64-unknown-elf``, and
|
||||
``picolibc-xtensa-lx106-elf`` packages) assume thread-local storage (TLS) is
|
||||
available at runtime, but unfortunately MicroPython modules do not support that
|
||||
on some architectures (namely ``rv32imc``). This means that some
|
||||
functionalities provided by Picolibc will default to use TLS, returning an
|
||||
error either during compilation or during linking.
|
||||
|
||||
For an example on how this may affect you, the ``examples/natmod/btree``
|
||||
example module contains a workaround to make sure ``errno`` works (look for
|
||||
``__PICOLIBC_ERRNO_FUNCTION`` in the Makefile and follow the trail from there).
|
||||
|
||||
Further examples
|
||||
----------------
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ Python 3.6 beta 1 was released on 12 Sep 2016, and a summary of the new 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 | Partial |
|
||||
| | | [#setname]_ |
|
||||
| `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 | |
|
||||
+--------------------------------------------------------+--------------------------------------------------+-----------------+
|
||||
@@ -199,7 +198,3 @@ Changes to built-in modules:
|
||||
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||
| The *compress()* and *decompress()* functions now accept keyword arguments | |
|
||||
+--------------------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
.. rubric:: Notes
|
||||
|
||||
.. [#setname] Currently, only :func:`__set_name__` is implemented.
|
||||
|
||||
@@ -148,7 +148,6 @@ Required keyword arguments for the constructor:
|
||||
- ``mdc`` and ``mdio`` - :class:`machine.Pin` objects (or integers) specifying
|
||||
the MDC and MDIO pins.
|
||||
- ``phy_type`` - Select the PHY device type. Supported devices are
|
||||
``PHY_GENERIC``,
|
||||
``PHY_LAN8710``, ``PHY_LAN8720``, ``PHY_IP101``, ``PHY_RTL8201``,
|
||||
``PHY_DP83848``, ``PHY_KSZ8041`` and ``PHY_KSZ8081``. These values are all
|
||||
constants defined in the ``network`` module.
|
||||
@@ -271,10 +270,8 @@ Use the :mod:`time <time>` module::
|
||||
Timers
|
||||
------
|
||||
|
||||
The ESP32 port has one, two or four hardware timers, depending on the ESP32 device type.
|
||||
There is 1 timer for ESP32C2, 2 timers for ESP32C4, ESP32C6 and ESP32H4, and
|
||||
4 timers otherwise. Use the :ref:`machine.Timer <machine.Timer>` class
|
||||
with a timer ID of 0, 0 and 1, or from 0 to 3 (inclusive)::
|
||||
The ESP32 port has four hardware timers. Use the :ref:`machine.Timer <machine.Timer>` class
|
||||
with a timer ID from 0 to 3 (inclusive)::
|
||||
|
||||
from machine import Timer
|
||||
|
||||
@@ -284,8 +281,7 @@ with a timer ID of 0, 0 and 1, or from 0 to 3 (inclusive)::
|
||||
tim1 = Timer(1)
|
||||
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))
|
||||
|
||||
The period is in milliseconds. When using UART.IRQ_RXIDLE, timer 0 is needed for
|
||||
the IRQ_RXIDLE mechanism and must not be used otherwise.
|
||||
The period is in milliseconds.
|
||||
|
||||
Virtual timers are not currently supported on this port.
|
||||
|
||||
@@ -387,7 +383,7 @@ for more details.
|
||||
|
||||
Use the :ref:`machine.PWM <machine.PWM>` class::
|
||||
|
||||
from machine import Pin, PWM, lightsleep
|
||||
from machine import Pin, PWM
|
||||
|
||||
pwm0 = PWM(Pin(0), freq=5000, duty_u16=32768) # create PWM object from a pin
|
||||
freq = pwm0.freq() # get current frequency
|
||||
@@ -397,7 +393,7 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
|
||||
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(65536*3//4) # set duty cycle from 0 to 65535 as a ratio duty_u16/65535, (now 75%)
|
||||
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%)
|
||||
@@ -406,35 +402,19 @@ Use the :ref:`machine.PWM <machine.PWM>` class::
|
||||
|
||||
pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
|
||||
print(pwm2) # view PWM settings
|
||||
pwm2.deinit() # turn off PWM on the pin
|
||||
|
||||
pwm0 = PWM(Pin(0), duty_u16=16384) # The output is at a high level 25% of the time.
|
||||
pwm2 = PWM(Pin(2), duty_u16=16384, invert=1) # The output is at a low level 25% of the time.
|
||||
|
||||
pwm4 = PWM(Pin(4), lightsleep=True) # Allow PWM during light sleep mode
|
||||
|
||||
lightsleep(10*1000) # pwm0, pwm2 goes off, pwm4 stays on during 10s light sleep
|
||||
# pwm0, pwm2, pwm4 on after 10s light sleep
|
||||
|
||||
ESP chips have different hardware peripherals:
|
||||
|
||||
======================================================= ======== ========= ==========
|
||||
Hardware specification ESP32 ESP32-S2, ESP32-C2,
|
||||
ESP32-S3, ESP32-C3,
|
||||
ESP32-P4 ESP32-C5,
|
||||
ESP32-C6,
|
||||
ESP32-H2
|
||||
------------------------------------------------------- -------- --------- ----------
|
||||
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
|
||||
======================================================= ======== ========= ==========
|
||||
|
||||
In light sleep, the ESP32 PWM can only operate in low speed mode, so only 4 timers and
|
||||
8 channels are available.
|
||||
===================================================== ======== ======== ========
|
||||
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
|
||||
@@ -544,63 +524,14 @@ Legacy methods:
|
||||
|
||||
Equivalent to ``ADC.block().init(bits=bits)``.
|
||||
|
||||
The only chip that can switch resolution to a lower one is the normal esp32.
|
||||
The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits.
|
||||
|
||||
For compatibility, the ``ADC`` object also provides constants matching the
|
||||
supported ADC resolutions, per chip:
|
||||
supported ADC resolutions:
|
||||
|
||||
ESP32:
|
||||
- ``ADC.WIDTH_9BIT`` = 9
|
||||
- ``ADC.WIDTH_10BIT`` = 10
|
||||
- ``ADC.WIDTH_11BIT`` = 11
|
||||
- ``ADC.WIDTH_12BIT`` = 12
|
||||
|
||||
ESP32 C3 & S3:
|
||||
- ``ADC.WIDTH_12BIT`` = 12
|
||||
|
||||
ESP32 S2:
|
||||
- ``ADC.WIDTH_13BIT`` = 13
|
||||
|
||||
.. method:: ADC.deinit()
|
||||
|
||||
Provided to deinit the adc driver.
|
||||
|
||||
Pulse Counter (pin pulse/edge counting)
|
||||
---------------------------------------
|
||||
|
||||
The ESP32 provides up to 8 pulse counter peripherals depending on the hardware,
|
||||
with id 0..7. These can be configured to count rising and/or falling edges on
|
||||
any input pin.
|
||||
|
||||
Use the :ref:`esp32.PCNT <esp32.PCNT>` class::
|
||||
|
||||
from machine import Pin
|
||||
from esp32 import PCNT
|
||||
|
||||
counter = PCNT(0, pin=Pin(2), rising=PCNT.INCREMENT) # create counter
|
||||
counter.start() # start counter
|
||||
count = counter.value() # read count, -32768..32767
|
||||
counter.value(0) # reset counter
|
||||
count = counter.value(0) # read and reset
|
||||
|
||||
The PCNT hardware supports monitoring multiple pins in a single unit to
|
||||
implement quadrature decoding or up/down signal counters.
|
||||
|
||||
See the :ref:`machine.Counter <machine.Counter>` and
|
||||
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
|
||||
common pulse counting applications::
|
||||
|
||||
from machine import Pin, Counter
|
||||
|
||||
counter = Counter(0, Pin(2)) # create a counter as above and start it
|
||||
count = counter.value() # read the count as an arbitrary precision signed integer
|
||||
|
||||
encoder = Encoder(0, Pin(12), Pin(14)) # create an encoder and begin counting
|
||||
count = encoder.value() # read the count as an arbitrary precision signed integer
|
||||
|
||||
Note that the id passed to these ``Counter()`` and ``Encoder()`` objects must be
|
||||
a PCNT id.
|
||||
|
||||
Software SPI bus
|
||||
----------------
|
||||
@@ -838,9 +769,6 @@ The RMT is ESP32-specific and allows generation of accurate digital pulses with
|
||||
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
||||
r.write_pulses((1, 20, 2, 40), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||
|
||||
The ESP32-C2 family does not include any RMT peripheral, so this class is
|
||||
unavailable on those SoCs.
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
||||
|
||||
@@ -11,20 +11,16 @@ 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**::
|
||||
* More comprehensive example with all 16 PWM channels and 8 timers::
|
||||
|
||||
from time import sleep
|
||||
from machine import Pin, PWM
|
||||
try:
|
||||
F = 10000 # Hz
|
||||
D = 65536 // 16 # 6.25%
|
||||
pins = (2, 4, 12, 13, 14, 15, 16, 18, 19, 22, 23, 25, 26, 27, 32, 33)
|
||||
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):
|
||||
f = F * (i // 2 + 1)
|
||||
d = min(65535, D * (i + 1))
|
||||
pwms.append(PWM(pin, freq=f, duty_u16=d))
|
||||
sleep(2 / f)
|
||||
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:
|
||||
@@ -35,100 +31,65 @@ low all of the time.
|
||||
|
||||
Output is::
|
||||
|
||||
PWM(Pin(2), freq=10000, duty_u16=4096)
|
||||
PWM(Pin(4), freq=10000, duty_u16=8192)
|
||||
PWM(Pin(12), freq=20000, duty_u16=12288)
|
||||
PWM(Pin(13), freq=20000, duty_u16=16384)
|
||||
PWM(Pin(14), freq=30030, duty_u16=20480)
|
||||
PWM(Pin(15), freq=30030, duty_u16=24576)
|
||||
PWM(Pin(16), freq=40000, duty_u16=28672)
|
||||
PWM(Pin(18), freq=40000, duty_u16=32768)
|
||||
PWM(Pin(19), freq=50000, duty_u16=36864)
|
||||
PWM(Pin(22), freq=50000, duty_u16=40960)
|
||||
PWM(Pin(23), freq=60060, duty_u16=45056)
|
||||
PWM(Pin(25), freq=60060, duty_u16=49152)
|
||||
PWM(Pin(26), freq=69930, duty_u16=53248)
|
||||
PWM(Pin(27), freq=69930, duty_u16=57344)
|
||||
PWM(Pin(32), freq=80000, duty_u16=61440)
|
||||
PWM(Pin(33), freq=80000, duty_u16=65535)
|
||||
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**::
|
||||
* Example of a smooth frequency change::
|
||||
|
||||
from time import sleep
|
||||
from machine import Pin, PWM
|
||||
|
||||
F_MIN = 1000
|
||||
F_MAX = 10000
|
||||
F_MIN = 500
|
||||
F_MAX = 1000
|
||||
|
||||
f = F_MIN
|
||||
delta_f = F_MAX // 50
|
||||
delta_f = 1
|
||||
|
||||
pwm = PWM(Pin(27), f)
|
||||
p = PWM(Pin(5), f)
|
||||
print(p)
|
||||
|
||||
while True:
|
||||
pwm.freq(f)
|
||||
sleep(1 / f)
|
||||
sleep(0.1)
|
||||
print(pwm)
|
||||
p.freq(f)
|
||||
|
||||
sleep(10 / F_MIN)
|
||||
|
||||
f += delta_f
|
||||
if f > F_MAX or f < F_MIN:
|
||||
if f >= F_MAX or f <= F_MIN:
|
||||
delta_f = -delta_f
|
||||
print()
|
||||
if f > F_MAX:
|
||||
f = F_MAX
|
||||
elif f < F_MIN:
|
||||
f = F_MIN
|
||||
|
||||
See PWM wave on Pin(27) with an oscilloscope.
|
||||
See PWM wave at Pin(5) with an oscilloscope.
|
||||
|
||||
Output is::
|
||||
|
||||
PWM(Pin(27), freq=998, duty_u16=32768)
|
||||
PWM(Pin(27), freq=1202, duty_u16=32768)
|
||||
PWM(Pin(27), freq=1401, duty_u16=32768)
|
||||
PWM(Pin(27), freq=1598, duty_u16=32768)
|
||||
...
|
||||
PWM(Pin(27), freq=9398, duty_u16=32768)
|
||||
PWM(Pin(27), freq=9615, duty_u16=32768)
|
||||
PWM(Pin(27), freq=9804, duty_u16=32768)
|
||||
PWM(Pin(27), freq=10000, duty_u16=32768)
|
||||
|
||||
PWM(Pin(27), freq=10000, duty_u16=32768)
|
||||
PWM(Pin(27), freq=9804, duty_u16=32768)
|
||||
PWM(Pin(27), freq=9615, duty_u16=32768)
|
||||
PWM(Pin(27), freq=9398, duty_u16=32768)
|
||||
...
|
||||
PWM(Pin(27), freq=1598, duty_u16=32768)
|
||||
PWM(Pin(27), freq=1401, duty_u16=32768)
|
||||
PWM(Pin(27), freq=1202, duty_u16=32768)
|
||||
PWM(Pin(27), freq=998, duty_u16=32768)
|
||||
|
||||
|
||||
* Example of a **smooth duty change**::
|
||||
* Example of a smooth duty change::
|
||||
|
||||
from time import sleep
|
||||
from machine import Pin, PWM
|
||||
|
||||
DUTY_MAX = 65535
|
||||
DUTY_MAX = 2**16 - 1
|
||||
|
||||
duty_u16 = 0
|
||||
delta_d = 256
|
||||
delta_d = 16
|
||||
|
||||
pwm = PWM(Pin(27), freq=1000, duty_u16=duty_u16)
|
||||
p = PWM(Pin(5), 1000, duty_u16=duty_u16)
|
||||
print(p)
|
||||
|
||||
while True:
|
||||
pwm.duty_u16(duty_u16)
|
||||
sleep(2 / pwm.freq())
|
||||
print(pwm)
|
||||
p.duty_u16(duty_u16)
|
||||
|
||||
if duty_u16 >= DUTY_MAX:
|
||||
print()
|
||||
sleep(2)
|
||||
elif duty_u16 <= 0:
|
||||
print()
|
||||
sleep(2)
|
||||
sleep(1 / 1000)
|
||||
|
||||
duty_u16 += delta_d
|
||||
if duty_u16 >= DUTY_MAX:
|
||||
@@ -138,106 +99,9 @@ low all of the time.
|
||||
duty_u16 = 0
|
||||
delta_d = -delta_d
|
||||
|
||||
PWM wave on Pin(27) with an oscilloscope.
|
||||
See PWM wave at Pin(5) with an oscilloscope.
|
||||
|
||||
Output is::
|
||||
|
||||
PWM(Pin(27), freq=998, duty_u16=0)
|
||||
PWM(Pin(27), freq=998, duty_u16=256)
|
||||
PWM(Pin(27), freq=998, duty_u16=512)
|
||||
PWM(Pin(27), freq=998, duty_u16=768)
|
||||
PWM(Pin(27), freq=998, duty_u16=1024)
|
||||
...
|
||||
PWM(Pin(27), freq=998, duty_u16=64512)
|
||||
PWM(Pin(27), freq=998, duty_u16=64768)
|
||||
PWM(Pin(27), freq=998, duty_u16=65024)
|
||||
PWM(Pin(27), freq=998, duty_u16=65280)
|
||||
PWM(Pin(27), freq=998, duty_u16=65535)
|
||||
|
||||
PWM(Pin(27), freq=998, duty_u16=65279)
|
||||
PWM(Pin(27), freq=998, duty_u16=65023)
|
||||
PWM(Pin(27), freq=998, duty_u16=64767)
|
||||
PWM(Pin(27), freq=998, duty_u16=64511)
|
||||
...
|
||||
PWM(Pin(27), freq=998, duty_u16=1023)
|
||||
PWM(Pin(27), freq=998, duty_u16=767)
|
||||
PWM(Pin(27), freq=998, duty_u16=511)
|
||||
PWM(Pin(27), freq=998, duty_u16=255)
|
||||
PWM(Pin(27), freq=998, duty_u16=0)
|
||||
|
||||
|
||||
* Example of a **smooth duty change and PWM output inversion**::
|
||||
|
||||
from utime import sleep
|
||||
from machine import Pin, PWM
|
||||
|
||||
try:
|
||||
DUTY_MAX = 65535
|
||||
|
||||
duty_u16 = 0
|
||||
delta_d = 65536 // 32
|
||||
|
||||
pwm = PWM(Pin(27))
|
||||
pwmi = PWM(Pin(32), invert=1)
|
||||
|
||||
while True:
|
||||
pwm.duty_u16(duty_u16)
|
||||
pwmi.duty_u16(duty_u16)
|
||||
|
||||
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
|
||||
|
||||
sleep(.01)
|
||||
print(pwm)
|
||||
print(pwmi)
|
||||
|
||||
finally:
|
||||
try:
|
||||
pwm.deinit()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
pwmi.deinit()
|
||||
except:
|
||||
pass
|
||||
|
||||
Output is::
|
||||
|
||||
PWM(Pin(27), freq=5000, duty_u16=0)
|
||||
PWM(Pin(32), freq=5000, duty_u16=32768, invert=1)
|
||||
PWM(Pin(27), freq=5000, duty_u16=2048)
|
||||
PWM(Pin(32), freq=5000, duty_u16=2048, invert=1)
|
||||
PWM(Pin(27), freq=5000, duty_u16=4096)
|
||||
PWM(Pin(32), freq=5000, duty_u16=4096, invert=1)
|
||||
PWM(Pin(27), freq=5000, duty_u16=6144)
|
||||
PWM(Pin(32), freq=5000, duty_u16=6144, invert=1)
|
||||
PWM(Pin(27), freq=5000, duty_u16=8192)
|
||||
PWM(Pin(32), freq=5000, duty_u16=8192, invert=1)
|
||||
...
|
||||
|
||||
|
||||
See PWM waves on Pin(27) and Pin(32) with an oscilloscope.
|
||||
|
||||
Note: New PWM parameters take effect in the next PWM cycle.
|
||||
|
||||
pwm = PWM(2, duty=512)
|
||||
print(pwm)
|
||||
>>> PWM(Pin(2), freq=5000, duty=1023) # the duty is not relevant
|
||||
pwm.init(freq=2, duty=64)
|
||||
print(pwm)
|
||||
>>> PWM(Pin(2), freq=2, duty=16) # the duty is not relevant
|
||||
time.sleep(1 / 2) # wait one PWM period
|
||||
print(pwm)
|
||||
>>> PWM(Pin(2), freq=2, duty=64) # the duty is actual
|
||||
|
||||
Note: machine.freq(20_000_000) reduces the highest PWM frequency to 10 MHz.
|
||||
|
||||
Note: the Pin.OUT mode does not need to be specified. The channel is initialized
|
||||
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::
|
||||
|
||||
@@ -764,5 +764,4 @@ Constructor
|
||||
The **value** can be either:
|
||||
|
||||
- A 16-bit integer. e.g. ``0x2908``.
|
||||
- An object with the buffer protocol and that is 2, 4 or 16 bytes long, e.g. ``b'\x08\x29'``.
|
||||
- A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``.
|
||||
|
||||
@@ -151,10 +151,10 @@ Constants
|
||||
|
||||
.. data:: INCL
|
||||
|
||||
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be inclusive of the end key.
|
||||
|
||||
.. data:: DESC
|
||||
|
||||
A flag for :meth:`btree.keys`, :meth:`btree.values`, :meth:`btree.items` methods to specify that
|
||||
A flag for `keys()`, `values()`, `items()` methods to specify that
|
||||
scanning should be in descending direction of keys.
|
||||
|
||||
@@ -18,31 +18,23 @@ Functions
|
||||
Configure whether or not a touch will wake the device from sleep.
|
||||
*wake* should be a boolean value.
|
||||
|
||||
.. note:: This is only available for boards that have touch sensor support.
|
||||
|
||||
.. function:: wake_on_ulp(wake)
|
||||
|
||||
Configure whether or not the Ultra-Low-Power co-processor can wake the
|
||||
device from sleep. *wake* should be a boolean value.
|
||||
|
||||
.. note:: This is only available for boards that have ULP coprocessor support.
|
||||
|
||||
.. function:: wake_on_ext0(pin, level)
|
||||
|
||||
Configure how EXT0 wakes the device from sleep. *pin* can be ``None``
|
||||
or a valid Pin object. *level* should be ``esp32.WAKEUP_ALL_LOW`` or
|
||||
``esp32.WAKEUP_ANY_HIGH``.
|
||||
|
||||
.. note:: This is only available for boards that have ext0 support.
|
||||
|
||||
.. function:: wake_on_ext1(pins, level)
|
||||
|
||||
Configure how EXT1 wakes the device from sleep. *pins* can be ``None``
|
||||
or a tuple/list of valid Pin objects. *level* should be ``esp32.WAKEUP_ALL_LOW``
|
||||
or ``esp32.WAKEUP_ANY_HIGH``.
|
||||
|
||||
.. note:: This is only available for boards that have ext1 support.
|
||||
|
||||
.. function:: gpio_deep_sleep_hold(enable)
|
||||
|
||||
Configure whether non-RTC GPIO pin configuration is retained during
|
||||
@@ -88,29 +80,6 @@ Functions
|
||||
The result of :func:`gc.mem_free()` is the total of the current "free"
|
||||
and "max new split" values printed by :func:`micropython.mem_info()`.
|
||||
|
||||
.. function:: idf_task_info()
|
||||
|
||||
Returns information about running ESP-IDF/FreeRTOS tasks, which include
|
||||
MicroPython threads. This data is useful to gain insight into how much time
|
||||
tasks spend running or if they are blocked for significant parts of time,
|
||||
and to determine if allocated stacks are fully utilized or might be reduced.
|
||||
|
||||
``CONFIG_FREERTOS_USE_TRACE_FACILITY=y`` must be set in the board
|
||||
configuration to make this method available. Additionally configuring
|
||||
``CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y`` and
|
||||
``CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y`` is recommended to be able to
|
||||
retrieve the total and per-task runtime and the core ID respectively.
|
||||
|
||||
The return value is a 2-tuple where the first value is the total runtime,
|
||||
and the second a list of tasks. Each task is a 7-tuple containing: the task
|
||||
ID, name, current state, priority, runtime, stack high water mark, and the
|
||||
ID of the core it is running on. Runtime and core ID will be None when the
|
||||
respective FreeRTOS configuration option is not enabled.
|
||||
|
||||
.. note:: For an easier to use output based on this function you can use the
|
||||
`utop library <https://github.com/micropython/micropython-lib/tree/master/micropython/utop>`_,
|
||||
which implements a live overview similar to the Unix ``top`` command.
|
||||
|
||||
|
||||
Flash partitions
|
||||
----------------
|
||||
@@ -195,151 +164,6 @@ Constants
|
||||
|
||||
Used in `idf_heap_info`.
|
||||
|
||||
|
||||
.. _esp32.PCNT:
|
||||
|
||||
PCNT
|
||||
----
|
||||
|
||||
This class provides access to the ESP32 hardware support for pulse counting.
|
||||
There are 8 pulse counter units, with id 0..7.
|
||||
|
||||
See the :ref:`machine.Counter <machine.Counter>` and
|
||||
:ref:`machine.Encoder <machine.Encoder>` classes for simpler and portable
|
||||
abstractions of common pulse counting applications. These classes are
|
||||
implemented as thin Python shims around :class:`PCNT`.
|
||||
|
||||
.. class:: PCNT(id, *, ...)
|
||||
|
||||
Returns the singleton PCNT instance for the given unit ``id``.
|
||||
|
||||
Keyword arguments are passed to the ``init()`` method as described
|
||||
below.
|
||||
|
||||
.. method:: PCNT.init(*, ...)
|
||||
|
||||
(Re-)initialise a pulse counter unit. Supported keyword arguments are:
|
||||
|
||||
- ``channel``: see description below
|
||||
- ``pin``: the input Pin to monitor for pulses
|
||||
- ``rising``: an action to take on a rising edge - one of
|
||||
``PCNT.INCREMENT``, ``PCNT.DECREMENT`` or ``PCNT.IGNORE`` (the default)
|
||||
- ``falling``: an action to take on a falling edge (takes the save values
|
||||
as the ``rising`` argument).
|
||||
- ``mode_pin``: ESP32 pulse counters support monitoring a second pin and
|
||||
altering the behaviour of the counter based on its level - set this
|
||||
keyword to any input Pin
|
||||
- ``mode_low``: set to either ``PCNT.HOLD`` or ``PCNT.REVERSE`` to
|
||||
either suspend counting or reverse the direction of the counter (i.e.,
|
||||
``PCNT.INCREMENT`` behaves as ``PCNT.DECREMENT`` and vice versa)
|
||||
when ``mode_pin`` is low
|
||||
- ``mode_high``: as ``mode_low`` but for the behaviour when ``mode_pin``
|
||||
is high
|
||||
- ``filter``: set to a value 1..1023, in ticks of the 80MHz clock, to
|
||||
enable the pulse width filter
|
||||
- ``min``: set to the minimum level of the counter value when
|
||||
decrementing (-32768..-1) or 0 to disable
|
||||
- ``max``: set to the maximum level of the counter value when
|
||||
incrementing (1..32767) or 0 to disable
|
||||
- ``threshold0``: sets the counter value for the
|
||||
``PCNT.IRQ_THRESHOLD0`` event (see ``irq`` method)
|
||||
- ``threshold1``: sets the counter value for the
|
||||
``PCNT.IRQ_THRESHOLD1`` event (see ``irq`` method)
|
||||
- ``value``: can be set to ``0`` to reset the counter value
|
||||
|
||||
The hardware initialisation is done in stages and so some of the keyword
|
||||
arguments can be used in groups or in isolation to partially reconfigure a
|
||||
unit:
|
||||
|
||||
- the ``pin`` keyword (optionally combined with ``mode_pin``) can be used
|
||||
to change just the bound pin(s)
|
||||
- ``rising``, ``falling``, ``mode_low`` and ``mode_high`` can be used
|
||||
(singly or together) to change the counting logic - omitted keywords
|
||||
use their default (``PCNT.IGNORE`` or ``PCNT.NORMAL``)
|
||||
- ``filter`` can be used to change only the pulse width filter (with 0
|
||||
disabling it)
|
||||
- each of ``min``, ``max``, ``threshold0`` and ``threshold1`` can
|
||||
be used to change these limit/event values individually; however,
|
||||
setting any will reset the counter to zero (i.e., they imply
|
||||
``value=0``)
|
||||
|
||||
Each pulse counter unit supports two channels, 0 and 1, each able to
|
||||
monitor different pins with different counting logic but updating the same
|
||||
counter value. Use ``channel=1`` with the ``pin``, ``rising``, ``falling``,
|
||||
``mode_pin``, ``mode_low`` and ``mode_high`` keywords to configure the
|
||||
second channel.
|
||||
|
||||
The second channel can be used to configure 4X quadrature decoding with a
|
||||
single counter unit::
|
||||
|
||||
pin_a = Pin(2, Pin.INPUT, pull=Pin.PULL_UP)
|
||||
pin_b = Pin(3, Pin.INPUT, pull=Pin.PULL_UP)
|
||||
rotary = PCNT(0, min=-32000, max=32000)
|
||||
rotary.init(channel=0, pin=pin_a, falling=PCNT.INCREMENT, rising=PCNT.DECREMENT, mode_pin=pin_b, mode_low=PCNT.REVERSE)
|
||||
rotary.init(channel=1, pin=pin_b, falling=PCNT.DECREMENT, rising=PCNT.INCREMENT, mode_pin=pin_a, mode_low=PCNT.REVERSE)
|
||||
rotary.start()
|
||||
|
||||
.. method:: PCNT.value([value])
|
||||
|
||||
Call this method with no arguments to return the current counter value.
|
||||
|
||||
If the optional *value* argument is set to ``0`` then the counter is
|
||||
reset (but the previous value is returned). Read and reset is not atomic and
|
||||
so it is possible for a pulse to be missed. Any value other than ``0`` will
|
||||
raise an error.
|
||||
|
||||
.. method:: PCNT.irq(handler=None, trigger=PCNT.IRQ_ZERO)
|
||||
|
||||
ESP32 pulse counters support interrupts on these counter events:
|
||||
|
||||
- ``PCNT.IRQ_ZERO``: the counter has reset to zero
|
||||
- ``PCNT.IRQ_MIN``: the counter has hit the ``min`` value
|
||||
- ``PCNT.IRQ_MAX``: the counter has hit the ``max`` value
|
||||
- ``PCNT.IRQ_THRESHOLD0``: the counter has hit the ``threshold0`` value
|
||||
- ``PCNT.IRQ_THRESHOLD1``: the counter has hit the ``threshold1`` value
|
||||
|
||||
``trigger`` should be a bit-mask of the desired events OR'ed together. The
|
||||
``handler`` function should take a single argument which is the
|
||||
:class:`PCNT` instance that raised the event.
|
||||
|
||||
This method returns a callback object. The callback object can be used to
|
||||
access the bit-mask of events that are outstanding on the PCNT unit.::
|
||||
|
||||
def pcnt_irq(pcnt):
|
||||
flags = pcnt.irq().flags()
|
||||
if flags & PCNT.IRQ_ZERO:
|
||||
# reset
|
||||
if flags & PCNT.IRQ_MAX:
|
||||
# overflow...
|
||||
... etc
|
||||
|
||||
pcnt.irq(handler=pcnt_irq, trigger=PCNT.IRQ_ZERO | PCNT.IRQ_MAX | ...)
|
||||
|
||||
**Note:** Accessing ``irq.flags()`` will clear the flags, so only call it
|
||||
once per invocation of the handler.
|
||||
|
||||
The handler is called with the MicroPython scheduler and so will run at a
|
||||
point after the interrupt. If another interrupt occurs before the handler
|
||||
has been called then the events will be coalesced together into a single
|
||||
call and the bit mask will indicate all events that have occurred.
|
||||
|
||||
To avoid race conditions between a handler being called and retrieving the
|
||||
current counter value, the ``value()`` method will force execution of any
|
||||
pending events before returning the current counter value (and potentially
|
||||
resetting the value).
|
||||
|
||||
Only one handler can be in place per-unit. Set ``handler`` to ``None`` to
|
||||
disable the event interrupt.
|
||||
|
||||
.. Note::
|
||||
ESP32 pulse counters reset to *zero* when reaching the minimum or maximum
|
||||
value. Thus the ``IRQ_ZERO`` event will also trigger when either of these
|
||||
events occurs.
|
||||
|
||||
See the :ref:`machine.Counter <machine.Counter>` and
|
||||
:ref:`machine.Encoder <machine.Encoder>` classes for simpler abstractions of
|
||||
common pulse counting applications.
|
||||
|
||||
.. _esp32.RMT:
|
||||
|
||||
RMT
|
||||
|
||||
@@ -137,18 +137,6 @@ Other methods
|
||||
is compared to the value from *palette*, not to the value directly from
|
||||
*fbuf*.)
|
||||
|
||||
*fbuf* can be another FrameBuffer instance, or a tuple or list of the form::
|
||||
|
||||
(buffer, width, height, format)
|
||||
|
||||
or::
|
||||
|
||||
(buffer, width, height, format, stride)
|
||||
|
||||
This matches the signature of the FrameBuffer constructor, and the elements
|
||||
of the tuple/list are the same as the arguments to the constructor except that
|
||||
the *buffer* here can be read-only.
|
||||
|
||||
The *palette* argument enables blitting between FrameBuffers with differing
|
||||
formats. Typical usage is to render a monochrome or grayscale glyph/icon to
|
||||
a color display. The *palette* is a FrameBuffer instance whose format is
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Counter:
|
||||
|
||||
class Counter -- pulse counter
|
||||
==============================
|
||||
|
||||
Counter implements pulse counting by monitoring an input signal and counting
|
||||
rising or falling edges.
|
||||
|
||||
Minimal example usage::
|
||||
|
||||
from machine import Pin, Counter
|
||||
|
||||
counter = Counter(0, Pin(0, Pin.IN)) # create Counter for pin 0 and begin counting
|
||||
value = counter.value() # retrieve current pulse count
|
||||
|
||||
Availability: **ESP32**
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: Counter(id, ...)
|
||||
|
||||
Returns the singleton Counter object for the the given *id*. Values of *id*
|
||||
depend on a particular port and its hardware. Values 0, 1, etc. are commonly
|
||||
used to select hardware block #0, #1, etc.
|
||||
|
||||
Additional arguments are passed to the :meth:`init` method described below,
|
||||
and will cause the Counter instance to be re-initialised and reset.
|
||||
|
||||
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Counter.init(src, *, ...)
|
||||
|
||||
Initialise and reset the Counter with the given parameters:
|
||||
|
||||
- *src* specifies the input pin as a :ref:`machine.Pin <machine.Pin>` object.
|
||||
May be omitted on ports that have a predefined pin for a given hardware
|
||||
block.
|
||||
|
||||
Additional keyword-only parameters that may be supported by a port are:
|
||||
|
||||
- *edge* specifies the edge to count. Either ``Counter.RISING`` (the default)
|
||||
or ``Counter.FALLING``. *(Supported on ESP32)*
|
||||
|
||||
- *direction* specifies the direction to count. Either ``Counter.UP`` (the
|
||||
default) or ``Counter.DOWN``. *(Supported on ESP32)*
|
||||
|
||||
- *filter_ns* specifies a minimum period of time in nanoseconds that the
|
||||
source signal needs to be stable for a pulse to be counted. Implementations
|
||||
should use the longest filter supported by the hardware that is less than
|
||||
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
|
||||
|
||||
.. method:: Counter.deinit()
|
||||
|
||||
Stops the Counter, disabling any interrupts and releasing hardware resources.
|
||||
A Soft Reset should deinitialize all Counter objects.
|
||||
|
||||
.. method:: Counter.value([value])
|
||||
|
||||
Get, and optionally set, the counter value as a signed integer.
|
||||
Implementations must aim to do the get and set atomically (i.e. without
|
||||
leading to skipped counts).
|
||||
|
||||
This counter value could exceed the range of a :term:`small integer`, which
|
||||
means that calling :meth:`Counter.value` could cause a heap allocation, but
|
||||
implementations should aim to ensure that internal state only uses small
|
||||
integers and therefore will not allocate until the user calls
|
||||
:meth:`Counter.value`.
|
||||
|
||||
For example, on ESP32, the internal state counts overflows of the hardware
|
||||
counter (every 32000 counts), which means that it will not exceed the small
|
||||
integer range until ``2**30 * 32000`` counts (slightly over 1 year at 1MHz).
|
||||
|
||||
In general, it is recommended that you should use ``Counter.value(0)`` to reset
|
||||
the counter (i.e. to measure the counts since the last call), and this will
|
||||
avoid this problem.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: Counter.RISING
|
||||
Counter.FALLING
|
||||
|
||||
Select the pulse edge.
|
||||
|
||||
.. data:: Counter.UP
|
||||
Counter.DOWN
|
||||
|
||||
Select the counting direction.
|
||||
@@ -1,72 +0,0 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.Encoder:
|
||||
|
||||
class Encoder -- quadrature decoding
|
||||
====================================
|
||||
|
||||
Encoder implements decoding of quadrature signals as commonly output from
|
||||
rotary encoders, by counting either up or down depending on the order of two
|
||||
input pulses.
|
||||
|
||||
Minimal example usage::
|
||||
|
||||
from machine import Pin, Encoder
|
||||
|
||||
counter = Counter(0, Pin(0, Pin.IN), Pin(1, Pin.IN)) # create Encoder for pins 0, 1 and begin counting
|
||||
value = counter.value() # retrieve current count
|
||||
|
||||
Availability: **ESP32**
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: Encoder(id, ...)
|
||||
|
||||
Returns the singleton Encoder object for the the given *id*. Values of *id*
|
||||
depend on a particular port and its hardware. Values 0, 1, etc. are commonly
|
||||
used to select hardware block #0, #1, etc.
|
||||
|
||||
Additional arguments are passed to the :meth:`init` method described below,
|
||||
and will cause the Encoder instance to be re-initialised and reset.
|
||||
|
||||
On ESP32, the *id* corresponds to a :ref:`PCNT unit <esp32.PCNT>`.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Encoder.init(phase_a, phase_b, *, ...)
|
||||
|
||||
Initialise and reset the Encoder with the given parameters:
|
||||
|
||||
- *phase_a* specifies the first input pin as a
|
||||
:ref:`machine.Pin <machine.Pin>` object.
|
||||
|
||||
- *phase_b* specifies the second input pin as a
|
||||
:ref:`machine.Pin <machine.Pin>` object.
|
||||
|
||||
These pins may be omitted on ports that have predefined pins for a given
|
||||
hardware block.
|
||||
|
||||
Additional keyword-only parameters that may be supported by a port are:
|
||||
|
||||
- *filter_ns* specifies a minimum period of time in nanoseconds that the
|
||||
source signal needs to be stable for a pulse to be counted. Implementations
|
||||
should use the longest filter supported by the hardware that is less than
|
||||
or equal to this value. The default is 0 (no filter). *(Supported on ESP32)*
|
||||
|
||||
- *phases* specifies the number of signal edges to count and thus the
|
||||
granularity of the decoding. e.g. 4 phases corresponds to "4x quadrature
|
||||
decoding", and will result in four counts per pulse. Ports may support
|
||||
either 1, 2, or 4 phases and the default is 1 phase. *(Supported on ESP32)*
|
||||
|
||||
.. method:: Encoder.deinit()
|
||||
|
||||
Stops the Encoder, disabling any interrupts and releasing hardware resources.
|
||||
A Soft Reset should deinitialize all Encoder objects.
|
||||
|
||||
.. method:: Encoder.value([value])
|
||||
|
||||
Get, and optionally set, the encoder value as a signed integer.
|
||||
Implementations should aim to do the get and set atomically.
|
||||
|
||||
See :meth:`machine.Counter.value` for details about overflow of this value.
|
||||
@@ -1,174 +0,0 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.I2CTarget:
|
||||
|
||||
class I2CTarget -- an I2C target device
|
||||
=======================================
|
||||
|
||||
An I2C target is a device which connects to an I2C bus and is controlled by an
|
||||
I2C controller. I2C targets can take many forms. The :class:`machine.I2CTarget`
|
||||
class implements an I2C target that can be configured as a memory/register device,
|
||||
or as an arbitrary I2C device by using callbacks (if supported by the port).
|
||||
|
||||
Example usage for the case of a memory device::
|
||||
|
||||
from machine import I2CTarget
|
||||
|
||||
# Create the backing memory for the I2C target.
|
||||
mem = bytearray(8)
|
||||
|
||||
# Create an I2C target. Depending on the port, extra parameters
|
||||
# may be required to select the peripheral and/or pins to use.
|
||||
i2c = I2CTarget(addr=67, mem=mem)
|
||||
|
||||
# At this point an I2C controller can read and write `mem`.
|
||||
...
|
||||
|
||||
# Deinitialise the I2C target.
|
||||
i2c.deinit()
|
||||
|
||||
Note that some ports require an ``id``, and maybe ``scl`` and ``sda`` pins, to be
|
||||
passed to the `I2CTarget` constructor, to select the hardware I2C instance and
|
||||
pins that it connects to.
|
||||
|
||||
When configured as a memory device, it's also possible to register to receive events.
|
||||
For example to be notified when the memory is read/written::
|
||||
|
||||
from machine import I2CTarget
|
||||
|
||||
# Define an IRQ handler, for I2C events.
|
||||
def irq_handler(i2c_target):
|
||||
flags = i2c_target.irq().flags()
|
||||
if flags & I2CTarget.IRQ_END_READ:
|
||||
print("controller read target at addr", i2c_target.memaddr)
|
||||
if flags & I2CTarget.IRQ_END_WRITE:
|
||||
print("controller wrote target at addr", i2c_target.memaddr)
|
||||
|
||||
# Create the I2C target and register to receive default events.
|
||||
mem = bytearray(8)
|
||||
i2c = I2CTarget(addr=67, mem=mem)
|
||||
i2c.irq(irq_handler)
|
||||
|
||||
More complicated I2C devices can be implemented using the full set of events. For
|
||||
example, to see the raw events as they are triggered::
|
||||
|
||||
from machine import I2CTarget
|
||||
|
||||
# Define an IRQ handler that prints the event id and responds to reads/writes.
|
||||
def irq_handler(i2c_target, buf=bytearray(1)):
|
||||
flags = i2c_target.irq().flags()
|
||||
print(flags)
|
||||
if flags & I2CTarget.IRQ_READ_REQ:
|
||||
i2c_target.write(buf)
|
||||
if flags & I2CTarget.IRQ_WRITE_REQ:
|
||||
i2c_target.readinto(buf)
|
||||
|
||||
# Create the I2C target and register to receive all events.
|
||||
i2c = I2CTarget(addr=67)
|
||||
all_triggers = (
|
||||
I2CTarget.IRQ_ADDR_MATCH_READ
|
||||
| I2CTarget.IRQ_ADDR_MATCH_WRITE
|
||||
| I2CTarget.IRQ_READ_REQ
|
||||
| I2CTarget.IRQ_WRITE_REQ
|
||||
| I2CTarget.IRQ_END_READ
|
||||
| I2CTarget.IRQ_END_WRITE
|
||||
)
|
||||
i2c.irq(irq_handler, trigger=all_triggers, hard=True)
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: I2CTarget(id, addr, *, addrsize=7, mem=None, mem_addrsize=8, scl=None, sda=None)
|
||||
|
||||
Construct and return a new I2CTarget object using the following parameters:
|
||||
|
||||
- *id* identifies a particular I2C peripheral. Allowed values depend on the
|
||||
particular port/board. Some ports have a default in which case this parameter
|
||||
can be omitted.
|
||||
- *addr* is the I2C address of the target.
|
||||
- *addrsize* is the number of bits in the I2C target address. Valid values
|
||||
are 7 and 10.
|
||||
- *mem* is an object with the buffer protocol that is writable. If not
|
||||
specified then there is no backing memory and data must be read/written
|
||||
using the :meth:`I2CTarget.readinto` and :meth:`I2CTarget.write` methods.
|
||||
- *mem_addrsize* is the number of bits in the memory address. Valid values
|
||||
are 0, 8, 16, 24 and 32.
|
||||
- *scl* is a pin object specifying the pin to use for SCL.
|
||||
- *sda* is a pin object specifying the pin to use for SDA.
|
||||
|
||||
Note that some ports/boards will have default values of *scl* and *sda*
|
||||
that can be changed in this constructor. Others will have fixed values
|
||||
of *scl* and *sda* that cannot be changed.
|
||||
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. method:: I2CTarget.deinit()
|
||||
|
||||
Deinitialise the I2C target. After this method is called the hardware will no
|
||||
longer respond to requests on the I2C bus, and no other methods can be called.
|
||||
|
||||
.. method:: I2CTarget.readinto(buf)
|
||||
|
||||
Read into the given buffer any pending bytes written by the I2C controller.
|
||||
Returns the number of bytes read.
|
||||
|
||||
.. method:: I2CTarget.write(buf)
|
||||
|
||||
Write out the bytes from the given buffer, to be passed to the I2C controller
|
||||
after it sends a read request. Returns the number of bytes written. Most ports
|
||||
only accept one byte at a time to this method.
|
||||
|
||||
.. method:: I2CTarget.irq(handler=None, trigger=IRQ_END_READ|IRQ_END_WRITE, hard=False)
|
||||
|
||||
Configure an IRQ *handler* to be called when an event occurs. The possible events are
|
||||
given by the following constants, which can be or'd together and passed to the *trigger*
|
||||
argument:
|
||||
|
||||
- ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a
|
||||
controller for a read transaction.
|
||||
- ``IRQ_ADDR_MATCH_READ`` indicates that the target was addressed by a
|
||||
controller for a write transaction.
|
||||
- ``IRQ_READ_REQ`` indicates that the controller is requesting data, and this
|
||||
request must be satisfied by calling `I2CTarget.write` with the data to be
|
||||
passed back to the controller.
|
||||
- ``IRQ_WRITE_REQ`` indicates that the controller has written data, and the
|
||||
data must be read by calling `I2CTarget.readinto`.
|
||||
- ``IRQ_END_READ`` indicates that the controller has finished a read transaction.
|
||||
- ``IRQ_END_WRITE`` indicates that the controller has finished a write transaction.
|
||||
|
||||
Not all triggers are available on all ports. If a port has the constant then that
|
||||
event is available.
|
||||
|
||||
Note the following restrictions:
|
||||
|
||||
- ``IRQ_ADDR_MATCH_READ``, ``IRQ_ADDR_MATCH_READ``, ``IRQ_READ_REQ`` and
|
||||
``IRQ_WRITE_REQ`` must be handled by a hard IRQ callback (with the *hard* argument
|
||||
set to ``True``). This is because these events have very strict timing requirements
|
||||
and must usually be satisfied synchronously with the hardware event.
|
||||
|
||||
- ``IRQ_END_READ`` and ``IRQ_END_WRITE`` may be handled by either a soft or hard
|
||||
IRQ callback (although note that all events must be registered with the same handler,
|
||||
so if any events need a hard callback then all events must be hard).
|
||||
|
||||
- If a memory buffer has been supplied in the constructor then ``IRQ_END_WRITE``
|
||||
is not emitted for the transaction that writes the memory address. This is to
|
||||
allow ``IRQ_END_READ`` and ``IRQ_END_WRITE`` to function correctly as soft IRQ
|
||||
callbacks, where the IRQ handler may be called quite some time after the actual
|
||||
hardware event.
|
||||
|
||||
.. attribute:: I2CTarget.memaddr
|
||||
|
||||
The integer value of the most recent memory address that was selected by the I2C
|
||||
controller (only valid if ``mem`` was specified in the constructor).
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: I2CTarget.IRQ_ADDR_MATCH_READ
|
||||
I2CTarget.IRQ_ADDR_MATCH_WRITE
|
||||
I2CTarget.IRQ_READ_REQ
|
||||
I2CTarget.IRQ_WRITE_REQ
|
||||
I2CTarget.IRQ_END_READ
|
||||
I2CTarget.IRQ_END_WRITE
|
||||
|
||||
IRQ trigger sources.
|
||||
@@ -11,20 +11,20 @@ Example usage::
|
||||
from machine import PWM
|
||||
|
||||
pwm = PWM(pin, freq=50, duty_u16=8192) # create a PWM object on a pin
|
||||
# and set freq 50 Hz and duty 12.5%
|
||||
pwm.duty_u16(32768) # set duty to 50%
|
||||
# and set freq and duty
|
||||
pwm.duty_u16(32768) # set duty to 50%
|
||||
|
||||
# reinitialise with a period of 200us, duty of 5us
|
||||
pwm.init(freq=5000, duty_ns=5000)
|
||||
|
||||
pwm.duty_ns(3000) # set pulse width to 3us
|
||||
pwm.duty_ns(3000) # set pulse width to 3us
|
||||
|
||||
pwm.deinit()
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert=False)
|
||||
.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert)
|
||||
|
||||
Construct and return a new PWM object using the following parameters:
|
||||
|
||||
@@ -40,7 +40,7 @@ Constructors
|
||||
Setting *freq* may affect other PWM objects if the objects share the same
|
||||
underlying PWM generator (this is hardware specific).
|
||||
Only one of *duty_u16* and *duty_ns* should be specified at a time.
|
||||
*invert* is available only on the esp32, mimxrt, nrf, rp2, samd and zephyr ports.
|
||||
*invert* is not available at all ports.
|
||||
|
||||
Methods
|
||||
-------
|
||||
@@ -116,10 +116,10 @@ Limitations of PWM
|
||||
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=65536//2)
|
||||
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2)
|
||||
|
||||
and::
|
||||
|
||||
pwm=PWM(Pin(13), freq=300_000, duty_u16=65536//2 + 255)
|
||||
pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255)
|
||||
|
||||
will generate PWM with the same 50% duty cycle.
|
||||
|
||||
@@ -224,8 +224,7 @@ Methods
|
||||
|
||||
|
||||
.. note::
|
||||
- The ESP32 port does not support the option hard=True. It uses Timer(0)
|
||||
for UART.IRQ_RXIDLE, so this timer cannot be used for other means.
|
||||
- The ESP32 port does not support the option hard=True.
|
||||
|
||||
- The rp2 port's UART.IRQ_TXIDLE is only triggered when the message
|
||||
is longer than 5 characters and the trigger happens when still 5 characters
|
||||
|
||||
@@ -264,12 +264,9 @@ Classes
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.I2CTarget.rst
|
||||
machine.I2S.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.Counter.rst
|
||||
machine.Encoder.rst
|
||||
machine.WDT.rst
|
||||
machine.SD.rst
|
||||
machine.SDCard.rst
|
||||
|
||||
@@ -58,11 +58,6 @@ Methods
|
||||
- *pull_thresh* is the threshold in bits before auto-pull or conditional
|
||||
re-pulling is triggered.
|
||||
|
||||
Note: pins used for *in_base* need to be configured manually for input (or
|
||||
otherwise) so that the PIO can see the desired signal (they could be input
|
||||
pins, output pins, or connected to a different peripheral). The *jmp_pin*
|
||||
can also be configured manually, but by default will be an input pin.
|
||||
|
||||
.. method:: StateMachine.active([value])
|
||||
|
||||
Gets or sets whether the state machine is currently running.
|
||||
|
||||
@@ -227,28 +227,22 @@ Methods
|
||||
has the same "no short writes" policy for blocking sockets, and will return
|
||||
number of bytes sent on non-blocking sockets.
|
||||
|
||||
.. method:: socket.recv(bufsize, [flags])
|
||||
.. method:: socket.recv(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a bytes object representing the data
|
||||
received. The maximum amount of data to be received at once is specified by bufsize.
|
||||
|
||||
Most ports support the optional *flags* argument. Available *flags* are defined as constants
|
||||
in the socket module and have the same meaning as in CPython. ``MSG_PEEK`` and ``MSG_DONTWAIT``
|
||||
are supported on all ports which accept the *flags* argument.
|
||||
|
||||
.. method:: socket.sendto(bytes, address)
|
||||
|
||||
Send data to the socket. The socket should not be connected to a remote socket, since the
|
||||
destination socket is specified by *address*.
|
||||
|
||||
.. method:: socket.recvfrom(bufsize, [flags])
|
||||
.. method:: socket.recvfrom(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a
|
||||
bytes object representing the data received and *address* is the address of the socket sending
|
||||
the data.
|
||||
|
||||
See the `recv` function for an explanation of the optional *flags* argument.
|
||||
|
||||
.. method:: socket.setsockopt(level, optname, value)
|
||||
|
||||
Set the value of the given socket option. The needed symbolic constants are defined in the
|
||||
|
||||
@@ -66,7 +66,7 @@ class SSLContext
|
||||
Set the available ciphers for sockets created with this context. *ciphers* should be
|
||||
a list of strings in the `IANA cipher suite format <https://wiki.mozilla.org/Security/Cipher_Suites>`_ .
|
||||
|
||||
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None, client_id=None)
|
||||
.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None)
|
||||
|
||||
Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
|
||||
and returns an instance of ssl.SSLSocket, wrapping the underlying stream.
|
||||
@@ -89,9 +89,6 @@ class SSLContext
|
||||
server certificate. It also sets the name for Server Name Indication (SNI), allowing the server
|
||||
to present the proper certificate.
|
||||
|
||||
- *client_id* is a MicroPython-specific extension argument used only when implementing a DTLS
|
||||
Server. See :ref:`dtls` for details.
|
||||
|
||||
.. warning::
|
||||
|
||||
Some implementations of ``ssl`` module do NOT validate server certificates,
|
||||
@@ -120,8 +117,6 @@ Exceptions
|
||||
|
||||
This exception does NOT exist. Instead its base class, OSError, is used.
|
||||
|
||||
.. _dtls:
|
||||
|
||||
DTLS support
|
||||
------------
|
||||
|
||||
@@ -130,47 +125,16 @@ DTLS support
|
||||
|
||||
This is a MicroPython extension.
|
||||
|
||||
On most ports, this module supports DTLS in client and server mode via the
|
||||
`PROTOCOL_DTLS_CLIENT` and `PROTOCOL_DTLS_SERVER` constants that can be used as
|
||||
the ``protocol`` argument of `SSLContext`.
|
||||
This module supports DTLS in client and server mode via the `PROTOCOL_DTLS_CLIENT`
|
||||
and `PROTOCOL_DTLS_SERVER` constants that can be used as the ``protocol`` argument
|
||||
of `SSLContext`.
|
||||
|
||||
In this case the underlying socket is expected to behave as a datagram socket (i.e.
|
||||
like the socket opened with ``socket.socket`` with ``socket.AF_INET`` as ``af`` and
|
||||
``socket.SOCK_DGRAM`` as ``type``).
|
||||
|
||||
DTLS is only supported on ports that use mbedTLS, and it is enabled by default
|
||||
in most configurations but can be manually disabled by defining
|
||||
``MICROPY_PY_SSL_DTLS`` to 0.
|
||||
|
||||
DTLS server support
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
MicroPython's DTLS server support is configured with "Hello Verify" as required
|
||||
for DTLS 1.2. This is transparent for DTLS clients, but there are relevant
|
||||
considerations when implementing a DTLS server in MicroPython:
|
||||
|
||||
- The server should pass an additional argument *client_id* when calling
|
||||
`SSLContext.wrap_socket()`. This ID must be a `bytes` object (or similar) with
|
||||
a transport-specific identifier representing the client.
|
||||
|
||||
The simplest approach is to convert the tuple of ``(client_ip, client_port)``
|
||||
returned from ``socket.recv_from()`` into a byte string, i.e.::
|
||||
|
||||
_, client_addr = sock.recvfrom(1, socket.MSG_PEEK)
|
||||
sock.connect(client_addr) # Connect back to the client
|
||||
sock = ssl_ctx.wrap_socket(sock, server_side=True,
|
||||
client_id=repr(client_addr).encode())
|
||||
|
||||
- The first time a client connects, the server call to ``wrap_socket`` will fail
|
||||
with a `OSError` error "Hello Verify Required". This is because the DTLS
|
||||
"Hello Verify" cookie is not yet known by the client. If the same client
|
||||
connects a second time then ``wrap_socket`` will succeed.
|
||||
|
||||
- DTLS cookies for "Hello Verify" are associated with the `SSLContext` object,
|
||||
so the same `SSLContext` object should be used to wrap a subsequent connection
|
||||
from the same client. The cookie implementation includes a timeout and has
|
||||
constant memory use regardless of how many clients connect, so it's OK to
|
||||
reuse the same `SSLContext` object for the lifetime of the server.
|
||||
DTLS is only supported on ports that use mbed TLS, and it is not enabled by default:
|
||||
it requires enabling ``MBEDTLS_SSL_PROTO_DTLS`` in the specific port configuration.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
@@ -77,8 +77,6 @@ Constants
|
||||
* *_mpy* - supported mpy file-format version (optional attribute)
|
||||
* *_build* - string that can help identify the configuration that
|
||||
MicroPython was built with
|
||||
* *_thread* - optional string attribute, exists if the target has threading
|
||||
and is either "GIL" or "unsafe"
|
||||
|
||||
This object is the recommended way to distinguish MicroPython from other
|
||||
Python implementations (note that it still may not exist in the very
|
||||
@@ -97,14 +95,6 @@ Constants
|
||||
* On microcontroller targets, the first element is the board name and the second
|
||||
element (if present) is the board variant, for example ``'RPI_PICO2-RISCV'``
|
||||
|
||||
The *_thread* entry was added in version 1.26.0 and if it exists then the
|
||||
target has the ``_thread`` module. If the target enables the GIL (global
|
||||
interpreter lock) then this attribute is ``"GIL"``. Otherwise the attribute
|
||||
is ``"unsafe"`` and the target has threading but does not enable the GIL,
|
||||
and mutable Python objects (such as `bytearray`, `list` and `dict`) that are
|
||||
shared amongst threads must be protected explicitly by locks such as
|
||||
``_thread.allocate_lock``.
|
||||
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
The ``time`` module provides functions for getting the current time and date,
|
||||
measuring time intervals, and for delays.
|
||||
|
||||
**Time Epoch**: The unix, windows, webassembly, alif, mimxrt and rp2 ports
|
||||
use the standard for POSIX systems epoch of 1970-01-01 00:00:00 UTC.
|
||||
The other embedded ports use an epoch of 2000-01-01 00:00:00 UTC.
|
||||
Epoch year may be determined with ``gmtime(0)[0]``.
|
||||
**Time Epoch**: Unix port uses standard for POSIX systems epoch of
|
||||
1970-01-01 00:00:00 UTC. However, some embedded ports use epoch of
|
||||
2000-01-01 00:00:00 UTC. Epoch year may be determined with ``gmtime(0)[0]``.
|
||||
|
||||
**Maintaining actual calendar date/time**: This requires a
|
||||
Real Time Clock (RTC). On systems with underlying OS (including some
|
||||
@@ -58,11 +57,11 @@ Functions
|
||||
* weekday is 0-6 for Mon-Sun
|
||||
* yearday is 1-366
|
||||
|
||||
.. function:: mktime(date_time_tuple)
|
||||
.. function:: mktime()
|
||||
|
||||
This is inverse function of localtime. It's argument is a full 8-tuple
|
||||
which expresses a time as per localtime. It returns an integer which is
|
||||
the number of seconds since the time epoch.
|
||||
the number of seconds since Jan 1, 2000.
|
||||
|
||||
.. function:: sleep(seconds)
|
||||
|
||||
|
||||
@@ -358,13 +358,13 @@ Run WM8960 on a MIMXRT10xx_DEV board in secondary mode (default)::
|
||||
sysclk_source=wm8960.SYSCLK_MCLK)
|
||||
|
||||
|
||||
Record with a SparkFun WM8960 breakout board with Teensy in secondary mode (default)::
|
||||
Record with a Sparkfun WM8960 breakout board with Teensy in secondary mode (default)::
|
||||
|
||||
# Micro_python WM8960 Codec driver
|
||||
#
|
||||
# The breakout board uses a fixed 24MHz MCLK. Therefore the internal
|
||||
# PLL must be used as sysclk, which is the master audio clock.
|
||||
# The SparkFun board has the WS pins for RX and TX connected on the
|
||||
# The Sparkfun board has the WS pins for RX and TX connected on the
|
||||
# board. Therefore adc_sync must be set to sync_adc, to configure
|
||||
# it's ADCLRC pin as input.
|
||||
#
|
||||
@@ -379,11 +379,11 @@ Record with a SparkFun WM8960 breakout board with Teensy in secondary mode (defa
|
||||
right_input=wm8960.INPUT_CLOSED)
|
||||
|
||||
|
||||
Play with a SparkFun WM8960 breakout board with Teensy in secondary mode (default)::
|
||||
Play with a Sparkfun WM8960 breakout board with Teensy in secondary mode (default)::
|
||||
|
||||
# The breakout board uses a fixed 24MHz MCLK. Therefore the internal
|
||||
# PLL must be used as sysclk, which is the master audio clock.
|
||||
# The SparkFun board has the WS pins for RX and TX connected on the
|
||||
# The Sparkfun board has the WS pins for RX and TX connected on the
|
||||
# board. Therefore adc_sync must be set to sync_adc, to configure
|
||||
# it's ADCLRC pin as input.
|
||||
|
||||
|
||||
@@ -22,10 +22,9 @@ Functions
|
||||
|
||||
Returns the thread id of the current thread, which is used to reference the thread.
|
||||
|
||||
.. function:: thread_analyze(cpu)
|
||||
.. function:: thread_analyze()
|
||||
|
||||
Runs the Zephyr debug thread analyzer on the current thread on the given cpu
|
||||
and prints stack size statistics in the format:
|
||||
Runs the Zephyr debug thread analyzer on the current thread and prints stack size statistics in the format:
|
||||
|
||||
"``thread_name``-20s: STACK: unused ``available_stack_space`` usage ``stack_space_used``
|
||||
/ ``stack_size`` (``percent_stack_space_used`` %); CPU: ``cpu_utilization`` %"
|
||||
@@ -36,9 +35,6 @@ Functions
|
||||
For more information, see documentation for Zephyr `thread analyzer
|
||||
<https://docs.zephyrproject.org/latest/guides/debug_tools/thread-analyzer.html#thread-analyzer>`_.
|
||||
|
||||
Note that the ``cpu`` argument is only used in Zephyr v4.0.0 and
|
||||
newer and ignored otherwise.
|
||||
|
||||
.. function:: shell_exec(cmd_in)
|
||||
|
||||
Executes the given command on an UART backend. This function can only be accessed if ``CONFIG_SHELL_BACKEND_SERIAL``
|
||||
|
||||
@@ -188,13 +188,6 @@ Glossary
|
||||
Most MicroPython boards make a REPL available over a UART, and this is
|
||||
typically accessible on a host PC via USB.
|
||||
|
||||
small integer
|
||||
MicroPython optimises the internal representation of integers such that
|
||||
"small" values do not take up space on the heap, and calculations with
|
||||
them do not require heap allocation. On most 32-bit ports, this
|
||||
corresponds to values in the interval ``-2**30 <= x < 2**30``, but this
|
||||
should be considered an implementation detail and not relied upon.
|
||||
|
||||
stream
|
||||
Also known as a "file-like object". A Python object which provides
|
||||
sequential read-write access to the underlying data. A stream object
|
||||
|
||||
@@ -108,7 +108,7 @@ The full list of supported commands are:
|
||||
**Note:** Instead of using the ``connect`` command, there are several
|
||||
:ref:`pre-defined shortcuts <mpremote_shortcuts>` for common device paths. For
|
||||
example the ``a0`` shortcut command is equivalent to
|
||||
``connect /dev/ttyACM0`` (Linux), or ``c1`` for ``COM1`` (Windows).
|
||||
``connect /dev/ttyACM0`` (Linux), or ``c0`` for ``COM0`` (Windows).
|
||||
|
||||
**Note:** The ``auto`` option will only detect USB serial ports, i.e. a serial
|
||||
port that has an associated USB VID/PID (i.e. CDC/ACM or FTDI-style
|
||||
@@ -234,7 +234,6 @@ The full list of supported commands are:
|
||||
- ``rmdir <dirs...>`` to remove directories on the device
|
||||
- ``touch <file..>`` to create the files (if they don't already exist)
|
||||
- ``sha256sum <file..>`` to calculate the SHA256 sum of files
|
||||
- ``tree [-vsh] <dirs...>`` to print a tree of the given directories
|
||||
|
||||
The ``cp`` command uses a convention where a leading ``:`` represents a remote
|
||||
path. Without a leading ``:`` means a local path. This is based on the
|
||||
@@ -265,13 +264,6 @@ The full list of supported commands are:
|
||||
There is no supported way to undelete files removed by ``mpremote rm -r :``.
|
||||
Please use with caution.
|
||||
|
||||
The ``tree`` command will print a tree of the given directories.
|
||||
Using the ``--size/-s`` option will print the size of each file, or use
|
||||
``--human/-h`` to use a more human readable format.
|
||||
Note: Directory size is only printed when a non-zero size is reported by the device's filesystem.
|
||||
The ``-v`` option can be used to include the name of the serial device in
|
||||
the output.
|
||||
|
||||
All other commands implicitly assume the path is a remote path, but the ``:``
|
||||
can be optionally used for clarity.
|
||||
|
||||
@@ -487,16 +479,9 @@ Shortcuts can be defined using the macro system. Built-in shortcuts are:
|
||||
|
||||
- ``cat``, ``edit``, ``ls``, ``cp``, ``rm``, ``mkdir``, ``rmdir``, ``touch``: Aliases for ``fs <sub-command>``
|
||||
|
||||
Additional shortcuts can be defined in the user configuration file ``mpremote/config.py``,
|
||||
located in the User Configuration Directory.
|
||||
The correct location for each OS is determined using the ``platformdirs`` module.
|
||||
|
||||
This is typically:
|
||||
- ``$XDG_CONFIG_HOME/mpremote/config.py``
|
||||
- ``$HOME/.config/mpremote/config.py``
|
||||
- ``$env:LOCALAPPDATA/mpremote/config.py``
|
||||
|
||||
The ``config.py``` file should define a dictionary named ``commands``. The keys of this dictionary are the shortcuts
|
||||
Additional shortcuts can be defined by in user-configuration files, which is
|
||||
located at ``.config/mpremote/config.py``. This file should define a
|
||||
dictionary named ``commands``. The keys of this dictionary are the shortcuts
|
||||
and the values are either a string or a list-of-strings:
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
@@ -246,13 +246,6 @@ There are certain limitations in the current implementation of the native code e
|
||||
* Context managers are not supported (the ``with`` statement).
|
||||
* Generators are not supported.
|
||||
* If ``raise`` is used an argument must be supplied.
|
||||
* The background scheduler (see `micropython.schedule`) is not run during
|
||||
execution of native code.
|
||||
* On targets with thrteading and the GIL, the GIL is not released during
|
||||
execution of native code.
|
||||
|
||||
To mitigate the last two points, long running native functions should call
|
||||
``time.sleep(0)`` periodically, which will run the scheduler and bounce the GIL.
|
||||
|
||||
The trade-off for the improved performance (roughly twice as fast as bytecode) is an
|
||||
increase in compiled code size.
|
||||
|
||||
@@ -135,12 +135,6 @@ Use the :mod:`machine.Timer` class::
|
||||
tim = Timer(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
|
||||
tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
|
||||
|
||||
By default, timer callbacks run as soft IRQs so they can allocate but
|
||||
are prone to GC jitter and delays. Pass ``hard=True`` to the ``Timer()``
|
||||
constructor or ``init()`` method to run the callback in hard-IRQ context
|
||||
instead. This reduces delay and jitter, but see :ref:`isr_rules` for the
|
||||
restrictions that apply to hard-IRQ handlers.
|
||||
|
||||
|
||||
.. _rp2_Pins_and_GPIO:
|
||||
|
||||
|
||||
@@ -650,124 +650,6 @@ Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
|
||||
|
||||
The board does not provide access to UART, I2C, SPI or DAC.
|
||||
|
||||
SparkFun Redboard Turbo assignment table
|
||||
----------------------------------------
|
||||
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
2 PA02 A0 2 0 - - - -
|
||||
40 PB08 A1 8 2 - 4/0 4/0 -
|
||||
41 PB09 A2 9 3 - 4/1 4/1 -
|
||||
4 PA04 A3 4 4 - 0/0 0/0 -
|
||||
5 PA05 A4 5 5 - 0/1 0/1 -
|
||||
34 PB02 A5 2 10 - 5/0 6/0 -
|
||||
11 PA11 D0 11 19 0/3 2/3 1/1 0/3
|
||||
10 PA10 D1 10 18 0/2 2/2 1/0 0/2
|
||||
14 PA14 D2 14 - 2/2 4/2 3/0 0/4
|
||||
9 PA09 D3 9 17 0/1 2/1 0/1 1/3
|
||||
8 PA08 D4 - 16 0/0 2/0 0/0 1/2
|
||||
15 PA15 D5 15 - 2/3 4/3 3/1 0/5
|
||||
20 PA20 D6 4 - 5/2 3/2 7/0 0/4
|
||||
21 PA21 D7 5 - 5/3 3/3 7/1 0/7
|
||||
6 PA06 D8 6 6 - 0/2 1/0 -
|
||||
7 PA07 D9 7 7 - 0/3 1/1 -
|
||||
11 PA11 RX 11 19 0/3 2/3 1/1 0/3
|
||||
10 PA10 TX 10 18 0/2 2/2 1/0 0/2
|
||||
3 PA03 AREF 3 1 - - - -
|
||||
18 PA18 D10 2 - 1/2 3/2 3/0 0/2
|
||||
16 PA16 D11 0 - 1/0 3/0 2/0 0/6
|
||||
19 PA19 D12 3 - 1/3 3/3 3/1 0/3
|
||||
17 PA17 D13 1 - 1/1 3/1 2/1 0/7
|
||||
13 PA13 FLASH_CS 13 - 2/1 4/1 2/0 0/7
|
||||
35 PB03 FLASH_MISO 3 11 - 5/1 6/1 -
|
||||
54 PB22 FLASH_MOSI 6 - - 5/2 7/0 -
|
||||
55 PB23 FLASH_SCK 7 - - 5/3 7/1 -
|
||||
31 PA31 LED_RX 11 - - 1/3 1/1 -
|
||||
27 PA27 LED_TX 15 - - - - -
|
||||
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
|
||||
42 PB10 MOSI 10 - - 4/2 5/0 0/4
|
||||
30 PA30 NEOPIXEL 10 - - 1/2 1/0 -
|
||||
43 PB11 SCK 11 - - 4/3 5/1 0/5
|
||||
23 PA23 SCL 7 - 3/1 5/1 4/1 0/5
|
||||
22 PA22 SDA 6 - 3/0 5/0 4/0 0/4
|
||||
30 PA30 SWCLK 10 - - 1/2 1/0 -
|
||||
31 PA31 SWDIO 11 - - 1/3 1/1 -
|
||||
24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2
|
||||
25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3
|
||||
0 PA00 0 - - 1/0 2/0 -
|
||||
1 PA01 1 - - 1/1 2/1 -
|
||||
28 PA28 8 - - - - -
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
|
||||
For the definition of the table columns see the explanation at the table for
|
||||
Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
|
||||
|
||||
The default devices at the board are:
|
||||
|
||||
- UART 0 at pins PA11/PA10, labelled RX/TX
|
||||
- I2C 3 at pins PA22/PA23, labelled SDA/SCL
|
||||
- SPI 4 at pins PB10/PA12/PB11, labelled MISO, MOSI and SCK
|
||||
- DAC output on pin PA02, labelled A0
|
||||
|
||||
|
||||
SparkFun SAMD21 Dev Breakout assignment table
|
||||
---------------------------------------------
|
||||
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
Pin GPIO Pin name IRQ ADC Serial Serial TCC/TC TCC/TC
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
2 PA02 A0 2 0 - - - -
|
||||
40 PB08 A1 8 2 - 4/0 4/0 -
|
||||
41 PB09 A2 9 3 - 4/1 4/1 -
|
||||
4 PA04 A3 4 4 - 0/0 0/0 -
|
||||
5 PA05 A4 5 5 - 0/1 0/1 -
|
||||
34 PB02 A5 2 10 - 5/0 6/0 -
|
||||
11 PA11 D0 11 19 0/3 2/3 1/1 0/3
|
||||
10 PA10 D1 10 18 0/2 2/2 1/0 0/2
|
||||
14 PA14 D2 14 - 2/2 4/2 3/0 0/4
|
||||
9 PA09 D3 9 17 0/1 2/1 0/1 1/3
|
||||
8 PA08 D4 - 16 0/0 2/0 0/0 1/2
|
||||
15 PA15 D5 15 - 2/3 4/3 3/1 0/5
|
||||
20 PA20 D6 4 - 5/2 3/2 7/0 0/4
|
||||
21 PA21 D7 5 - 5/3 3/3 7/1 0/7
|
||||
6 PA06 D8 6 6 - 0/2 1/0 -
|
||||
7 PA07 D9 7 7 - 0/3 1/1 -
|
||||
11 PA11 RX 11 19 0/3 2/3 1/1 0/3
|
||||
10 PA10 TX 10 18 0/2 2/2 1/0 0/2
|
||||
3 PA03 AREF 3 1 - - - -
|
||||
18 PA18 D10 2 - 1/2 3/2 3/0 0/2
|
||||
16 PA16 D11 0 - 1/0 3/0 2/0 0/6
|
||||
19 PA19 D12 3 - 1/3 3/3 3/1 0/3
|
||||
17 PA17 D13 1 - 1/1 3/1 2/1 0/7
|
||||
54 PB22 D30 6 - - 5/2 7/0 -
|
||||
55 PB23 D31 7 - - 5/3 7/1 -
|
||||
13 PA13 D38 13 - 2/1 4/1 2/0 0/7
|
||||
35 PB03 LED_RX 3 11 - 5/1 6/1 -
|
||||
27 PA27 LED_TX 15 - - - - -
|
||||
12 PA12 MISO 12 - 2/0 4/0 2/0 0/6
|
||||
42 PB10 MOSI 10 - - 4/2 5/0 0/4
|
||||
43 PB11 SCK 11 - - 4/3 5/1 0/5
|
||||
23 PA23 SCL 7 - 3/1 5/1 4/1 0/5
|
||||
22 PA22 SDA 6 - 3/0 5/0 4/0 0/4
|
||||
30 PA30 SWCLK 10 - - 1/2 1/0 -
|
||||
31 PA31 SWDIO 11 - - 1/3 1/1 -
|
||||
24 PA24 USB_DM 12 - 3/2 5/2 5/0 1/2
|
||||
25 PA25 USB_DP 13 - 3/3 5/3 5/1 1/3
|
||||
0 PA00 0 - - 1/0 2/0 -
|
||||
1 PA01 1 - - 1/1 2/1 -
|
||||
28 PA28 8 - - - - -
|
||||
=== ==== ============ ==== ==== ====== ====== ====== ======
|
||||
|
||||
For the definition of the table columns see the explanation at the table for
|
||||
Adafruit ItsyBitsy M0 Express :ref:`samd21_pinout_table`.
|
||||
|
||||
The default devices at the board are:
|
||||
|
||||
- UART 0 at pins PA11/PA10, labelled RX/TX
|
||||
- I2C 3 at pins PA22/PA23, labelled SDA/SCL
|
||||
- SPI 4 at pins PB10/PA12/PB11, labelled MISO, MOSI and SCK
|
||||
- DAC output on pin PA02, labelled A0
|
||||
|
||||
SAMD21 Xplained PRO pin assignment table
|
||||
----------------------------------------
|
||||
@@ -1010,7 +892,7 @@ Default pin assignments:
|
||||
|
||||
There seems to be no default pin assignment for this board.
|
||||
|
||||
SparkFun SAMD51 Thing Plus pin assignment table
|
||||
Sparkfun SAMD51 Thing Plus pin assignment table
|
||||
------------------------------------------------
|
||||
|
||||
=== ==== ============ ==== ==== ==== ====== ====== ===== ===== =====
|
||||
|
||||
@@ -56,21 +56,6 @@ Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||
switch = Pin(("gpioc", 6), Pin.IN) # create input pin for a switch
|
||||
switch.irq(lambda t: print("SW2 changed")) # enable an interrupt when switch state is changed
|
||||
|
||||
PWM
|
||||
---
|
||||
|
||||
Use the :ref:`machine.PWM <machine.PWM>` class::
|
||||
|
||||
from machine import PWM
|
||||
|
||||
pwm = PWM(("pwm0", 0), freq=3921568, duty_ns=200, invert=True) # create pwm on PWM0
|
||||
print(pwm) # print pwm
|
||||
|
||||
print(pwm.duty_ns()) # print pwm duty cycle in nanoseconds
|
||||
pwm.duty_ns(255) # set new pwm duty cycle in nanoseconds
|
||||
|
||||
pwm.deinit()
|
||||
|
||||
Hardware I2C bus
|
||||
----------------
|
||||
|
||||
@@ -153,8 +138,6 @@ Use the :ref:`zephyr.FlashArea <zephyr.FlashArea>` class to support filesystem::
|
||||
f.write('Hello world') # write to the file
|
||||
print(open('/flash/hello.txt').read()) # print contents of the file
|
||||
|
||||
The FlashAreas' IDs that are available are listed in the FlashArea module, as ID_*.
|
||||
|
||||
Sensor
|
||||
------
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ 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
|
||||
you should be presented with the following text::
|
||||
|
||||
*** Booting Zephyr OS build v4.0.0 ***
|
||||
*** Booting Zephyr OS build v3.7.0 ***
|
||||
MicroPython v1.24.0-preview.179.g5b85b24bd on 2024-08-05; zephyr-frdm_k64f with mk64f12
|
||||
Type "help()" for more information.
|
||||
>>>
|
||||
|
||||
@@ -46,7 +46,6 @@ typedef struct _mp_qspi_proto_t {
|
||||
int (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
|
||||
int (*read_cmd)(void *self, uint8_t cmd, size_t len, uint32_t *dest);
|
||||
int (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, uint8_t num_dummy, size_t len, uint8_t *dest);
|
||||
int (*direct_read)(void *self, uint32_t addr, size_t len, uint8_t *dest); // can be NULL if direct read not supported
|
||||
} mp_qspi_proto_t;
|
||||
|
||||
typedef struct _mp_soft_qspi_obj_t {
|
||||
|
||||
17
drivers/cyw43/README.md
Normal file
17
drivers/cyw43/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
CYW43xx WiFi SoC driver
|
||||
=======================
|
||||
|
||||
This is a driver for the CYW43xx WiFi SoC.
|
||||
|
||||
There are four layers to the driver:
|
||||
|
||||
1. SDIO bus interface, provided by the host device/system.
|
||||
|
||||
2. Low-level CYW43xx interface, managing the bus, control messages, Ethernet
|
||||
frames and asynchronous events. Includes download of SoC firmware. The
|
||||
header file `cyw43_ll.h` defines the interface to this layer.
|
||||
|
||||
3. Mid-level CYW43xx control, to control and set WiFi parameters and manage
|
||||
events. See `cyw43_ctrl.c`.
|
||||
|
||||
4. TCP/IP bindings to lwIP. See `cyw43_lwip.c`.
|
||||
304
drivers/cyw43/cywbt.c
Normal file
304
drivers/cyw43/cywbt.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/mpbthci.h"
|
||||
|
||||
#if MICROPY_PY_NETWORK_CYW43
|
||||
|
||||
#include "lib/cyw43-driver/src/cyw43_config.h"
|
||||
#include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h"
|
||||
|
||||
// Provided by the port, and also possibly shared with the stack.
|
||||
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
||||
|
||||
/******************************************************************************/
|
||||
// CYW BT HCI low-level driver
|
||||
|
||||
#ifdef CYW43_PIN_BT_CTS
|
||||
// This code is not portable and currently only builds on stm32 port.
|
||||
|
||||
#include "pin_static_af.h"
|
||||
#include "uart.h"
|
||||
|
||||
// Provided by the port.
|
||||
extern machine_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||
|
||||
static void cywbt_wait_cts_low(void) {
|
||||
mp_hal_pin_config(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) {
|
||||
break;
|
||||
}
|
||||
mp_hal_delay_ms(1);
|
||||
}
|
||||
mp_hal_pin_config_alt(CYW43_PIN_BT_CTS, MP_HAL_PIN_MODE_ALT,
|
||||
MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||
mp_bluetooth_hci_uart_write((void *)buf, len);
|
||||
for (int c, i = 0; i < 6; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
// expect a command complete event (event 0x0e)
|
||||
if (buf[0] != 0x04 || buf[1] != 0x0e) {
|
||||
printf("unknown response: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
if buf[3:6] != cmd[:3]:
|
||||
print('response doesn\'t match cmd:', cmd, ev)
|
||||
return b''
|
||||
*/
|
||||
|
||||
int sz = buf[2] - 3;
|
||||
for (int c, i = 0; i < sz; ++i) {
|
||||
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cywbt_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] = 0x01;
|
||||
buf[1] = ocf;
|
||||
buf[2] = ogf << 2 | ocf >> 8;
|
||||
buf[3] = param_len;
|
||||
if (param_len) {
|
||||
memcpy(buf + 4, param_buf, param_len);
|
||||
}
|
||||
return cywbt_hci_cmd_raw(4 + param_len, buf);
|
||||
}
|
||||
|
||||
static void put_le16(uint8_t *buf, uint16_t val) {
|
||||
buf[0] = val;
|
||||
buf[1] = val >> 8;
|
||||
}
|
||||
|
||||
static void put_le32(uint8_t *buf, uint32_t val) {
|
||||
buf[0] = val;
|
||||
buf[1] = val >> 8;
|
||||
buf[2] = val >> 16;
|
||||
buf[3] = val >> 24;
|
||||
}
|
||||
|
||||
static int cywbt_set_baudrate(uint32_t baudrate) {
|
||||
uint8_t buf[6];
|
||||
put_le16(buf, 0);
|
||||
put_le32(buf + 2, baudrate);
|
||||
return cywbt_hci_cmd(0x3f, 0x18, 6, buf);
|
||||
}
|
||||
|
||||
// download firmware
|
||||
static int cywbt_download_firmware(const uint8_t *firmware) {
|
||||
cywbt_hci_cmd(0x3f, 0x2e, 0, NULL);
|
||||
|
||||
bool last_packet = false;
|
||||
while (!last_packet) {
|
||||
uint8_t *buf = mp_bluetooth_hci_cmd_buf;
|
||||
memcpy(buf + 1, firmware, 3);
|
||||
firmware += 3;
|
||||
last_packet = buf[1] == 0x4e;
|
||||
if (buf[2] != 0xfc) {
|
||||
printf("fail1 %02x\n", buf[2]);
|
||||
break;
|
||||
}
|
||||
uint8_t len = buf[3];
|
||||
|
||||
memcpy(buf + 4, firmware, len);
|
||||
firmware += len;
|
||||
|
||||
buf[0] = 1;
|
||||
cywbt_hci_cmd_raw(4 + len, buf);
|
||||
if (buf[0] != 0) {
|
||||
printf("fail3 %02x\n", buf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// RF switch must select high path during BT patch boot
|
||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||
mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||
#endif
|
||||
mp_hal_delay_ms(10); // give some time for CTS to go high
|
||||
#ifdef CYW43_PIN_BT_CTS
|
||||
cywbt_wait_cts_low();
|
||||
#endif
|
||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||
// Select chip antenna (could also select external)
|
||||
mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0);
|
||||
#endif
|
||||
|
||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||
cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
|
||||
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_bluetooth_hci_controller_init(void) {
|
||||
// This is called immediately after the UART is initialised during stack initialisation.
|
||||
|
||||
mp_hal_pin_output(CYW43_PIN_BT_REG_ON);
|
||||
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||
#ifdef CYW43_PIN_BT_HOST_WAKE
|
||||
mp_hal_pin_input(CYW43_PIN_BT_HOST_WAKE);
|
||||
#endif
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
mp_hal_pin_output(CYW43_PIN_BT_DEV_WAKE);
|
||||
mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE);
|
||||
#endif
|
||||
|
||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||
// TODO don't select antenna if wifi is enabled
|
||||
mp_hal_pin_config(CYW43_PIN_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
|
||||
mp_hal_pin_high(CYW43_PIN_WL_GPIO_4); // Turn the RF-switch on
|
||||
#endif
|
||||
|
||||
uint8_t buf[256];
|
||||
|
||||
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||
mp_hal_delay_ms(100);
|
||||
mp_hal_pin_high(CYW43_PIN_BT_REG_ON);
|
||||
#ifdef CYW43_PIN_BT_CTS
|
||||
cywbt_wait_cts_low();
|
||||
#else
|
||||
mp_hal_delay_ms(100);
|
||||
#endif
|
||||
|
||||
// Reset
|
||||
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
||||
|
||||
#ifdef MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE
|
||||
// Change baudrate
|
||||
cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
|
||||
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
|
||||
#endif
|
||||
|
||||
cywbt_download_firmware((const uint8_t *)&cyw43_btfw_4343A1[0]);
|
||||
|
||||
// Reset
|
||||
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
||||
|
||||
// Set BD_ADDR (sent as little endian)
|
||||
uint8_t bdaddr[6];
|
||||
mp_hal_get_mac(MP_HAL_MAC_BDADDR, bdaddr);
|
||||
buf[0] = bdaddr[5];
|
||||
buf[1] = bdaddr[4];
|
||||
buf[2] = bdaddr[3];
|
||||
buf[3] = bdaddr[2];
|
||||
buf[4] = bdaddr[1];
|
||||
buf[5] = bdaddr[0];
|
||||
cywbt_hci_cmd(0x3f, 0x0001, 6, buf);
|
||||
|
||||
// Set local name
|
||||
// memset(buf, 0, 248);
|
||||
// memcpy(buf, "PYBD-BLE", 8);
|
||||
// cywbt_hci_cmd(0x03, 0x0013, 248, buf);
|
||||
|
||||
// Configure sleep mode
|
||||
cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t *)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00");
|
||||
|
||||
// HCI_Write_LE_Host_Support
|
||||
cywbt_hci_cmd(3, 109, 2, (const uint8_t *)"\x01\x00");
|
||||
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_bluetooth_hci_controller_deinit(void) {
|
||||
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
static uint32_t bt_sleep_ticks;
|
||||
#endif
|
||||
|
||||
int mp_bluetooth_hci_controller_sleep_maybe(void) {
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 0) {
|
||||
if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) {
|
||||
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool mp_bluetooth_hci_controller_woken(void) {
|
||||
#ifdef CYW43_PIN_BT_HOST_WAKE
|
||||
bool host_wake = mp_hal_pin_read(CYW43_PIN_BT_HOST_WAKE);
|
||||
/*
|
||||
// this is just for info/tracing purposes
|
||||
static bool last_host_wake = false;
|
||||
if (host_wake != last_host_wake) {
|
||||
printf("HOST_WAKE change %d -> %d\n", last_host_wake, host_wake);
|
||||
last_host_wake = host_wake;
|
||||
}
|
||||
*/
|
||||
return host_wake;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mp_bluetooth_hci_controller_wakeup(void) {
|
||||
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||
bt_sleep_ticks = mp_hal_ticks_ms();
|
||||
|
||||
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 1) {
|
||||
mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); // wake up
|
||||
// Use delay_us rather than delay_ms to prevent running the scheduler (which
|
||||
// might result in more BLE operations).
|
||||
mp_hal_delay_us(5000); // can't go lower than this
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -72,7 +72,7 @@ int esp_hosted_hci_cmd(int ogf, int ocf, size_t param_len, const uint8_t *param_
|
||||
// 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()) {
|
||||
mp_event_wait_ms(1);
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
// Timeout.
|
||||
if ((mp_hal_ticks_ms() - start) > HCI_COMMAND_TIMEOUT) {
|
||||
error_printf("timeout waiting for HCI packet\n");
|
||||
@@ -126,7 +126,7 @@ int mp_bluetooth_hci_controller_init(void) {
|
||||
if (mp_bluetooth_hci_uart_any()) {
|
||||
mp_bluetooth_hci_uart_readchar();
|
||||
}
|
||||
mp_event_wait_ms(1);
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
|
||||
#ifdef MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY
|
||||
@@ -243,7 +243,7 @@ static int esp_hosted_request(CtrlMsgId msg_id, void *ctrl_payload) {
|
||||
|
||||
static CtrlMsg *esp_hosted_response(CtrlMsgId msg_id, uint32_t timeout) {
|
||||
CtrlMsg *ctrl_msg = NULL;
|
||||
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_event_wait_ms(10)) {
|
||||
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
|
||||
if (!esp_hosted_stack_empty(&esp_state.stack)) {
|
||||
ctrl_msg = esp_hosted_stack_pop(&esp_state.stack, true);
|
||||
if (ctrl_msg->msg_id == msg_id) {
|
||||
@@ -264,6 +264,8 @@ static CtrlMsg *esp_hosted_response(CtrlMsgId msg_id, uint32_t timeout) {
|
||||
if ((mp_hal_ticks_ms() - start) >= timeout) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MICROPY_EVENT_POLL_HOOK
|
||||
}
|
||||
|
||||
// If message type is a response, check the response struct's return value.
|
||||
|
||||
@@ -197,10 +197,6 @@ void mp_spiflash_init(mp_spiflash_t *self) {
|
||||
} else {
|
||||
uint8_t num_dummy = MICROPY_HW_SPIFLASH_QREAD_NUM_DUMMY(self);
|
||||
self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT, num_dummy);
|
||||
if (self->config->bus.u_qspi.proto->direct_read != NULL) {
|
||||
// A bus with a custom read function should not have any further initialisation done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mp_spiflash_acquire_bus(self);
|
||||
@@ -322,10 +318,6 @@ int mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *de
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
const mp_spiflash_config_t *c = self->config;
|
||||
if (c->bus_kind == MP_SPIFLASH_BUS_QSPI && c->bus.u_qspi.proto->direct_read != NULL) {
|
||||
return c->bus.u_qspi.proto->direct_read(c->bus.u_qspi.data, addr, len, dest);
|
||||
}
|
||||
mp_spiflash_acquire_bus(self);
|
||||
int ret = mp_spiflash_read_data(self, addr, len, dest);
|
||||
mp_spiflash_release_bus(self);
|
||||
|
||||
@@ -114,13 +114,13 @@ void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
|
||||
mode = NINA_GPIO_OUTPUT;
|
||||
self->is_output = true;
|
||||
} else {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("only Pin.OUT and Pin.IN are supported for this pin"));
|
||||
mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin");
|
||||
}
|
||||
if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
|
||||
uint8_t buf[] = {pin_map[self->id], mode};
|
||||
if (mode == NINA_GPIO_OUTPUT) {
|
||||
if (NINA_GPIO_IS_INPUT_ONLY(self->id)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("only Pin.IN is supported for this pin"));
|
||||
mp_raise_ValueError("only Pin.IN is supported for this pin");
|
||||
}
|
||||
machine_pin_ext_set(self, value);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
#define OCF_SET_EVENT_MASK (0x0001)
|
||||
#define OCF_RESET (0x0003)
|
||||
|
||||
#define error_printf(...) // mp_printf(&mp_plat_print, "nina_bthci_uart.c: " __VA_ARGS__)
|
||||
#define debug_printf(...) // mp_printf(&mp_plat_print, "nina_bthci_uart.c: " __VA_ARGS__)
|
||||
#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];
|
||||
@@ -79,9 +79,12 @@ def decode_name(payload):
|
||||
|
||||
def decode_services(payload):
|
||||
services = []
|
||||
for code in (_ADV_TYPE_UUID16_COMPLETE, _ADV_TYPE_UUID32_COMPLETE, _ADV_TYPE_UUID128_COMPLETE):
|
||||
for u in decode_field(payload, code):
|
||||
services.append(bluetooth.UUID(u))
|
||||
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
|
||||
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
|
||||
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
|
||||
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
|
||||
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
|
||||
services.append(bluetooth.UUID(u))
|
||||
return services
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ MOD = btree_$(ARCH)
|
||||
SRC = btree_c.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
|
||||
ARCH ?= x64
|
||||
ARCH = x64
|
||||
|
||||
BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx
|
||||
BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\"
|
||||
@@ -32,18 +32,6 @@ SRC += $(addprefix $(realpath $(BTREE_DIR))/,\
|
||||
mpool/mpool.c \
|
||||
)
|
||||
|
||||
ifeq ($(ARCH),xtensa)
|
||||
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
|
||||
endif
|
||||
|
||||
# Use our own errno implementation if Picolibc is used
|
||||
CFLAGS += -D__PICOLIBC_ERRNO_FUNCTION=__errno
|
||||
|
||||
ifeq ($(ARCH),armv6m)
|
||||
# Link with libgcc.a for division helper functions
|
||||
LINK_RUNTIME = 1
|
||||
endif
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
# btree needs gnu99 defined
|
||||
|
||||
@@ -8,17 +8,6 @@ MOD = deflate_$(ARCH)
|
||||
SRC = deflate.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
|
||||
ARCH ?= x64
|
||||
|
||||
ifeq ($(ARCH),armv6m)
|
||||
# Link with libgcc.a for division helper functions
|
||||
LINK_RUNTIME = 1
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),xtensa)
|
||||
# Link with libm.a and libgcc.a from the toolchain
|
||||
LINK_RUNTIME = 1
|
||||
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
|
||||
endif
|
||||
ARCH = x64
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
@@ -8,15 +8,6 @@ MOD = framebuf_$(ARCH)
|
||||
SRC = framebuf.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH ?= x64
|
||||
|
||||
ifeq ($(ARCH),armv6m)
|
||||
# Link with libgcc.a for division helper functions
|
||||
LINK_RUNTIME = 1
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),xtensa)
|
||||
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
|
||||
endif
|
||||
ARCH = x64
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
#if !defined(__linux__)
|
||||
void *memcpy(void *dst, const void *src, size_t n) {
|
||||
return mp_fun_table.memmove_(dst, src, n);
|
||||
}
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
return mp_fun_table.memset_(s, c, n);
|
||||
}
|
||||
|
||||
@@ -8,15 +8,6 @@ MOD = random_$(ARCH)
|
||||
SRC = random.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
|
||||
ARCH ?= x64
|
||||
|
||||
ifeq ($(ARCH),xtensa)
|
||||
MPY_EXTERN_SYM_FILE=$(MPY_DIR)/ports/esp8266/boards/eagle.rom.addr.v6.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),$(filter $(ARCH),armv6m armv7m))
|
||||
# Link with libm.a for soft-float helper functions
|
||||
LINK_RUNTIME = 1
|
||||
endif
|
||||
ARCH = x64
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
@@ -10,9 +10,4 @@ SRC = re.c
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc)
|
||||
ARCH = x64
|
||||
|
||||
ifeq ($(ARCH),armv6m)
|
||||
# Link with libgcc.a for division helper functions
|
||||
LINK_RUNTIME = 1
|
||||
endif
|
||||
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
@@ -23,7 +23,7 @@ PIO_RX_PIN = Pin(3, Pin.IN, Pin.PULL_UP)
|
||||
@asm_pio(
|
||||
autopush=True,
|
||||
push_thresh=8,
|
||||
in_shiftdir=PIO.SHIFT_RIGHT,
|
||||
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
|
||||
fifo_join=PIO.JOIN_RX,
|
||||
)
|
||||
def uart_rx_mini():
|
||||
@@ -42,7 +42,7 @@ def uart_rx_mini():
|
||||
|
||||
|
||||
@asm_pio(
|
||||
in_shiftdir=PIO.SHIFT_RIGHT,
|
||||
in_shiftdir=rp2.PIO.SHIFT_RIGHT,
|
||||
)
|
||||
def uart_rx():
|
||||
# fmt: off
|
||||
|
||||
@@ -86,12 +86,12 @@ static void example_AdvancedTimer_print(const mp_print_t *print, mp_obj_t self_i
|
||||
mp_uint_t elapsed = mp_obj_get_int(example_Timer_time(self_in));
|
||||
|
||||
// We'll make all representations print at least the class name.
|
||||
mp_printf(print, "%q()", (qstr)MP_QSTR_AdvancedTimer);
|
||||
mp_printf(print, "%q()", MP_QSTR_AdvancedTimer);
|
||||
|
||||
// Decide what else to print based on print kind.
|
||||
if (kind == PRINT_STR) {
|
||||
// For __str__, let's attempt to make it more readable.
|
||||
mp_printf(print, " # created %d seconds ago", (int)(elapsed / 1000));
|
||||
mp_printf(print, " # created %d seconds ago", elapsed / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,16 +163,9 @@ def run_until_complete(main_task=None):
|
||||
# A task waiting on _task_queue; "ph_key" is time to schedule task at
|
||||
dt = max(0, ticks_diff(t.ph_key, ticks()))
|
||||
elif not _io_queue.map:
|
||||
# No tasks can be woken
|
||||
# No tasks can be woken so finished running
|
||||
cur_task = None
|
||||
if not main_task or not main_task.state:
|
||||
# no main_task, or main_task is done so finished running
|
||||
return
|
||||
# At this point, there is theoretically nothing that could wake the
|
||||
# scheduler, but it is not allowed to exit either. We keep the code
|
||||
# running so that a hypothetical debugger (or other such meta-process)
|
||||
# can get a view of what is happening and possibly abort.
|
||||
dt = 3
|
||||
return
|
||||
# print('(poll {})'.format(dt), len(_io_queue.map))
|
||||
_io_queue.wait_io_event(dt)
|
||||
|
||||
@@ -194,33 +187,31 @@ def run_until_complete(main_task=None):
|
||||
except excs_all as er:
|
||||
# Check the task is not on any event queue
|
||||
assert t.data is None
|
||||
# If it's the main task, it is considered as awaited by the caller
|
||||
awaited = t is main_task
|
||||
if awaited:
|
||||
# This task is done, check if it's the main task and then loop should stop
|
||||
if t is main_task:
|
||||
cur_task = None
|
||||
if not isinstance(er, StopIteration):
|
||||
t.state = False
|
||||
raise er
|
||||
if t.state is None:
|
||||
t.state = False
|
||||
if isinstance(er, StopIteration):
|
||||
return er.value
|
||||
raise er
|
||||
if t.state:
|
||||
# Task was running but is now finished.
|
||||
waiting = False
|
||||
if t.state is True:
|
||||
# "None" indicates that the task is complete and not await'ed on (yet).
|
||||
t.state = False if awaited else None
|
||||
t.state = None
|
||||
elif callable(t.state):
|
||||
# The task has a callback registered to be called on completion.
|
||||
t.state(t, er)
|
||||
t.state = False
|
||||
awaited = True
|
||||
waiting = True
|
||||
else:
|
||||
# Schedule any other tasks waiting on the completion of this task.
|
||||
while t.state.peek():
|
||||
_task_queue.push(t.state.pop())
|
||||
awaited = True
|
||||
waiting = True
|
||||
# "False" indicates that the task is complete and has been await'ed on.
|
||||
t.state = False
|
||||
if not awaited and not isinstance(er, excs_stop):
|
||||
if not waiting and not isinstance(er, excs_stop):
|
||||
# An exception ended this detached task, so queue it for later
|
||||
# execution to handle the uncaught exception if no other task retrieves
|
||||
# the exception in the meantime (this is handled by Task.throw).
|
||||
@@ -238,9 +229,6 @@ def run_until_complete(main_task=None):
|
||||
_exc_context["exception"] = exc
|
||||
_exc_context["future"] = t
|
||||
Loop.call_exception_handler(_exc_context)
|
||||
# If it's the main task then the loop should stop
|
||||
if t is main_task:
|
||||
return er.value
|
||||
|
||||
|
||||
# Create a new task from a coroutine and run it until it finishes
|
||||
|
||||
@@ -705,12 +705,12 @@ int mp_bluetooth_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_bluetooth_deinit(void) {
|
||||
void mp_bluetooth_deinit(void) {
|
||||
DEBUG_printf("mp_bluetooth_deinit\n");
|
||||
|
||||
// Nothing to do if not initialised.
|
||||
if (!MP_STATE_PORT(bluetooth_btstack_root_pointers)) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mp_bluetooth_gap_advertise_stop();
|
||||
@@ -737,9 +737,6 @@ int mp_bluetooth_deinit(void) {
|
||||
deinit_stack();
|
||||
|
||||
DEBUG_printf("mp_bluetooth_deinit: complete\n");
|
||||
|
||||
bool timeout = mp_bluetooth_btstack_state == MP_BLUETOOTH_BTSTACK_STATE_TIMEOUT;
|
||||
return timeout ? MP_ETIMEDOUT : 0;
|
||||
}
|
||||
|
||||
bool mp_bluetooth_is_active(void) {
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2025 Damien P. George, Angus Gratton
|
||||
*
|
||||
* 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_CYW43_CONFIG_COMMON_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H
|
||||
|
||||
// The board-level config will be included here, so it can set some CYW43 values.
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/runtime.h"
|
||||
#include "extmod/modnetwork.h"
|
||||
#include "lwip/apps/mdns.h"
|
||||
#include "pendsv.h"
|
||||
|
||||
// This file is included at the top of port-specific cyw43_configport.h files,
|
||||
// and holds the MicroPython-specific but non-port-specific parts.
|
||||
//
|
||||
// It's included into both MicroPython sources and the lib/cyw43-driver sources.
|
||||
|
||||
#define CYW43_IOCTL_TIMEOUT_US (1000000)
|
||||
#define CYW43_NETUTILS (1)
|
||||
#define CYW43_PRINTF(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__)
|
||||
|
||||
#define CYW43_EPERM MP_EPERM // Operation not permitted
|
||||
#define CYW43_EIO MP_EIO // I/O error
|
||||
#define CYW43_EINVAL MP_EINVAL // Invalid argument
|
||||
#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out
|
||||
|
||||
#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER
|
||||
#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT
|
||||
#define CYW43_THREAD_LOCK_CHECK
|
||||
|
||||
#define CYW43_HOST_NAME mod_network_hostname_data
|
||||
|
||||
#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a)
|
||||
|
||||
#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT
|
||||
#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT
|
||||
#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE
|
||||
#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP
|
||||
#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN
|
||||
|
||||
#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0
|
||||
#define CYW43_HAL_MAC_BDADDR MP_HAL_MAC_BDADDR
|
||||
|
||||
#define cyw43_hal_ticks_us mp_hal_ticks_us
|
||||
#define cyw43_hal_ticks_ms mp_hal_ticks_ms
|
||||
|
||||
#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t
|
||||
#define cyw43_hal_pin_config mp_hal_pin_config
|
||||
#define cyw43_hal_pin_read mp_hal_pin_read
|
||||
#define cyw43_hal_pin_low mp_hal_pin_low
|
||||
#define cyw43_hal_pin_high mp_hal_pin_high
|
||||
|
||||
#define cyw43_hal_get_mac mp_hal_get_mac
|
||||
#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii
|
||||
#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac
|
||||
|
||||
#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func)
|
||||
|
||||
// Note: this function is only called if CYW43_POST_POLL_HOOK is defined in cyw43_configport.h
|
||||
void cyw43_post_poll_hook(void);
|
||||
|
||||
#ifdef MICROPY_EVENT_POLL_HOOK
|
||||
// Older style hook macros on some ports
|
||||
#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK
|
||||
#else
|
||||
// Newer style hooks on other ports
|
||||
#define CYW43_EVENT_POLL_HOOK mp_event_handle_nowait()
|
||||
#endif
|
||||
|
||||
static inline void cyw43_delay_us(uint32_t us) {
|
||||
uint32_t start = mp_hal_ticks_us();
|
||||
while (mp_hal_ticks_us() - start < us) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cyw43_delay_ms(uint32_t ms) {
|
||||
// PendSV may be disabled via CYW43_THREAD_ENTER, so this delay is a busy loop.
|
||||
uint32_t us = ms * 1000;
|
||||
uint32_t start = mp_hal_ticks_us();
|
||||
while (mp_hal_ticks_us() - start < us) {
|
||||
CYW43_EVENT_POLL_HOOK;
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_MDNS_RESPONDER == 1
|
||||
|
||||
// Hook for any additional TCP/IP initialization than needs to be done.
|
||||
// Called after the netif specified by `itf` has been set up.
|
||||
#ifndef CYW43_CB_TCPIP_INIT_EXTRA
|
||||
#define CYW43_CB_TCPIP_INIT_EXTRA(self, itf) mdns_resp_add_netif(&self->netif[itf], mod_network_hostname_data)
|
||||
#endif
|
||||
|
||||
// Hook for any additional TCP/IP deinitialization than needs to be done.
|
||||
// Called before the netif specified by `itf` is removed.
|
||||
#ifndef CYW43_CB_TCPIP_DEINIT_EXTRA
|
||||
#define CYW43_CB_TCPIP_DEINIT_EXTRA(self, itf) mdns_resp_remove_netif(&self->netif[itf])
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H
|
||||
@@ -11,7 +11,6 @@ set(MICROPY_SOURCE_EXTMOD
|
||||
${MICROPY_EXTMOD_DIR}/machine_adc_block.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_bitstream.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2c.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2c_target.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_i2s.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_mem.c
|
||||
${MICROPY_EXTMOD_DIR}/machine_pulse.c
|
||||
@@ -136,13 +135,6 @@ if(MICROPY_PY_BTREE)
|
||||
${MICROPY_LIB_BERKELEY_DIR}/include
|
||||
)
|
||||
|
||||
target_link_options(micropy_extmod_btree PRIVATE
|
||||
-Wl,--wrap=malloc
|
||||
-Wl,--wrap=free
|
||||
-Wl,--wrap=realloc
|
||||
-Wl,--wrap=calloc
|
||||
)
|
||||
|
||||
if(NOT BERKELEY_DB_CONFIG_FILE)
|
||||
set(BERKELEY_DB_CONFIG_FILE "${MICROPY_DIR}/extmod/berkeley-db/berkeley_db_config_port.h")
|
||||
endif()
|
||||
@@ -160,13 +152,11 @@ if(MICROPY_PY_BTREE)
|
||||
|
||||
list(APPEND MICROPY_DEF_CORE
|
||||
MICROPY_PY_BTREE=1
|
||||
MICROPY_STREAMS_POSIX_API # Required for mp_stream_posix_ functions if !MICROPY_ENABLE_DYNRUNTIME
|
||||
BERKELEY_DB_CONFIG_FILE="${BERKELEY_DB_CONFIG_FILE}"
|
||||
)
|
||||
|
||||
list(APPEND MICROPY_SOURCE_EXTMOD
|
||||
${MICROPY_EXTMOD_DIR}/modbtree.c
|
||||
${MICROPY_EXTMOD_DIR}/modbtree_malloc.c
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ SRC_EXTMOD_C += \
|
||||
extmod/machine_adc_block.c \
|
||||
extmod/machine_bitstream.c \
|
||||
extmod/machine_i2c.c \
|
||||
extmod/machine_i2c_target.c \
|
||||
extmod/machine_i2s.c \
|
||||
extmod/machine_mem.c \
|
||||
extmod/machine_pinbase.c \
|
||||
@@ -207,7 +206,7 @@ endif
|
||||
|
||||
ifeq ($(MICROPY_VFS_LFS2),1)
|
||||
CFLAGS_EXTMOD += -DMICROPY_VFS_LFS2=1
|
||||
CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_DEFINES=extmod/littlefs-include/lfs2_defines.h
|
||||
CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT
|
||||
SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\
|
||||
lfs2.c \
|
||||
lfs2_util.c \
|
||||
@@ -505,7 +504,7 @@ ESP_HOSTED_SRC_C = $(addprefix $(ESP_HOSTED_DIR)/,\
|
||||
)
|
||||
|
||||
ifeq ($(MICROPY_PY_BLUETOOTH),1)
|
||||
ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci_uart.c
|
||||
ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci.c
|
||||
endif
|
||||
|
||||
# Include the protobuf-c support functions
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef LFS2_DEFINES_H
|
||||
#define LFS2_DEFINES_H
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
#if MICROPY_PY_DEFLATE
|
||||
// We reuse the CRC32 implementation from uzlib to save a few bytes
|
||||
#include "lib/uzlib/uzlib.h"
|
||||
#define LFS2_CRC(crc, buffer, size) uzlib_crc32(buffer, size, crc)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// This is needed to access `next_timeout` via `sys_timeouts_get_next_timeout()`.
|
||||
#define LWIP_TESTMODE 1
|
||||
|
||||
// This sys-arch protection is not needed.
|
||||
// Ports either protect lwIP code with flags, or run it at PendSV priority.
|
||||
#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0)
|
||||
|
||||
@@ -1,424 +0,0 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2025 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_I2C_TARGET
|
||||
|
||||
#include "extmod/modmachine.h"
|
||||
#include "shared/runtime/mpirq.h"
|
||||
|
||||
enum {
|
||||
// Events exposed to Python.
|
||||
I2C_TARGET_IRQ_ADDR_MATCH_READ = 1 << 0,
|
||||
I2C_TARGET_IRQ_ADDR_MATCH_WRITE = 1 << 1,
|
||||
I2C_TARGET_IRQ_READ_REQ = 1 << 2,
|
||||
I2C_TARGET_IRQ_WRITE_REQ = 1 << 3,
|
||||
I2C_TARGET_IRQ_END_READ = 1 << 4,
|
||||
I2C_TARGET_IRQ_END_WRITE = 1 << 5,
|
||||
|
||||
// Internal event, not exposed to Python.
|
||||
I2C_TARGET_IRQ_MEM_ADDR_MATCH = 1 << 6,
|
||||
};
|
||||
|
||||
// Define the IRQs that require a hard interrupt.
|
||||
#define I2C_TARGET_IRQ_ALL_HARD ( \
|
||||
I2C_TARGET_IRQ_ADDR_MATCH_READ \
|
||||
| I2C_TARGET_IRQ_ADDR_MATCH_WRITE \
|
||||
| I2C_TARGET_IRQ_READ_REQ \
|
||||
| I2C_TARGET_IRQ_WRITE_REQ \
|
||||
)
|
||||
|
||||
enum {
|
||||
STATE_INACTIVE,
|
||||
STATE_IDLE,
|
||||
STATE_ADDR_MATCH_READ,
|
||||
STATE_ADDR_MATCH_WRITE,
|
||||
STATE_MEM_ADDR_SELECT,
|
||||
STATE_READING,
|
||||
STATE_WRITING,
|
||||
};
|
||||
|
||||
typedef struct _machine_i2c_target_data_t {
|
||||
uint8_t state;
|
||||
uint8_t mem_addr_count;
|
||||
uint8_t mem_addrsize;
|
||||
uint32_t mem_addr_last;
|
||||
uint32_t mem_addr;
|
||||
uint32_t mem_len;
|
||||
uint8_t *mem_buf;
|
||||
} machine_i2c_target_data_t;
|
||||
|
||||
typedef struct _machine_i2c_target_irq_obj_t {
|
||||
mp_irq_obj_t base;
|
||||
uint32_t flags;
|
||||
uint32_t trigger;
|
||||
} machine_i2c_target_irq_obj_t;
|
||||
|
||||
// The port must provide implementations of these low-level I2C target functions.
|
||||
|
||||
static void mp_machine_i2c_target_event_callback(machine_i2c_target_irq_obj_t *irq);
|
||||
|
||||
// Read up to N bytes, and return the number of bytes read.
|
||||
static size_t mp_machine_i2c_target_read_bytes(machine_i2c_target_obj_t *self, size_t len, uint8_t *buf);
|
||||
|
||||
// Write (or buffer) N bytes, and return the number of bytes written/buffered.
|
||||
static size_t mp_machine_i2c_target_write_bytes(machine_i2c_target_obj_t *self, size_t len, const uint8_t *buf);
|
||||
|
||||
// Configure the given events to trigger an interrupt.
|
||||
static void mp_machine_i2c_target_irq_config(machine_i2c_target_obj_t *self, unsigned int trigger);
|
||||
|
||||
static mp_obj_t mp_machine_i2c_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
static void mp_machine_i2c_target_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
|
||||
static void mp_machine_i2c_target_deinit(machine_i2c_target_obj_t *self);
|
||||
|
||||
static const mp_irq_methods_t machine_i2c_target_irq_methods;
|
||||
|
||||
static machine_i2c_target_data_t machine_i2c_target_data[MICROPY_PY_MACHINE_I2C_TARGET_MAX];
|
||||
|
||||
// Needed to retain a root pointer to the memory object.
|
||||
MP_REGISTER_ROOT_POINTER(mp_obj_t machine_i2c_target_mem_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
|
||||
|
||||
// Needed to retain a root pointer to the IRQ object.
|
||||
MP_REGISTER_ROOT_POINTER(void *machine_i2c_target_irq_obj[MICROPY_PY_MACHINE_I2C_TARGET_MAX]);
|
||||
|
||||
static bool handle_event(machine_i2c_target_data_t *data, unsigned int trigger) {
|
||||
unsigned int id = data - &machine_i2c_target_data[0];
|
||||
if (trigger & I2C_TARGET_IRQ_MEM_ADDR_MATCH) {
|
||||
data->mem_addr_last = data->mem_addr;
|
||||
}
|
||||
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[id]);
|
||||
if (irq != NULL && (trigger & irq->trigger)) {
|
||||
irq->flags = trigger & irq->trigger;
|
||||
mp_machine_i2c_target_event_callback(irq);
|
||||
return true; // irq handled
|
||||
}
|
||||
return false; // irq not handled
|
||||
}
|
||||
|
||||
static void machine_i2c_target_data_init(machine_i2c_target_data_t *data, mp_obj_t mem_obj, mp_int_t mem_addrsize) {
|
||||
data->state = STATE_IDLE;
|
||||
data->mem_addr_count = 0;
|
||||
data->mem_addrsize = 0;
|
||||
data->mem_addr_last = 0;
|
||||
data->mem_addr = 0;
|
||||
data->mem_len = 0;
|
||||
data->mem_buf = NULL;
|
||||
if (mem_obj != mp_const_none) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(mem_obj, &bufinfo, MP_BUFFER_RW);
|
||||
if (mem_addrsize < 0 || mem_addrsize > 32 || mem_addrsize % 8 != 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("mem_addrsize must be 0, 8, 16, 24 or 32"));
|
||||
}
|
||||
data->mem_addrsize = mem_addrsize / 8;
|
||||
data->mem_len = bufinfo.len;
|
||||
data->mem_buf = bufinfo.buf;
|
||||
}
|
||||
}
|
||||
|
||||
static void machine_i2c_target_data_reset_helper(machine_i2c_target_data_t *data) {
|
||||
if (data->state == STATE_READING) {
|
||||
handle_event(data, I2C_TARGET_IRQ_END_READ);
|
||||
} else if (data->state == STATE_ADDR_MATCH_WRITE || data->state == STATE_WRITING) {
|
||||
handle_event(data, I2C_TARGET_IRQ_END_WRITE);
|
||||
}
|
||||
data->state = STATE_IDLE;
|
||||
}
|
||||
|
||||
static void machine_i2c_target_data_addr_match(machine_i2c_target_data_t *data, bool read) {
|
||||
machine_i2c_target_data_reset_helper(data);
|
||||
if (read) {
|
||||
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_READ);
|
||||
data->state = STATE_ADDR_MATCH_READ;
|
||||
} else {
|
||||
handle_event(data, I2C_TARGET_IRQ_ADDR_MATCH_WRITE);
|
||||
data->state = STATE_ADDR_MATCH_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
static void machine_i2c_target_data_read_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
|
||||
// Let the user handle the read request.
|
||||
bool event_handled = handle_event(data, I2C_TARGET_IRQ_READ_REQ);
|
||||
if (data->mem_buf == NULL) {
|
||||
data->state = STATE_READING;
|
||||
if (!event_handled) {
|
||||
// No data source, just write out a zero.
|
||||
uint8_t val = 0;
|
||||
mp_machine_i2c_target_write_bytes(self, 1, &val);
|
||||
}
|
||||
} else {
|
||||
// Have a buffer.
|
||||
if (data->state == STATE_MEM_ADDR_SELECT) {
|
||||
// Got a short memory address.
|
||||
data->mem_addr %= data->mem_len;
|
||||
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
|
||||
}
|
||||
if (data->state != STATE_READING) {
|
||||
data->state = STATE_READING;
|
||||
}
|
||||
uint8_t val = data->mem_buf[data->mem_addr++];
|
||||
if (data->mem_addr >= data->mem_len) {
|
||||
data->mem_addr = 0;
|
||||
}
|
||||
mp_machine_i2c_target_write_bytes(self, 1, &val);
|
||||
}
|
||||
}
|
||||
|
||||
static void machine_i2c_target_data_write_request(machine_i2c_target_obj_t *self, machine_i2c_target_data_t *data) {
|
||||
// Let the user handle the write request.
|
||||
bool event_handled = handle_event(data, I2C_TARGET_IRQ_WRITE_REQ);
|
||||
if (data->mem_buf == NULL) {
|
||||
data->state = STATE_WRITING;
|
||||
if (!event_handled) {
|
||||
// No data sink, just read and discard the incoming byte.
|
||||
uint8_t buf = 0;
|
||||
mp_machine_i2c_target_read_bytes(self, 1, &buf);
|
||||
}
|
||||
} else {
|
||||
// Have a buffer.
|
||||
uint8_t buf[4] = {0};
|
||||
size_t n = mp_machine_i2c_target_read_bytes(self, sizeof(buf), &buf[0]);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
uint8_t val = buf[i];
|
||||
if (data->state == STATE_ADDR_MATCH_WRITE) {
|
||||
data->state = STATE_MEM_ADDR_SELECT;
|
||||
data->mem_addr = 0;
|
||||
data->mem_addr_count = data->mem_addrsize;
|
||||
}
|
||||
if (data->state == STATE_MEM_ADDR_SELECT && data->mem_addr_count > 0) {
|
||||
data->mem_addr = data->mem_addr << 8 | val;
|
||||
--data->mem_addr_count;
|
||||
if (data->mem_addr_count == 0) {
|
||||
data->mem_addr %= data->mem_len;
|
||||
handle_event(data, I2C_TARGET_IRQ_MEM_ADDR_MATCH);
|
||||
}
|
||||
} else {
|
||||
if (data->state == STATE_MEM_ADDR_SELECT) {
|
||||
data->state = STATE_WRITING;
|
||||
}
|
||||
data->mem_buf[data->mem_addr++] = val;
|
||||
if (data->mem_addr >= data->mem_len) {
|
||||
data->mem_addr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void machine_i2c_target_data_restart_or_stop(machine_i2c_target_data_t *data) {
|
||||
machine_i2c_target_data_reset_helper(data);
|
||||
}
|
||||
|
||||
static inline void machine_i2c_target_data_stop(machine_i2c_target_data_t *data) {
|
||||
machine_i2c_target_data_reset_helper(data);
|
||||
}
|
||||
|
||||
// The port provides implementations of its bindings in this file.
|
||||
#include MICROPY_PY_MACHINE_I2C_TARGET_INCLUDEFILE
|
||||
|
||||
static void machine_i2c_target_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
size_t index = mp_machine_i2c_target_get_index(self);
|
||||
machine_i2c_target_data_t *data = &machine_i2c_target_data[index];
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
// Load attribute.
|
||||
if (attr == MP_QSTR_memaddr) {
|
||||
dest[0] = mp_obj_new_int(data->mem_addr_last);
|
||||
} else {
|
||||
// Continue lookup in locals_dict.
|
||||
dest[1] = MP_OBJ_SENTINEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I2CTarget.deinit()
|
||||
static mp_obj_t machine_i2c_target_deinit(mp_obj_t self_in) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
size_t index = mp_machine_i2c_target_get_index(self);
|
||||
if (machine_i2c_target_data[index].state != STATE_INACTIVE) {
|
||||
machine_i2c_target_data[index].state = STATE_INACTIVE;
|
||||
mp_machine_i2c_target_deinit(self);
|
||||
MP_STATE_PORT(machine_i2c_target_mem_obj[index]) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(machine_i2c_target_irq_obj[index]) = NULL;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_target_deinit_obj, machine_i2c_target_deinit);
|
||||
|
||||
// I2CTarget.readinto(buf)
|
||||
static mp_obj_t machine_i2c_target_readinto(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_i2c_target_read_bytes(self, bufinfo.len, bufinfo.buf));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_target_readinto_obj, machine_i2c_target_readinto);
|
||||
|
||||
// I2CTarget.write(data)
|
||||
static mp_obj_t machine_i2c_target_write(mp_obj_t self_in, mp_obj_t data_in) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
|
||||
return MP_OBJ_NEW_SMALL_INT(mp_machine_i2c_target_write_bytes(self, bufinfo.len, bufinfo.buf));
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(machine_i2c_target_write_obj, machine_i2c_target_write);
|
||||
|
||||
static machine_i2c_target_irq_obj_t *machine_i2c_target_get_irq(machine_i2c_target_obj_t *self) {
|
||||
// Get the IRQ object.
|
||||
size_t index = mp_machine_i2c_target_get_index(self);
|
||||
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
|
||||
|
||||
// Allocate the IRQ object if it doesn't already exist.
|
||||
if (irq == NULL) {
|
||||
irq = m_new_obj(machine_i2c_target_irq_obj_t);
|
||||
irq->base.base.type = &mp_irq_type;
|
||||
irq->base.methods = (mp_irq_methods_t *)&machine_i2c_target_irq_methods;
|
||||
irq->base.parent = MP_OBJ_FROM_PTR(self);
|
||||
irq->base.handler = mp_const_none;
|
||||
irq->base.ishard = false;
|
||||
MP_STATE_PORT(machine_i2c_target_irq_obj[index]) = irq;
|
||||
}
|
||||
return irq;
|
||||
}
|
||||
|
||||
// I2CTarget.irq(handler=None, trigger=IRQ_END_READ|IRQ_END_WRITE, hard=False)
|
||||
static mp_obj_t machine_i2c_target_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_handler, ARG_trigger, ARG_hard };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_trigger, MP_ARG_INT, {.u_int = I2C_TARGET_IRQ_END_READ | I2C_TARGET_IRQ_END_WRITE} },
|
||||
{ MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
machine_i2c_target_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);
|
||||
|
||||
machine_i2c_target_irq_obj_t *irq = machine_i2c_target_get_irq(self);
|
||||
|
||||
if (n_args > 1 || kw_args->used != 0) {
|
||||
// Update IRQ data.
|
||||
mp_obj_t handler = args[ARG_handler].u_obj;
|
||||
mp_uint_t trigger = args[ARG_trigger].u_int;
|
||||
bool hard = args[ARG_hard].u_bool;
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
|
||||
if ((trigger & I2C_TARGET_IRQ_ALL_HARD) && !hard) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ required"));
|
||||
}
|
||||
#else
|
||||
if (hard) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("hard IRQ unsupported"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Disable all IRQs while data is updated.
|
||||
mp_machine_i2c_target_irq_config(self, 0);
|
||||
|
||||
// Update IRQ data.
|
||||
irq->base.handler = handler;
|
||||
irq->base.ishard = hard;
|
||||
irq->flags = 0;
|
||||
irq->trigger = trigger;
|
||||
|
||||
// Enable IRQ if a handler is given.
|
||||
if (handler != mp_const_none && trigger != 0) {
|
||||
mp_machine_i2c_target_irq_config(self, trigger);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(irq);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_target_irq_obj, 1, machine_i2c_target_irq);
|
||||
|
||||
static const mp_rom_map_elem_t machine_i2c_target_locals_dict_table[] = {
|
||||
#if MICROPY_PY_MACHINE_I2C_TARGET_FINALISER
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_i2c_target_deinit_obj) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2c_target_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&machine_i2c_target_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&machine_i2c_target_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_i2c_target_irq_obj) },
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C_TARGET_HARD_IRQ
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_READ), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_READ) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_ADDR_MATCH_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_ADDR_MATCH_WRITE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_READ_REQ), MP_ROM_INT(I2C_TARGET_IRQ_READ_REQ) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_WRITE_REQ), MP_ROM_INT(I2C_TARGET_IRQ_WRITE_REQ) },
|
||||
#endif
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_READ), MP_ROM_INT(I2C_TARGET_IRQ_END_READ) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_IRQ_END_WRITE), MP_ROM_INT(I2C_TARGET_IRQ_END_WRITE) },
|
||||
};
|
||||
static MP_DEFINE_CONST_DICT(machine_i2c_target_locals_dict, machine_i2c_target_locals_dict_table);
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
machine_i2c_target_type,
|
||||
MP_QSTR_I2CTarget,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
make_new, mp_machine_i2c_target_make_new,
|
||||
print, mp_machine_i2c_target_print,
|
||||
attr, &machine_i2c_target_attr,
|
||||
locals_dict, &machine_i2c_target_locals_dict
|
||||
);
|
||||
|
||||
static mp_uint_t machine_i2c_target_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
size_t index = mp_machine_i2c_target_get_index(self);
|
||||
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
|
||||
mp_machine_i2c_target_irq_config(self, 0);
|
||||
irq->flags = 0;
|
||||
irq->trigger = new_trigger;
|
||||
mp_machine_i2c_target_irq_config(self, new_trigger);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mp_uint_t machine_i2c_target_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
|
||||
machine_i2c_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
size_t index = mp_machine_i2c_target_get_index(self);
|
||||
machine_i2c_target_irq_obj_t *irq = MP_STATE_PORT(machine_i2c_target_irq_obj[index]);
|
||||
if (info_type == MP_IRQ_INFO_FLAGS) {
|
||||
return irq->flags;
|
||||
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
|
||||
return irq->trigger;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const mp_irq_methods_t machine_i2c_target_irq_methods = {
|
||||
.trigger = machine_i2c_target_irq_trigger,
|
||||
.info = machine_i2c_target_irq_info,
|
||||
};
|
||||
|
||||
#if !MICROPY_PY_MACHINE_I2C_TARGET_FINALISER
|
||||
void mp_machine_i2c_target_deinit_all(void) {
|
||||
for (size_t i = 0; i < MICROPY_PY_MACHINE_I2C_TARGET_MAX; ++i) {
|
||||
if (machine_i2c_target_data[i].state != STATE_INACTIVE) {
|
||||
machine_i2c_target_deinit(MP_OBJ_FROM_PTR(&machine_i2c_target_obj[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MICROPY_PY_MACHINE_I2C_TARGET
|
||||
@@ -30,35 +30,20 @@
|
||||
|
||||
#if MICROPY_PY_MACHINE_PULSE
|
||||
|
||||
mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
|
||||
mp_uint_t nchanges = 2;
|
||||
MP_WEAK mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us) {
|
||||
mp_uint_t start = mp_hal_ticks_us();
|
||||
for (;;) {
|
||||
// Sample ticks and pin as close together as possible, and always in the same
|
||||
// order each time around the loop. This gives the most accurate measurement.
|
||||
mp_uint_t t = mp_hal_ticks_us();
|
||||
int pin_value = mp_hal_pin_read(pin);
|
||||
|
||||
if (pin_value == pulse_level) {
|
||||
// Pin is at desired value. Flip desired value and see if we are done.
|
||||
pulse_level = 1 - pulse_level;
|
||||
if (--nchanges == 0) {
|
||||
return t - start;
|
||||
}
|
||||
start = t;
|
||||
} else {
|
||||
// Pin hasn't changed yet, check for timeout.
|
||||
mp_uint_t dt = t - start;
|
||||
if (dt >= timeout_us) {
|
||||
return -nchanges;
|
||||
}
|
||||
|
||||
// Allow a port to perform background task processing if needed.
|
||||
#ifdef MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK
|
||||
MICROPY_PY_MACHINE_TIME_PULSE_US_HOOK(dt);
|
||||
#endif
|
||||
while (mp_hal_pin_read(pin) != pulse_level) {
|
||||
if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {
|
||||
return (mp_uint_t)-2;
|
||||
}
|
||||
}
|
||||
start = mp_hal_ticks_us();
|
||||
while (mp_hal_pin_read(pin) == pulse_level) {
|
||||
if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) {
|
||||
return (mp_uint_t)-1;
|
||||
}
|
||||
}
|
||||
return mp_hal_ticks_us() - start;
|
||||
}
|
||||
|
||||
static mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
@@ -108,7 +108,7 @@ static mp_obj_t usb_device_submit_xfer(mp_obj_t self, mp_obj_t ep, mp_obj_t buff
|
||||
//
|
||||
// This C layer doesn't otherwise keep track of which endpoints the host
|
||||
// is aware of (or not).
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("ep"));
|
||||
mp_raise_ValueError("ep");
|
||||
}
|
||||
|
||||
if (!usbd_edpt_claim(USBD_RHPORT, ep_addr)) {
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
|
||||
#define MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// If you want to debug MBEDTLS uncomment the following and
|
||||
// pass "3" to mbedtls_debug_set_threshold in socket_new.
|
||||
// #define MBEDTLS_DEBUG_C
|
||||
@@ -91,18 +89,12 @@
|
||||
#define MBEDTLS_SHA384_C
|
||||
#define MBEDTLS_SHA512_C
|
||||
#define MBEDTLS_SSL_CLI_C
|
||||
#define MBEDTLS_SSL_PROTO_DTLS
|
||||
#define MBEDTLS_SSL_SRV_C
|
||||
#define MBEDTLS_SSL_TLS_C
|
||||
#define MBEDTLS_X509_CRT_PARSE_C
|
||||
#define MBEDTLS_X509_USE_C
|
||||
|
||||
#if MICROPY_PY_SSL_DTLS
|
||||
#define MBEDTLS_SSL_PROTO_DTLS
|
||||
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
|
||||
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
#define MBEDTLS_SSL_COOKIE_C
|
||||
#endif
|
||||
|
||||
// A port may enable this option to select additional bare-metal configuration.
|
||||
#if MICROPY_MBEDTLS_CONFIG_BARE_METAL
|
||||
|
||||
@@ -123,8 +115,4 @@ void m_tracked_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
// Workaround for a mimxrt platform driver header that defines ARRAY_SIZE,
|
||||
// which is also defined in some mbedtls source files.
|
||||
#undef ARRAY_SIZE
|
||||
|
||||
#endif // MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
|
||||
|
||||
@@ -290,13 +290,12 @@ static mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
static mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 2) {
|
||||
// Boolean enable/disable argument supplied, set current state.
|
||||
int err;
|
||||
if (mp_obj_is_true(args[1])) {
|
||||
err = mp_bluetooth_init();
|
||||
int err = mp_bluetooth_init();
|
||||
bluetooth_handle_errno(err);
|
||||
} else {
|
||||
err = mp_bluetooth_deinit();
|
||||
mp_bluetooth_deinit();
|
||||
}
|
||||
bluetooth_handle_errno(err);
|
||||
}
|
||||
// Return current state.
|
||||
return mp_obj_new_bool(mp_bluetooth_is_active());
|
||||
@@ -341,7 +340,7 @@ static mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kwargs->alloc; ++i) {
|
||||
if (mp_map_slot_is_filled(kwargs, i)) {
|
||||
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
|
||||
mp_map_elem_t *e = &kwargs->table[i];
|
||||
switch (mp_obj_str_get_qstr(e->key)) {
|
||||
case MP_QSTR_gap_name: {
|
||||
|
||||
@@ -295,7 +295,7 @@ extern const mp_obj_type_t mp_type_bluetooth_uuid;
|
||||
int mp_bluetooth_init(void);
|
||||
|
||||
// Disables the Bluetooth stack. Is a no-op when not enabled.
|
||||
int mp_bluetooth_deinit(void);
|
||||
void mp_bluetooth_deinit(void);
|
||||
|
||||
// Returns true when the Bluetooth stack is active.
|
||||
bool mp_bluetooth_is_active(void);
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "py/runtime.h"
|
||||
#include <string.h>
|
||||
|
||||
void *__wrap_malloc(size_t size) {
|
||||
// Allocate an extra sizeof(size_t) bytes
|
||||
size_t *addr = (size_t *)m_tracked_calloc(sizeof(uint8_t), size + sizeof(size_t));
|
||||
// Tag our memory with its allocated size
|
||||
*addr = size;
|
||||
// Skip past the size_t size
|
||||
addr++;
|
||||
#ifdef BTREE_DEBUG_MALLOC
|
||||
mp_printf(&mp_plat_print, "malloc %lu %p : %p\n", size, addr, (uint8_t *)addr + size);
|
||||
#endif
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
void __wrap_free(void *p) {
|
||||
size_t *pp = (size_t *)p; // Convert our void pointer to size_t* so we can read the size marker
|
||||
pp--; // Skip back to get our real start
|
||||
size_t size __attribute__((unused)) = *pp;
|
||||
m_tracked_free((void *)pp);
|
||||
#ifdef BTREE_DEBUG_MALLOC
|
||||
mp_printf(&mp_plat_print, "free %p (size %d)\n", p, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *__wrap_realloc(void *p, size_t size) {
|
||||
void *addr = __wrap_malloc(size);
|
||||
size_t old_size = *((size_t *)p - 1);
|
||||
memcpy(addr, p, old_size < size ? old_size : size);
|
||||
__wrap_free(p);
|
||||
#ifdef BTREE_DEBUG_MALLOC
|
||||
mp_printf(&mp_plat_print, "realloc %lu -> %lu, %p -> %p : %p\n", old_size, size, p, addr, (uint8_t *)addr + size);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
void *__wrap_calloc(size_t nitems, size_t size) {
|
||||
return __wrap_malloc(size * nitems);
|
||||
}
|
||||
@@ -270,7 +270,8 @@ static void fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, u
|
||||
formats[fb->format].fill_rect(fb, x, y, xend - x, yend - y, col);
|
||||
}
|
||||
|
||||
static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in, unsigned int buf_flags, mp_obj_framebuf_t *o) {
|
||||
static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
mp_arg_check_num(n_args, n_kw, 4, 5, false);
|
||||
|
||||
mp_int_t width = mp_obj_get_int(args_in[1]);
|
||||
mp_int_t height = mp_obj_get_int(args_in[2]);
|
||||
@@ -317,15 +318,13 @@ static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in,
|
||||
}
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args_in[0], &bufinfo, buf_flags);
|
||||
mp_get_buffer_raise(args_in[0], &bufinfo, MP_BUFFER_WRITE);
|
||||
|
||||
if ((strides_required * stride + (height_required - strides_required) * width_required) * bpp / 8 > bufinfo.len) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
|
||||
if (o == NULL) {
|
||||
o = mp_obj_malloc(mp_obj_framebuf_t, (const mp_obj_type_t *)&mp_type_framebuf);
|
||||
}
|
||||
mp_obj_framebuf_t *o = mp_obj_malloc(mp_obj_framebuf_t, type);
|
||||
o->buf_obj = args_in[0];
|
||||
o->buf = bufinfo.buf;
|
||||
o->width = width;
|
||||
@@ -336,11 +335,6 @@ static mp_obj_t framebuf_make_new_helper(size_t n_args, const mp_obj_t *args_in,
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
static mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
|
||||
mp_arg_check_num(n_args, n_kw, 4, 5, false);
|
||||
return framebuf_make_new_helper(n_args, args_in, MP_BUFFER_WRITE, NULL);
|
||||
}
|
||||
|
||||
static void framebuf_args(const mp_obj_t *args_in, mp_int_t *args_out, int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
args_out[i] = mp_obj_get_int(args_in[i + 1]);
|
||||
@@ -713,27 +707,13 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf_poly_obj, 5, 6, framebuf_pol
|
||||
|
||||
#endif // MICROPY_PY_ARRAY
|
||||
|
||||
static void get_readonly_framebuffer(mp_obj_t arg, mp_obj_framebuf_t *rofb) {
|
||||
mp_obj_t fb = mp_obj_cast_to_native_base(arg, MP_OBJ_FROM_PTR(&mp_type_framebuf));
|
||||
if (fb != MP_OBJ_NULL) {
|
||||
*rofb = *(mp_obj_framebuf_t *)MP_OBJ_TO_PTR(fb);
|
||||
} else {
|
||||
// A tuple/list of the form: (buffer, width, height, format[, stride]).
|
||||
size_t len;
|
||||
mp_obj_t *items;
|
||||
mp_obj_get_array(arg, &len, &items);
|
||||
if (len < 4 || len > 5) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
framebuf_make_new_helper(len, items, MP_BUFFER_READ, rofb);
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
|
||||
mp_obj_framebuf_t *self = MP_OBJ_TO_PTR(args_in[0]);
|
||||
|
||||
mp_obj_framebuf_t source;
|
||||
get_readonly_framebuffer(args_in[1], &source);
|
||||
mp_obj_t source_in = mp_obj_cast_to_native_base(args_in[1], MP_OBJ_FROM_PTR(&mp_type_framebuf));
|
||||
if (source_in == MP_OBJ_NULL) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
mp_obj_framebuf_t *source = MP_OBJ_TO_PTR(source_in);
|
||||
|
||||
mp_int_t x = mp_obj_get_int(args_in[2]);
|
||||
mp_int_t y = mp_obj_get_int(args_in[3]);
|
||||
@@ -741,17 +721,16 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
|
||||
if (n_args > 4) {
|
||||
key = mp_obj_get_int(args_in[4]);
|
||||
}
|
||||
mp_obj_framebuf_t palette;
|
||||
palette.buf = NULL;
|
||||
mp_obj_framebuf_t *palette = NULL;
|
||||
if (n_args > 5 && args_in[5] != mp_const_none) {
|
||||
get_readonly_framebuffer(args_in[5], &palette);
|
||||
palette = MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(args_in[5], MP_OBJ_FROM_PTR(&mp_type_framebuf)));
|
||||
}
|
||||
|
||||
if (
|
||||
(x >= self->width) ||
|
||||
(y >= self->height) ||
|
||||
(-x >= source.width) ||
|
||||
(-y >= source.height)
|
||||
(-x >= source->width) ||
|
||||
(-y >= source->height)
|
||||
) {
|
||||
// Out of bounds, no-op.
|
||||
return mp_const_none;
|
||||
@@ -762,15 +741,15 @@ static mp_obj_t framebuf_blit(size_t n_args, const mp_obj_t *args_in) {
|
||||
int y0 = MAX(0, y);
|
||||
int x1 = MAX(0, -x);
|
||||
int y1 = MAX(0, -y);
|
||||
int x0end = MIN(self->width, x + source.width);
|
||||
int y0end = MIN(self->height, y + source.height);
|
||||
int x0end = MIN(self->width, x + source->width);
|
||||
int y0end = MIN(self->height, y + source->height);
|
||||
|
||||
for (; y0 < y0end; ++y0) {
|
||||
int cx1 = x1;
|
||||
for (int cx0 = x0; cx0 < x0end; ++cx0) {
|
||||
uint32_t col = getpixel(&source, cx1, y1);
|
||||
if (palette.buf) {
|
||||
col = getpixel(&palette, col, 0);
|
||||
uint32_t col = getpixel(source, cx1, y1);
|
||||
if (palette) {
|
||||
col = getpixel(palette, col, 0);
|
||||
}
|
||||
if (col != (uint32_t)key) {
|
||||
setpixel(self, cx0, y0, col);
|
||||
|
||||
@@ -160,8 +160,7 @@ static mp_obj_t mod_json_load(mp_obj_t stream_obj) {
|
||||
for (;;) {
|
||||
cont:
|
||||
if (S_END(s)) {
|
||||
// Input finished abruptly in the middle of a composite entity.
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
mp_obj_t next = MP_OBJ_NULL;
|
||||
bool enter = false;
|
||||
|
||||
305
extmod/modlwip.c
305
extmod/modlwip.c
@@ -70,10 +70,6 @@
|
||||
|
||||
#define TCP_NODELAY TF_NODELAY
|
||||
|
||||
// Socket flags
|
||||
#define MSG_PEEK 0x01
|
||||
#define MSG_DONTWAIT 0x02
|
||||
|
||||
// For compatibilily with older lwIP versions.
|
||||
#ifndef ip_set_option
|
||||
#define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt))
|
||||
@@ -290,15 +286,6 @@ static const int error_lookup_table[] = {
|
||||
#define MOD_NETWORK_SOCK_DGRAM (2)
|
||||
#define MOD_NETWORK_SOCK_RAW (3)
|
||||
|
||||
// Total queue length for buffered UDP/raw incoming packets.
|
||||
#define LWIP_INCOMING_PACKET_QUEUE_LEN (4)
|
||||
|
||||
typedef struct _lwip_incoming_packet_t {
|
||||
struct pbuf *pbuf;
|
||||
ip_addr_t peer_addr;
|
||||
uint16_t peer_port;
|
||||
} lwip_incoming_packet_t;
|
||||
|
||||
typedef struct _lwip_socket_obj_t {
|
||||
mp_obj_base_t base;
|
||||
|
||||
@@ -307,11 +294,8 @@ typedef struct _lwip_socket_obj_t {
|
||||
struct udp_pcb *udp;
|
||||
struct raw_pcb *raw;
|
||||
} pcb;
|
||||
|
||||
// Data structure that holds incoming pbuf's.
|
||||
// Each socket type has different state that it needs to keep track of.
|
||||
volatile union {
|
||||
// TCP listening sockets have a queue of incoming connections, implemented as a ringbuffer.
|
||||
struct pbuf *pbuf;
|
||||
struct {
|
||||
uint8_t alloc;
|
||||
uint8_t iget;
|
||||
@@ -321,23 +305,10 @@ typedef struct _lwip_socket_obj_t {
|
||||
struct tcp_pcb **array; // if alloc != 0
|
||||
} tcp;
|
||||
} connection;
|
||||
|
||||
// Connected TCP sockets have a single incoming pbuf that new data is appended to.
|
||||
struct {
|
||||
struct pbuf *pbuf;
|
||||
} tcp;
|
||||
|
||||
// UDP and raw sockets have a queue of incoming pbuf's, implemented as a ringbuffer.
|
||||
struct {
|
||||
uint8_t iget; // ringbuffer read index
|
||||
uint8_t iput; // ringbuffer write index
|
||||
lwip_incoming_packet_t *array;
|
||||
} udp_raw;
|
||||
} incoming;
|
||||
|
||||
mp_obj_t callback;
|
||||
ip_addr_t tcp_peer_addr;
|
||||
mp_uint_t tcp_peer_port;
|
||||
ip_addr_t peer;
|
||||
mp_uint_t peer_port;
|
||||
mp_uint_t timeout;
|
||||
uint16_t recv_offset;
|
||||
|
||||
@@ -376,21 +347,9 @@ static void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
|
||||
&& socket->pcb.tcp->state == LISTEN;
|
||||
|
||||
if (!socket_is_listener) {
|
||||
if (socket->type == MOD_NETWORK_SOCK_STREAM) {
|
||||
if (socket->incoming.tcp.pbuf != NULL) {
|
||||
pbuf_free(socket->incoming.tcp.pbuf);
|
||||
socket->incoming.tcp.pbuf = NULL;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) {
|
||||
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[i];
|
||||
if (slot->pbuf != NULL) {
|
||||
pbuf_free(slot->pbuf);
|
||||
slot->pbuf = NULL;
|
||||
}
|
||||
}
|
||||
socket->incoming.udp_raw.iget = 0;
|
||||
socket->incoming.udp_raw.iput = 0;
|
||||
if (socket->incoming.pbuf != NULL) {
|
||||
pbuf_free(socket->incoming.pbuf);
|
||||
socket->incoming.pbuf = NULL;
|
||||
}
|
||||
} else {
|
||||
uint8_t alloc = socket->incoming.connection.alloc;
|
||||
@@ -448,19 +407,6 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) {
|
||||
}
|
||||
}
|
||||
|
||||
static void udp_raw_incoming(lwip_socket_obj_t *socket, struct pbuf *p, const ip_addr_t *addr, u16_t port) {
|
||||
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iput];
|
||||
if (slot->pbuf != NULL) {
|
||||
// No room in the inn, drop the packet.
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
slot->pbuf = p;
|
||||
slot->peer_addr = *addr;
|
||||
slot->peer_port = port;
|
||||
socket->incoming.udp_raw.iput = (socket->incoming.udp_raw.iput + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
// Callback for incoming raw packets.
|
||||
#if LWIP_VERSION_MAJOR < 2
|
||||
@@ -470,7 +416,13 @@ static u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, c
|
||||
#endif
|
||||
{
|
||||
lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
|
||||
udp_raw_incoming(socket, p, addr, 0);
|
||||
|
||||
if (socket->incoming.pbuf != NULL) {
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
socket->incoming.pbuf = p;
|
||||
memcpy(&socket->peer, addr, sizeof(socket->peer));
|
||||
}
|
||||
return 1; // we ate the packet
|
||||
}
|
||||
#endif
|
||||
@@ -484,7 +436,15 @@ static void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||
#endif
|
||||
{
|
||||
lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
|
||||
udp_raw_incoming(socket, p, addr, port);
|
||||
|
||||
if (socket->incoming.pbuf != NULL) {
|
||||
// That's why they call it "unreliable". No room in the inn, drop the packet.
|
||||
pbuf_free(p);
|
||||
} else {
|
||||
socket->incoming.pbuf = p;
|
||||
socket->peer_port = (mp_uint_t)port;
|
||||
memcpy(&socket->peer, addr, sizeof(socket->peer));
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for general tcp errors.
|
||||
@@ -602,13 +562,13 @@ static err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
if (socket->incoming.tcp.pbuf == NULL) {
|
||||
socket->incoming.tcp.pbuf = p;
|
||||
if (socket->incoming.pbuf == NULL) {
|
||||
socket->incoming.pbuf = p;
|
||||
} else {
|
||||
#ifdef SOCKET_SINGLE_PBUF
|
||||
return ERR_BUF;
|
||||
#else
|
||||
pbuf_cat(socket->incoming.tcp.pbuf, p);
|
||||
pbuf_cat(socket->incoming.pbuf, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -677,20 +637,18 @@ static mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, m
|
||||
}
|
||||
|
||||
// Helper function for recv/recvfrom to handle raw/UDP packets
|
||||
static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, ip_addr_t *ip, mp_uint_t *port, int *_errno) {
|
||||
static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, ip_addr_t *ip, mp_uint_t *port, int *_errno) {
|
||||
|
||||
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget];
|
||||
|
||||
if (slot->pbuf == NULL) {
|
||||
// Non-blocking socket or flag
|
||||
if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) {
|
||||
if (socket->incoming.pbuf == NULL) {
|
||||
if (socket->timeout == 0) {
|
||||
// Non-blocking socket.
|
||||
*_errno = MP_EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Wait for data to arrive on UDP socket.
|
||||
mp_uint_t start = mp_hal_ticks_ms();
|
||||
while (slot->pbuf == NULL) {
|
||||
while (socket->incoming.pbuf == NULL) {
|
||||
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
|
||||
*_errno = MP_ETIMEDOUT;
|
||||
return -1;
|
||||
@@ -700,20 +658,17 @@ static mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_u
|
||||
}
|
||||
|
||||
if (ip != NULL) {
|
||||
*ip = slot->peer_addr;
|
||||
*port = slot->peer_port;
|
||||
memcpy(ip, &socket->peer, sizeof(socket->peer));
|
||||
*port = socket->peer_port;
|
||||
}
|
||||
|
||||
struct pbuf *p = slot->pbuf;
|
||||
struct pbuf *p = socket->incoming.pbuf;
|
||||
|
||||
MICROPY_PY_LWIP_ENTER
|
||||
|
||||
u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
|
||||
if ((flags & MSG_PEEK) == 0) {
|
||||
pbuf_free(p);
|
||||
slot->pbuf = NULL;
|
||||
socket->incoming.udp_raw.iget = (socket->incoming.udp_raw.iget + 1) % LWIP_INCOMING_PACKET_QUEUE_LEN;
|
||||
}
|
||||
pbuf_free(p);
|
||||
socket->incoming.pbuf = NULL;
|
||||
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
|
||||
@@ -821,20 +776,14 @@ static mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
|
||||
}
|
||||
|
||||
// Helper function for recv/recvfrom to handle TCP packets
|
||||
static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_int_t flags, int *_errno) {
|
||||
static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
|
||||
// Check for any pending errors
|
||||
STREAM_ERROR_CHECK(socket);
|
||||
|
||||
if (socket->state == STATE_LISTENING) {
|
||||
// original socket in listening state, not the accepted connection.
|
||||
*_errno = MP_ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
if (socket->incoming.pbuf == NULL) {
|
||||
|
||||
if (socket->incoming.tcp.pbuf == NULL) {
|
||||
|
||||
// Non-blocking socket or flag
|
||||
if (socket->timeout == 0 || (flags & MSG_DONTWAIT)) {
|
||||
// Non-blocking socket
|
||||
if (socket->timeout == 0) {
|
||||
if (socket->state == STATE_PEER_CLOSED) {
|
||||
return 0;
|
||||
}
|
||||
@@ -843,7 +792,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
|
||||
}
|
||||
|
||||
mp_uint_t start = mp_hal_ticks_ms();
|
||||
while (socket->state == STATE_CONNECTED && socket->incoming.tcp.pbuf == NULL) {
|
||||
while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) {
|
||||
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
|
||||
*_errno = MP_ETIMEDOUT;
|
||||
return -1;
|
||||
@@ -852,7 +801,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
|
||||
}
|
||||
|
||||
if (socket->state == STATE_PEER_CLOSED) {
|
||||
if (socket->incoming.tcp.pbuf == NULL) {
|
||||
if (socket->incoming.pbuf == NULL) {
|
||||
// socket closed and no data left in buffer
|
||||
return 0;
|
||||
}
|
||||
@@ -870,7 +819,7 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
|
||||
|
||||
assert(socket->pcb.tcp != NULL);
|
||||
|
||||
struct pbuf *p = socket->incoming.tcp.pbuf;
|
||||
struct pbuf *p = socket->incoming.pbuf;
|
||||
|
||||
mp_uint_t remaining = p->len - socket->recv_offset;
|
||||
if (len > remaining) {
|
||||
@@ -879,21 +828,19 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
|
||||
|
||||
memcpy(buf, (byte *)p->payload + socket->recv_offset, len);
|
||||
|
||||
if ((flags & MSG_PEEK) == 0) {
|
||||
remaining -= len;
|
||||
if (remaining == 0) {
|
||||
socket->incoming.tcp.pbuf = p->next;
|
||||
// If we don't ref here, free() will free the entire chain,
|
||||
// if we ref, it does what we need: frees 1st buf, and decrements
|
||||
// next buf's refcount back to 1.
|
||||
pbuf_ref(p->next);
|
||||
pbuf_free(p);
|
||||
socket->recv_offset = 0;
|
||||
} else {
|
||||
socket->recv_offset += len;
|
||||
}
|
||||
tcp_recved(socket->pcb.tcp, len);
|
||||
remaining -= len;
|
||||
if (remaining == 0) {
|
||||
socket->incoming.pbuf = p->next;
|
||||
// If we don't ref here, free() will free the entire chain,
|
||||
// if we ref, it does what we need: frees 1st buf, and decrements
|
||||
// next buf's refcount back to 1.
|
||||
pbuf_ref(p->next);
|
||||
pbuf_free(p);
|
||||
socket->recv_offset = 0;
|
||||
} else {
|
||||
socket->recv_offset += len;
|
||||
}
|
||||
tcp_recved(socket->pcb.tcp, len);
|
||||
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
|
||||
@@ -907,18 +854,8 @@ static const mp_obj_type_t lwip_socket_type;
|
||||
|
||||
static void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
lwip_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "<socket state=%d timeout=" UINT_FMT " incoming=", self->state, self->timeout);
|
||||
if (self->type == MOD_NETWORK_SOCK_STREAM) {
|
||||
mp_printf(print, "%p off=%d>", self->incoming.tcp.pbuf, self->recv_offset);
|
||||
} else {
|
||||
int num_in_queue = 0;
|
||||
for (size_t i = 0; i < LWIP_INCOMING_PACKET_QUEUE_LEN; ++i) {
|
||||
if (self->incoming.udp_raw.array[i].pbuf != NULL) {
|
||||
++num_in_queue;
|
||||
}
|
||||
}
|
||||
mp_printf(print, "%d>", num_in_queue);
|
||||
}
|
||||
mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout,
|
||||
self->incoming.pbuf, self->recv_offset);
|
||||
}
|
||||
|
||||
// FIXME: Only supports two arguments at present
|
||||
@@ -947,22 +884,16 @@ static mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s
|
||||
socket->incoming.connection.tcp.item = NULL;
|
||||
break;
|
||||
case MOD_NETWORK_SOCK_DGRAM:
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
case MOD_NETWORK_SOCK_RAW:
|
||||
#endif
|
||||
if (socket->type == MOD_NETWORK_SOCK_DGRAM) {
|
||||
socket->pcb.udp = udp_new();
|
||||
}
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
else {
|
||||
mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]);
|
||||
socket->pcb.raw = raw_new(proto);
|
||||
}
|
||||
#endif
|
||||
socket->incoming.udp_raw.iget = 0;
|
||||
socket->incoming.udp_raw.iput = 0;
|
||||
socket->incoming.udp_raw.array = m_new0(lwip_incoming_packet_t, LWIP_INCOMING_PACKET_QUEUE_LEN);
|
||||
socket->pcb.udp = udp_new();
|
||||
socket->incoming.pbuf = NULL;
|
||||
break;
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
case MOD_NETWORK_SOCK_RAW: {
|
||||
mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]);
|
||||
socket->pcb.raw = raw_new(proto);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
mp_raise_OSError(MP_EINVAL);
|
||||
}
|
||||
@@ -1144,7 +1075,7 @@ static mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
|
||||
// ...and set up the new socket for it.
|
||||
socket2->domain = MOD_NETWORK_AF_INET;
|
||||
socket2->type = MOD_NETWORK_SOCK_STREAM;
|
||||
socket2->incoming.tcp.pbuf = NULL;
|
||||
socket2->incoming.pbuf = NULL;
|
||||
socket2->timeout = socket->timeout;
|
||||
socket2->state = STATE_CONNECTED;
|
||||
socket2->recv_offset = 0;
|
||||
@@ -1199,8 +1130,8 @@ static mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
socket->state = STATE_NEW;
|
||||
mp_raise_OSError(error_lookup_table[-err]);
|
||||
}
|
||||
socket->tcp_peer_addr = dest;
|
||||
socket->tcp_peer_port = (mp_uint_t)port;
|
||||
socket->peer_port = (mp_uint_t)port;
|
||||
memcpy(&socket->peer, &dest, sizeof(socket->peer));
|
||||
MICROPY_PY_LWIP_EXIT
|
||||
|
||||
// And now we wait...
|
||||
@@ -1285,58 +1216,40 @@ static mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send);
|
||||
|
||||
// Common implementation for recv & recvfrom
|
||||
static mp_obj_t lwip_socket_recv_common(size_t n_args, const mp_obj_t *args, ip_addr_t *ip, mp_uint_t *port) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_int_t len = mp_obj_get_int(args[1]);
|
||||
mp_int_t flags = n_args > 2 ? mp_obj_get_int(args[2]) : 0;
|
||||
static mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
|
||||
int _errno;
|
||||
vstr_t vstr;
|
||||
mp_uint_t ret = 0;
|
||||
|
||||
lwip_socket_check_connected(socket);
|
||||
|
||||
mp_int_t len = mp_obj_get_int(len_in);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, len);
|
||||
|
||||
mp_uint_t ret = 0;
|
||||
switch (socket->type) {
|
||||
case MOD_NETWORK_SOCK_STREAM:
|
||||
if (ip != NULL) {
|
||||
*ip = socket->tcp_peer_addr;
|
||||
*port = (mp_uint_t)socket->tcp_peer_port;
|
||||
}
|
||||
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, flags, &_errno);
|
||||
case MOD_NETWORK_SOCK_STREAM: {
|
||||
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
|
||||
break;
|
||||
}
|
||||
case MOD_NETWORK_SOCK_DGRAM:
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
case MOD_NETWORK_SOCK_RAW:
|
||||
#endif
|
||||
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, flags, ip, port, &_errno);
|
||||
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, NULL, NULL, &_errno);
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
return mp_const_empty_bytes;
|
||||
}
|
||||
vstr.len = ret;
|
||||
return mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
|
||||
static mp_obj_t lwip_socket_recv(size_t n_args, const mp_obj_t *args) {
|
||||
return lwip_socket_recv_common(n_args, args, NULL, NULL);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recv_obj, 2, 3, lwip_socket_recv);
|
||||
|
||||
static mp_obj_t lwip_socket_recvfrom(size_t n_args, const mp_obj_t *args) {
|
||||
ip_addr_t ip;
|
||||
mp_uint_t port;
|
||||
mp_obj_t tuple[2];
|
||||
tuple[0] = lwip_socket_recv_common(n_args, args, &ip, &port);
|
||||
tuple[1] = lwip_format_inet_addr(&ip, port);
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_recvfrom_obj, 2, 3, lwip_socket_recvfrom);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv);
|
||||
|
||||
static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
|
||||
@@ -1371,6 +1284,50 @@ static mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto);
|
||||
|
||||
static mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
|
||||
int _errno;
|
||||
|
||||
lwip_socket_check_connected(socket);
|
||||
|
||||
mp_int_t len = mp_obj_get_int(len_in);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, len);
|
||||
ip_addr_t ip;
|
||||
mp_uint_t port;
|
||||
|
||||
mp_uint_t ret = 0;
|
||||
switch (socket->type) {
|
||||
case MOD_NETWORK_SOCK_STREAM: {
|
||||
memcpy(&ip, &socket->peer, sizeof(socket->peer));
|
||||
port = (mp_uint_t)socket->peer_port;
|
||||
ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
|
||||
break;
|
||||
}
|
||||
case MOD_NETWORK_SOCK_DGRAM:
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
case MOD_NETWORK_SOCK_RAW:
|
||||
#endif
|
||||
ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, &ip, &port, &_errno);
|
||||
break;
|
||||
}
|
||||
if (ret == -1) {
|
||||
mp_raise_OSError(_errno);
|
||||
}
|
||||
|
||||
mp_obj_t tuple[2];
|
||||
if (ret == 0) {
|
||||
tuple[0] = mp_const_empty_bytes;
|
||||
} else {
|
||||
vstr.len = ret;
|
||||
tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
|
||||
}
|
||||
tuple[1] = lwip_format_inet_addr(&ip, port);
|
||||
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom);
|
||||
|
||||
static mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
|
||||
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
|
||||
lwip_socket_check_connected(socket);
|
||||
@@ -1530,12 +1487,12 @@ static mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, i
|
||||
|
||||
switch (socket->type) {
|
||||
case MOD_NETWORK_SOCK_STREAM:
|
||||
return lwip_tcp_receive(socket, buf, size, 0, errcode);
|
||||
return lwip_tcp_receive(socket, buf, size, errcode);
|
||||
case MOD_NETWORK_SOCK_DGRAM:
|
||||
#if MICROPY_PY_LWIP_SOCK_RAW
|
||||
case MOD_NETWORK_SOCK_RAW:
|
||||
#endif
|
||||
return lwip_raw_udp_receive(socket, buf, size, 0, NULL, NULL, errcode);
|
||||
return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode);
|
||||
}
|
||||
// Unreachable
|
||||
return MP_STREAM_ERROR;
|
||||
@@ -1580,15 +1537,9 @@ static mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
|
||||
if (lwip_socket_incoming_array(socket)[socket->incoming.connection.iget] != NULL) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
} else if (socket->type == MOD_NETWORK_SOCK_STREAM) {
|
||||
// For TCP sockets there is just one slot for incoming data
|
||||
if (socket->incoming.tcp.pbuf != NULL) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
} else {
|
||||
// Otherwise for UDP/raw there is a queue of incoming data
|
||||
lwip_incoming_packet_t *slot = &socket->incoming.udp_raw.array[socket->incoming.udp_raw.iget];
|
||||
if (slot->pbuf != NULL) {
|
||||
// Otherwise there is just one slot for incoming data
|
||||
if (socket->incoming.pbuf != NULL) {
|
||||
ret |= MP_STREAM_POLL_RD;
|
||||
}
|
||||
}
|
||||
@@ -1907,8 +1858,6 @@ static const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IP_PROTO_TCP) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_TCP_NODELAY), MP_ROM_INT(TCP_NODELAY) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MSG_PEEK), MP_ROM_INT(MSG_PEEK) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_MSG_DONTWAIT), MP_ROM_INT(MSG_DONTWAIT) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
static void mp_machine_idle(void);
|
||||
|
||||
#if MICROPY_PY_MACHINE_BOOTLOADER
|
||||
MP_NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_RESET
|
||||
MP_NORETURN static void mp_machine_reset(void);
|
||||
NORETURN static void mp_machine_reset(void);
|
||||
static mp_int_t mp_machine_reset_cause(void);
|
||||
#endif
|
||||
|
||||
@@ -58,7 +58,7 @@ static mp_obj_t mp_machine_unique_id(void);
|
||||
static mp_obj_t mp_machine_get_freq(void);
|
||||
static void mp_machine_set_freq(size_t n_args, const mp_obj_t *args);
|
||||
static void mp_machine_lightsleep(size_t n_args, const mp_obj_t *args);
|
||||
MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
|
||||
NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args);
|
||||
#endif
|
||||
|
||||
// The port can provide additional machine-module implementation in this file.
|
||||
@@ -67,7 +67,7 @@ MP_NORETURN static void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_BOOTLOADER
|
||||
MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
|
||||
mp_machine_bootloader(n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
|
||||
@@ -81,7 +81,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
#if MICROPY_PY_MACHINE_RESET
|
||||
|
||||
MP_NORETURN static mp_obj_t machine_reset(void) {
|
||||
NORETURN static mp_obj_t machine_reset(void) {
|
||||
mp_machine_reset();
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
@@ -116,7 +116,7 @@ static mp_obj_t machine_lightsleep(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_lightsleep_obj, 0, 1, machine_lightsleep);
|
||||
|
||||
MP_NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
|
||||
NORETURN static mp_obj_t machine_deepsleep(size_t n_args, const mp_obj_t *args) {
|
||||
mp_machine_deepsleep(n_args, args);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_deepsleep_obj, 0, 1, machine_deepsleep);
|
||||
@@ -219,9 +219,6 @@ static const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
#if MICROPY_PY_MACHINE_I2C
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_I2C_TARGET
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2CTarget), MP_ROM_PTR(&machine_i2c_target_type) },
|
||||
#endif
|
||||
#if MICROPY_PY_MACHINE_I2S
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
|
||||
#endif
|
||||
|
||||
@@ -129,7 +129,6 @@
|
||||
// A port must provide these types, but they are otherwise opaque.
|
||||
typedef struct _machine_adc_obj_t machine_adc_obj_t;
|
||||
typedef struct _machine_adc_block_obj_t machine_adc_block_obj_t;
|
||||
typedef struct _machine_i2c_target_obj_t machine_i2c_target_obj_t;
|
||||
typedef struct _machine_i2s_obj_t machine_i2s_obj_t;
|
||||
typedef struct _machine_pwm_obj_t machine_pwm_obj_t;
|
||||
typedef struct _machine_uart_obj_t machine_uart_obj_t;
|
||||
@@ -204,7 +203,6 @@ extern const machine_mem_obj_t machine_mem32_obj;
|
||||
extern const mp_obj_type_t machine_adc_type;
|
||||
extern const mp_obj_type_t machine_adc_block_type;
|
||||
extern const mp_obj_type_t machine_i2c_type;
|
||||
extern const mp_obj_type_t machine_i2c_target_type;
|
||||
extern const mp_obj_type_t machine_i2s_type;
|
||||
extern const mp_obj_type_t machine_mem_type;
|
||||
extern const mp_obj_type_t machine_pin_type;
|
||||
@@ -244,7 +242,7 @@ uintptr_t MICROPY_MACHINE_MEM_GET_READ_ADDR(mp_obj_t addr_o, uint align);
|
||||
uintptr_t MICROPY_MACHINE_MEM_GET_WRITE_ADDR(mp_obj_t addr_o, uint align);
|
||||
#endif
|
||||
|
||||
MP_NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
|
||||
void machine_bitstream_high_low(mp_hal_pin_obj_t pin, uint32_t *timing_ns, const uint8_t *buf, size_t len);
|
||||
mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us);
|
||||
|
||||
@@ -263,10 +261,6 @@ int mp_machine_i2c_transfer_adaptor(mp_obj_base_t *self, uint16_t addr, size_t n
|
||||
int mp_machine_soft_i2c_transfer(mp_obj_base_t *self, uint16_t addr, size_t n, mp_machine_i2c_buf_t *bufs, unsigned int flags);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_I2C_TARGET
|
||||
void mp_machine_i2c_target_deinit_all(void);
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_MACHINE_SPI
|
||||
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
|
||||
|
||||
@@ -40,19 +40,6 @@
|
||||
#if MICROPY_PY_NETWORK_CYW43
|
||||
// So that CYW43_LINK_xxx constants are available to MICROPY_PORT_NETWORK_INTERFACES.
|
||||
#include "lib/cyw43-driver/src/cyw43.h"
|
||||
extern const struct _mp_obj_type_t mp_network_cyw43_type;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_WIZNET5K
|
||||
extern const struct _mp_obj_type_t mod_network_nic_type_wiznet5k;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_NINAW10
|
||||
extern const struct _mp_obj_type_t mod_network_nic_type_nina;
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_ESP_HOSTED
|
||||
extern const struct _mp_obj_type_t mod_network_esp_hosted_type;
|
||||
#endif
|
||||
|
||||
#ifdef MICROPY_PY_NETWORK_INCLUDEFILE
|
||||
@@ -179,32 +166,6 @@ static const mp_rom_map_elem_t mp_module_network_globals_table[] = {
|
||||
MICROPY_PORT_NETWORK_INTERFACES
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_CYW43
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mp_network_cyw43_type) },
|
||||
// CYW43 status constants, currently for rp2 port only.
|
||||
// TODO move these to WIFI module for all ports.
|
||||
#if defined(PICO_PROGRAM_NAME) && defined(CYW43_LINK_DOWN)
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(CYW43_LINK_DOWN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(CYW43_LINK_JOIN) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(CYW43_LINK_BADAUTH) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(CYW43_LINK_NONET) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(CYW43_LINK_FAIL) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(CYW43_LINK_UP) },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_WIZNET5K
|
||||
{ MP_ROM_QSTR(MP_QSTR_WIZNET5K), MP_ROM_PTR(&mod_network_nic_type_wiznet5k) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_NINAW10
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_nic_type_nina) },
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_ESP_HOSTED
|
||||
{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&mod_network_esp_hosted_type) },
|
||||
#endif
|
||||
|
||||
// Allow a port to take mostly full control of the network module.
|
||||
#ifdef MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE
|
||||
#include MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE
|
||||
|
||||
@@ -60,11 +60,6 @@ extern char mod_network_country_code[2];
|
||||
#define MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN (32)
|
||||
#endif
|
||||
|
||||
#if MICROPY_PY_NETWORK_NINAW10
|
||||
// This Network interface requires the extended socket state.
|
||||
#define MICROPY_PY_SOCKET_EXTENDED_STATE (1)
|
||||
#endif
|
||||
|
||||
// This is a null-terminated string.
|
||||
extern char mod_network_hostname_data[MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN + 1];
|
||||
|
||||
@@ -82,9 +77,6 @@ extern const struct _mp_obj_type_t mp_network_ppp_lwip_type;
|
||||
#endif
|
||||
|
||||
struct netif;
|
||||
|
||||
void sys_untimeout_all_with_arg(void *arg);
|
||||
|
||||
void mod_network_lwip_init(void);
|
||||
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);
|
||||
|
||||
@@ -427,9 +427,6 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
|
||||
const char *re_str = mp_obj_str_get_str(args[0]);
|
||||
int size = re1_5_sizecode(re_str);
|
||||
if (size == -1) {
|
||||
#if MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_NORMAL
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("regex too complex"));
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type);
|
||||
|
||||
@@ -58,7 +58,7 @@ static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
|
||||
return mp_time_localtime_get();
|
||||
} else {
|
||||
// Convert given seconds to tuple.
|
||||
mp_timestamp_t seconds = timeutils_obj_get_timestamp(args[0]);
|
||||
mp_int_t seconds = mp_obj_get_int(args[0]);
|
||||
timeutils_struct_time_t tm;
|
||||
timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
@@ -90,7 +90,7 @@ static mp_obj_t time_mktime(mp_obj_t tuple) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
|
||||
}
|
||||
|
||||
return timeutils_obj_from_timestamp(timeutils_mktime(mp_obj_get_int(elem[0]),
|
||||
return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
|
||||
mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
|
||||
mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ static const char *const ssl_error_tab2[] = {
|
||||
"NOT_SUPPORTED",
|
||||
};
|
||||
|
||||
static MP_NORETURN void ssl_raise_error(int err) {
|
||||
static NORETURN void ssl_raise_error(int err) {
|
||||
MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN);
|
||||
MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED);
|
||||
|
||||
|
||||
@@ -62,9 +62,6 @@
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/asn1.h"
|
||||
#endif
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
#include "mbedtls/ssl_cookie.h"
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_MBEDTLS_CONFIG_BARE_METAL
|
||||
#define MICROPY_MBEDTLS_CONFIG_BARE_METAL (0)
|
||||
@@ -78,7 +75,7 @@
|
||||
#define MP_PROTOCOL_TLS_CLIENT 0
|
||||
#define MP_PROTOCOL_TLS_SERVER MP_ENDPOINT_IS_SERVER
|
||||
#define MP_PROTOCOL_DTLS_CLIENT MP_TRANSPORT_IS_DTLS
|
||||
#define MP_PROTOCOL_DTLS_SERVER (MP_ENDPOINT_IS_SERVER | MP_TRANSPORT_IS_DTLS)
|
||||
#define MP_PROTOCOL_DTLS_SERVER MP_ENDPOINT_IS_SERVER | MP_TRANSPORT_IS_DTLS
|
||||
|
||||
// This corresponds to an SSLContext object.
|
||||
typedef struct _mp_obj_ssl_context_t {
|
||||
@@ -95,10 +92,6 @@ typedef struct _mp_obj_ssl_context_t {
|
||||
#if MICROPY_PY_SSL_ECDSA_SIGN_ALT
|
||||
mp_obj_t ecdsa_sign_callback;
|
||||
#endif
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
bool is_dtls_server;
|
||||
mbedtls_ssl_cookie_ctx cookie_ctx;
|
||||
#endif
|
||||
} mp_obj_ssl_context_t;
|
||||
|
||||
// This corresponds to an SSLSocket object.
|
||||
@@ -124,8 +117,7 @@ static const mp_obj_type_t ssl_socket_type;
|
||||
static const MP_DEFINE_STR_OBJ(mbedtls_version_obj, MBEDTLS_VERSION_STRING_FULL);
|
||||
|
||||
static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
|
||||
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname,
|
||||
mp_obj_t client_id);
|
||||
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname);
|
||||
|
||||
/******************************************************************************/
|
||||
// Helper functions.
|
||||
@@ -155,7 +147,7 @@ static const unsigned char *asn1_get_data(mp_obj_t obj, size_t *out_len) {
|
||||
return (const unsigned char *)str;
|
||||
}
|
||||
|
||||
static MP_NORETURN void mbedtls_raise_error(int err) {
|
||||
static NORETURN void mbedtls_raise_error(int err) {
|
||||
// Handle special cases.
|
||||
if (err == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
|
||||
mp_raise_OSError(MP_ENOMEM);
|
||||
@@ -328,19 +320,6 @@ static mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
|
||||
mbedtls_ssl_conf_dbg(&self->conf, mbedtls_debug, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
self->is_dtls_server = (protocol == MP_PROTOCOL_DTLS_SERVER);
|
||||
if (self->is_dtls_server) {
|
||||
mbedtls_ssl_cookie_init(&self->cookie_ctx);
|
||||
ret = mbedtls_ssl_cookie_setup(&self->cookie_ctx, mbedtls_ctr_drbg_random, &self->ctr_drbg);
|
||||
if (ret != 0) {
|
||||
mbedtls_raise_error(ret);
|
||||
}
|
||||
mbedtls_ssl_conf_dtls_cookies(&self->conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check,
|
||||
&self->cookie_ctx);
|
||||
}
|
||||
#endif // MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
@@ -387,11 +366,6 @@ static mp_obj_t ssl_context___del__(mp_obj_t self_in) {
|
||||
mbedtls_ctr_drbg_free(&self->ctr_drbg);
|
||||
mbedtls_entropy_free(&self->entropy);
|
||||
mbedtls_ssl_config_free(&self->conf);
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
if (self->is_dtls_server) {
|
||||
mbedtls_ssl_cookie_free(&self->cookie_ctx);
|
||||
}
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(ssl_context___del___obj, ssl_context___del__);
|
||||
@@ -494,14 +468,11 @@ static mp_obj_t ssl_context_load_verify_locations(mp_obj_t self_in, mp_obj_t cad
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(ssl_context_load_verify_locations_obj, ssl_context_load_verify_locations);
|
||||
|
||||
static mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname, ARG_client_id };
|
||||
enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_do_handshake_on_connect, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
|
||||
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
{ MP_QSTR_client_id, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
#endif
|
||||
};
|
||||
|
||||
// Parse arguments.
|
||||
@@ -510,14 +481,9 @@ static mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args,
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t client_id = mp_const_none;
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
client_id = args[ARG_client_id].u_obj;
|
||||
#endif
|
||||
|
||||
// Create and return the new SSLSocket object.
|
||||
return ssl_socket_make_new(self, sock, args[ARG_server_side].u_bool,
|
||||
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj, client_id);
|
||||
args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_wrap_socket_obj, 2, ssl_context_wrap_socket);
|
||||
|
||||
@@ -614,7 +580,7 @@ static int _mbedtls_timing_get_delay(void *ctx) {
|
||||
#endif
|
||||
|
||||
static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
|
||||
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname, mp_obj_t client_id) {
|
||||
bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname) {
|
||||
|
||||
// Store the current SSL context.
|
||||
store_active_context(ssl_context);
|
||||
@@ -639,7 +605,7 @@ static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
||||
|
||||
ret = mbedtls_ssl_setup(&o->ssl, &ssl_context->conf);
|
||||
#if !MICROPY_MBEDTLS_CONFIG_BARE_METAL
|
||||
if (ret != 0) {
|
||||
if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
|
||||
// If mbedTLS relies on platform libc heap for buffers (i.e. esp32
|
||||
// port), then run a GC pass and then try again. This is useful because
|
||||
// it may free a Python object (like an old SSL socket) whose finaliser
|
||||
@@ -669,20 +635,6 @@ static mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
||||
mbedtls_ssl_set_timer_cb(&o->ssl, o, _mbedtls_timing_set_delay, _mbedtls_timing_get_delay);
|
||||
#endif
|
||||
|
||||
#ifdef MBEDTLS_SSL_DTLS_HELLO_VERIFY
|
||||
if (ssl_context->is_dtls_server) {
|
||||
// require the client_id parameter for DTLS (as per mbedTLS requirement)
|
||||
ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
|
||||
mp_buffer_info_t buf;
|
||||
if (mp_get_buffer(client_id, &buf, MP_BUFFER_READ)) {
|
||||
ret = mbedtls_ssl_set_client_transport_id(&o->ssl, buf.buf, buf.len);
|
||||
}
|
||||
if (ret != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
|
||||
|
||||
if (do_handshake_on_connect) {
|
||||
|
||||
@@ -89,7 +89,7 @@ typedef struct _mp_obj_uctypes_struct_t {
|
||||
uint32_t flags;
|
||||
} mp_obj_uctypes_struct_t;
|
||||
|
||||
static MP_NORETURN void syntax_error(void) {
|
||||
static NORETURN void syntax_error(void) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor"));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,6 @@
|
||||
#ifndef MICROPY_INCLUDED_EXTMOD_MPBTHCI_H
|
||||
#define MICROPY_INCLUDED_EXTMOD_MPBTHCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define MICROPY_PY_BLUETOOTH_HCI_READ_MODE_BYTE (0)
|
||||
#define MICROPY_PY_BLUETOOTH_HCI_READ_MODE_PACKET (1)
|
||||
|
||||
|
||||
@@ -143,9 +143,6 @@ static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) {
|
||||
return mp_obj_new_bool(if_active[self->itf]);
|
||||
} else {
|
||||
bool value = mp_obj_is_true(args[1]);
|
||||
if (!value && self->itf == CYW43_ITF_STA) {
|
||||
cyw43_wifi_leave(self->cyw, self->itf);
|
||||
}
|
||||
cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code());
|
||||
if_active[self->itf] = value;
|
||||
return mp_const_none;
|
||||
|
||||
@@ -48,8 +48,6 @@
|
||||
#include "esp_hosted_wifi.h"
|
||||
#include "esp_hosted_hal.h"
|
||||
|
||||
extern const mp_obj_type_t mod_network_esp_hosted_type;
|
||||
|
||||
typedef struct _esp_hosted_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t itf;
|
||||
|
||||
@@ -52,19 +52,6 @@ int mp_mod_network_prefer_dns_use_ip_version = 4;
|
||||
|
||||
// Implementations of network methods that can be used by any interface.
|
||||
|
||||
// This follows sys_untimeout but removes all timeouts with the given argument.
|
||||
void sys_untimeout_all_with_arg(void *arg) {
|
||||
for (struct sys_timeo **t = sys_timeouts_get_next_timeout(); *t != NULL;) {
|
||||
if ((*t)->arg == arg) {
|
||||
struct sys_timeo *next = (*t)->next;
|
||||
memp_free(MEMP_SYS_TIMEOUT, *t);
|
||||
*t = next;
|
||||
} else {
|
||||
t = &(*t)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function provides the implementation of nic.ifconfig, is deprecated and will be removed.
|
||||
// Use network.ipconfig and nic.ipconfig instead.
|
||||
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) {
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// This file is intended to closely match ports/esp32/network_ppp.c. Changes can
|
||||
// and should probably be applied to both files. Compare them directly by using:
|
||||
// git diff --no-index extmod/network_ppp_lwip.c ports/esp32/network_ppp.c
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/stream.h"
|
||||
@@ -84,6 +80,7 @@ static void network_ppp_status_cb(ppp_pcb *pcb, int err_code, void *ctx) {
|
||||
break;
|
||||
case PPPERR_USER:
|
||||
if (self->state >= STATE_ERROR) {
|
||||
network_ppp_stream_uart_irq_disable(self);
|
||||
// Indicate that we are no longer connected and thus
|
||||
// only need to free the PPP PCB, not close it.
|
||||
self->state = STATE_ACTIVE;
|
||||
@@ -124,7 +121,6 @@ static mp_obj_t network_ppp___del__(mp_obj_t self_in) {
|
||||
self->state = STATE_INACTIVE;
|
||||
ppp_close(self->pcb, 1);
|
||||
}
|
||||
network_ppp_stream_uart_irq_disable(self);
|
||||
// Free PPP PCB and reset state.
|
||||
self->state = STATE_INACTIVE;
|
||||
ppp_free(self->pcb);
|
||||
@@ -299,8 +295,7 @@ static mp_obj_t network_ppp_connect(size_t n_args, const mp_obj_t *args, mp_map_
|
||||
ppp_set_auth(self->pcb, parsed_args[ARG_security].u_int, user_str, key_str);
|
||||
}
|
||||
|
||||
ppp_set_default(self->pcb);
|
||||
|
||||
netif_set_default(self->pcb->netif);
|
||||
ppp_set_usepeerdns(self->pcb, true);
|
||||
|
||||
if (ppp_connect(self->pcb, 0) != ERR_OK) {
|
||||
|
||||
@@ -78,8 +78,6 @@
|
||||
|
||||
#endif
|
||||
|
||||
extern const mp_obj_type_t mod_network_nic_type_wiznet5k;
|
||||
|
||||
#ifndef printf
|
||||
#define printf(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
static uint8_t nimble_address_mode = BLE_OWN_ADDR_RANDOM;
|
||||
|
||||
#define NIMBLE_STARTUP_TIMEOUT 2000
|
||||
#define NIMBLE_SHUTDOWN_TIMEOUT 500
|
||||
|
||||
// Any BLE_HS_xxx code not in this table will default to MP_EIO.
|
||||
static int8_t ble_hs_err_to_errno_table[] = {
|
||||
@@ -555,7 +554,7 @@ static void ble_hs_shutdown_stop_cb(int status, void *arg) {
|
||||
|
||||
static struct ble_hs_stop_listener ble_hs_shutdown_stop_listener;
|
||||
|
||||
int mp_bluetooth_nimble_port_shutdown(void) {
|
||||
void mp_bluetooth_nimble_port_shutdown(void) {
|
||||
DEBUG_printf("mp_bluetooth_nimble_port_shutdown (nimble default)\n");
|
||||
// By default, just call ble_hs_stop directly and wait for the stack to stop.
|
||||
|
||||
@@ -563,17 +562,9 @@ int mp_bluetooth_nimble_port_shutdown(void) {
|
||||
|
||||
ble_hs_stop(&ble_hs_shutdown_stop_listener, ble_hs_shutdown_stop_cb, NULL);
|
||||
|
||||
mp_uint_t timeout_start_ticks_ms = mp_hal_ticks_ms();
|
||||
while (mp_bluetooth_nimble_ble_state != MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
|
||||
mp_uint_t elapsed = mp_hal_ticks_ms() - timeout_start_ticks_ms;
|
||||
if (elapsed > NIMBLE_SHUTDOWN_TIMEOUT) {
|
||||
// Stack had not responded (via ble_hs_shutdown_stop_cb)
|
||||
return MP_ETIMEDOUT;
|
||||
}
|
||||
|
||||
mp_event_wait_ms(NIMBLE_SHUTDOWN_TIMEOUT - elapsed);
|
||||
mp_event_wait_indefinite();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // !MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY
|
||||
@@ -668,11 +659,10 @@ int mp_bluetooth_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mp_bluetooth_deinit(void) {
|
||||
void mp_bluetooth_deinit(void) {
|
||||
DEBUG_printf("mp_bluetooth_deinit %d\n", mp_bluetooth_nimble_ble_state);
|
||||
int ret = 0;
|
||||
if (mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Must call ble_hs_stop() in a port-specific way to stop the background
|
||||
@@ -685,7 +675,7 @@ int mp_bluetooth_deinit(void) {
|
||||
|
||||
DEBUG_printf("mp_bluetooth_deinit: starting port shutdown\n");
|
||||
|
||||
ret = mp_bluetooth_nimble_port_shutdown();
|
||||
mp_bluetooth_nimble_port_shutdown();
|
||||
assert(mp_bluetooth_nimble_ble_state == MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF);
|
||||
} else {
|
||||
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF;
|
||||
@@ -702,7 +692,6 @@ int mp_bluetooth_deinit(void) {
|
||||
#endif
|
||||
|
||||
DEBUG_printf("mp_bluetooth_deinit: shut down\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mp_bluetooth_is_active(void) {
|
||||
|
||||
@@ -84,7 +84,7 @@ void mp_bluetooth_nimble_port_hci_deinit(void);
|
||||
void mp_bluetooth_nimble_port_start(void);
|
||||
|
||||
// Tell the port to stop its background task.
|
||||
int mp_bluetooth_nimble_port_shutdown(void);
|
||||
void mp_bluetooth_nimble_port_shutdown(void);
|
||||
|
||||
// --- Called by the HCI UART layer to let us know when packets have been sent.
|
||||
void mp_bluetooth_nimble_sent_hci_packet(void);
|
||||
|
||||
@@ -326,7 +326,7 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
} else {
|
||||
mode |= MP_S_IFREG;
|
||||
}
|
||||
mp_timestamp_t seconds = timeutils_seconds_since_epoch(
|
||||
mp_int_t seconds = timeutils_seconds_since_epoch(
|
||||
1980 + ((fno.fdate >> 9) & 0x7f),
|
||||
(fno.fdate >> 5) & 0x0f,
|
||||
fno.fdate & 0x1f,
|
||||
@@ -341,9 +341,9 @@ static mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) {
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = mp_obj_new_int_from_uint(fno.fsize); // st_size
|
||||
t->items[7] = timeutils_obj_from_timestamp(seconds); // st_atime
|
||||
t->items[8] = timeutils_obj_from_timestamp(seconds); // st_mtime
|
||||
t->items[9] = timeutils_obj_from_timestamp(seconds); // st_ctime
|
||||
t->items[7] = mp_obj_new_int_from_uint(seconds); // st_atime
|
||||
t->items[8] = mp_obj_new_int_from_uint(seconds); // st_mtime
|
||||
t->items[9] = mp_obj_new_int_from_uint(seconds); // st_ctime
|
||||
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
|
||||
@@ -104,12 +104,6 @@ static void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx * self, mp_obj_t bdev, size
|
||||
config->read_buffer = m_new(uint8_t, config->cache_size);
|
||||
config->prog_buffer = m_new(uint8_t, config->cache_size);
|
||||
config->lookahead_buffer = m_new(uint8_t, config->lookahead_size);
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
// This can be set to override the on-disk lfs version.
|
||||
// eg. for compat with lfs2 < v2.6 add the following to make:
|
||||
// CFLAGS += '-DLFS2_MULTIVERSION=0x00020000'
|
||||
config->disk_version = LFS2_MULTIVERSION;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -306,7 +300,7 @@ static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
struct LFSx_API (info) info;
|
||||
int ret = LFSx_API(stat)(&self->lfs, path, &info);
|
||||
if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
mp_raise_OSError(-MP_ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +378,7 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
mp_raise_OSError(-ret);
|
||||
}
|
||||
|
||||
mp_timestamp_t mtime = 0;
|
||||
mp_uint_t mtime = 0;
|
||||
#if LFS_BUILD_VERSION == 2
|
||||
uint8_t mtime_buf[8];
|
||||
lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
|
||||
@@ -406,9 +400,9 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
|
||||
t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
|
||||
t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
|
||||
t->items[7] = timeutils_obj_from_timestamp(mtime); // st_atime
|
||||
t->items[8] = timeutils_obj_from_timestamp(mtime); // st_mtime
|
||||
t->items[9] = timeutils_obj_from_timestamp(mtime); // st_ctime
|
||||
t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
|
||||
t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
|
||||
t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
|
||||
|
||||
return MP_OBJ_FROM_PTR(t);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ static mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||
vstr_add_char(&vfs->root, '/');
|
||||
}
|
||||
vfs->root_len = vfs->root.len;
|
||||
vfs->readonly = !MICROPY_VFS_POSIX_WRITABLE;
|
||||
vfs->readonly = false;
|
||||
|
||||
return MP_OBJ_FROM_PTR(vfs);
|
||||
}
|
||||
@@ -160,21 +160,10 @@ static mp_obj_t vfs_posix_umount(mp_obj_t self_in) {
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount);
|
||||
|
||||
static inline bool vfs_posix_is_readonly(mp_obj_vfs_posix_t *self) {
|
||||
return !MICROPY_VFS_POSIX_WRITABLE || self->readonly;
|
||||
}
|
||||
|
||||
static void vfs_posix_require_writable(mp_obj_t self_in) {
|
||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (vfs_posix_is_readonly(self)) {
|
||||
mp_raise_OSError(MP_EROFS);
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
|
||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
const char *mode = mp_obj_str_get_str(mode_in);
|
||||
if (vfs_posix_is_readonly(self)
|
||||
if (self->readonly
|
||||
&& (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) {
|
||||
mp_raise_OSError(MP_EROFS);
|
||||
}
|
||||
@@ -314,7 +303,6 @@ typedef struct _mp_obj_listdir_t {
|
||||
} mp_obj_listdir_t;
|
||||
|
||||
static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
vfs_posix_require_writable(self_in);
|
||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
const char *path = vfs_posix_get_path_str(self, path_in);
|
||||
MP_THREAD_GIL_EXIT();
|
||||
@@ -332,13 +320,11 @@ static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir);
|
||||
|
||||
static mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
vfs_posix_require_writable(self_in);
|
||||
return vfs_posix_fun1_helper(self_in, path_in, unlink);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove);
|
||||
|
||||
static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
|
||||
vfs_posix_require_writable(self_in);
|
||||
mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
const char *old_path = vfs_posix_get_path_str(self, old_path_in);
|
||||
const char *new_path = vfs_posix_get_path_str(self, new_path_in);
|
||||
@@ -353,7 +339,6 @@ static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_
|
||||
static MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);
|
||||
|
||||
static mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) {
|
||||
vfs_posix_require_writable(self_in);
|
||||
return vfs_posix_fun1_helper(self_in, path_in, rmdir);
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);
|
||||
|
||||
Submodule lib/berkeley-db-1.xx updated: 0f3bb6947c...85373b548f
Submodule lib/libhydrogen updated: bbca575b62...5c5d513093
@@ -2,7 +2,7 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 || FLT_EVAL_METHOD==16
|
||||
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
|
||||
#define EPS DBL_EPSILON
|
||||
#elif FLT_EVAL_METHOD==2
|
||||
#define EPS LDBL_EPSILON
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ extern "C"
|
||||
// Software library version
|
||||
// Major (top-nibble), incremented on backwards incompatible changes
|
||||
// Minor (bottom-nibble), incremented on feature additions
|
||||
#define LFS2_VERSION 0x0002000b
|
||||
#define LFS2_VERSION 0x00020008
|
||||
#define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16))
|
||||
#define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0))
|
||||
|
||||
@@ -52,15 +52,16 @@ typedef uint32_t lfs2_block_t;
|
||||
#endif
|
||||
|
||||
// Maximum size of a file in bytes, may be redefined to limit to support other
|
||||
// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be
|
||||
// respected by other littlefs drivers.
|
||||
// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the
|
||||
// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return
|
||||
// incorrect values due to using signed integers. Stored in superblock and
|
||||
// must be respected by other littlefs drivers.
|
||||
#ifndef LFS2_FILE_MAX
|
||||
#define LFS2_FILE_MAX 2147483647
|
||||
#endif
|
||||
|
||||
// Maximum size of custom attributes in bytes, may be redefined, but there is
|
||||
// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. Stored
|
||||
// in superblock and must be respected by other littlefs drivers.
|
||||
// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022.
|
||||
#ifndef LFS2_ATTR_MAX
|
||||
#define LFS2_ATTR_MAX 1022
|
||||
#endif
|
||||
@@ -204,8 +205,7 @@ struct lfs2_config {
|
||||
// program sizes.
|
||||
lfs2_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device. Defaults to block_count stored
|
||||
// on disk when zero.
|
||||
// Number of erasable blocks on the device.
|
||||
lfs2_size_t block_count;
|
||||
|
||||
// Number of erase cycles before littlefs evicts metadata logs and moves
|
||||
@@ -226,20 +226,9 @@ struct lfs2_config {
|
||||
// Size of the lookahead buffer in bytes. A larger lookahead buffer
|
||||
// increases the number of blocks found during an allocation pass. The
|
||||
// lookahead buffer is stored as a compact bitmap, so each byte of RAM
|
||||
// can track 8 blocks.
|
||||
// can track 8 blocks. Must be a multiple of 8.
|
||||
lfs2_size_t lookahead_size;
|
||||
|
||||
// Threshold for metadata compaction during lfs2_fs_gc in bytes. Metadata
|
||||
// pairs that exceed this threshold will be compacted during lfs2_fs_gc.
|
||||
// Defaults to ~88% block_size when zero, though the default may change
|
||||
// in the future.
|
||||
//
|
||||
// Note this only affects lfs2_fs_gc. Normal compactions still only occur
|
||||
// when full.
|
||||
//
|
||||
// Set to -1 to disable metadata compaction during lfs2_fs_gc.
|
||||
lfs2_size_t compact_thresh;
|
||||
|
||||
// Optional statically allocated read buffer. Must be cache_size.
|
||||
// By default lfs2_malloc is used to allocate this buffer.
|
||||
void *read_buffer;
|
||||
@@ -248,24 +237,25 @@ struct lfs2_config {
|
||||
// By default lfs2_malloc is used to allocate this buffer.
|
||||
void *prog_buffer;
|
||||
|
||||
// Optional statically allocated lookahead buffer. Must be lookahead_size.
|
||||
// By default lfs2_malloc is used to allocate this buffer.
|
||||
// Optional statically allocated lookahead buffer. Must be lookahead_size
|
||||
// and aligned to a 32-bit boundary. By default lfs2_malloc is used to
|
||||
// allocate this buffer.
|
||||
void *lookahead_buffer;
|
||||
|
||||
// Optional upper limit on length of file names in bytes. No downside for
|
||||
// larger names except the size of the info struct which is controlled by
|
||||
// the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX or name_max stored on
|
||||
// disk when zero.
|
||||
// the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in
|
||||
// superblock and must be respected by other littlefs drivers.
|
||||
lfs2_size_t name_max;
|
||||
|
||||
// Optional upper limit on files in bytes. No downside for larger files
|
||||
// but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX or file_max stored
|
||||
// on disk when zero.
|
||||
// but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored
|
||||
// in superblock and must be respected by other littlefs drivers.
|
||||
lfs2_size_t file_max;
|
||||
|
||||
// Optional upper limit on custom attributes in bytes. No downside for
|
||||
// larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to
|
||||
// LFS2_ATTR_MAX or attr_max stored on disk when zero.
|
||||
// LFS2_ATTR_MAX when zero.
|
||||
lfs2_size_t attr_max;
|
||||
|
||||
// Optional upper limit on total space given to metadata pairs in bytes. On
|
||||
@@ -274,15 +264,6 @@ struct lfs2_config {
|
||||
// Defaults to block_size when zero.
|
||||
lfs2_size_t metadata_max;
|
||||
|
||||
// Optional upper limit on inlined files in bytes. Inlined files live in
|
||||
// metadata and decrease storage requirements, but may be limited to
|
||||
// improve metadata-related performance. Must be <= cache_size, <=
|
||||
// attr_max, and <= block_size/8. Defaults to the largest possible
|
||||
// inline_max when zero.
|
||||
//
|
||||
// Set to -1 to disable inlined files.
|
||||
lfs2_size_t inline_max;
|
||||
|
||||
#ifdef LFS2_MULTIVERSION
|
||||
// On-disk version to use when writing in the form of 16-bit major version
|
||||
// + 16-bit minor version. This limiting metadata to what is supported by
|
||||
@@ -449,20 +430,19 @@ typedef struct lfs2 {
|
||||
lfs2_gstate_t gdisk;
|
||||
lfs2_gstate_t gdelta;
|
||||
|
||||
struct lfs2_lookahead {
|
||||
lfs2_block_t start;
|
||||
struct lfs2_free {
|
||||
lfs2_block_t off;
|
||||
lfs2_block_t size;
|
||||
lfs2_block_t next;
|
||||
lfs2_block_t ckpoint;
|
||||
uint8_t *buffer;
|
||||
} lookahead;
|
||||
lfs2_block_t i;
|
||||
lfs2_block_t ack;
|
||||
uint32_t *buffer;
|
||||
} free;
|
||||
|
||||
const struct lfs2_config *cfg;
|
||||
lfs2_size_t block_count;
|
||||
lfs2_size_t name_max;
|
||||
lfs2_size_t file_max;
|
||||
lfs2_size_t attr_max;
|
||||
lfs2_size_t inline_max;
|
||||
|
||||
#ifdef LFS2_MIGRATE
|
||||
struct lfs21 *lfs21;
|
||||
@@ -732,6 +712,18 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2);
|
||||
// Returns a negative error code on failure.
|
||||
int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
|
||||
|
||||
// Attempt to proactively find free blocks
|
||||
//
|
||||
// Calling this function is not required, but may allowing the offloading of
|
||||
// the expensive block allocation scan to a less time-critical code path.
|
||||
//
|
||||
// Note: littlefs currently does not persist any found free blocks to disk.
|
||||
// This may change in the future.
|
||||
//
|
||||
// Returns a negative error code on failure. Finding no free blocks is
|
||||
// not an error.
|
||||
int lfs2_fs_gc(lfs2_t *lfs2);
|
||||
|
||||
#ifndef LFS2_READONLY
|
||||
// Attempt to make the filesystem consistent and ready for writing
|
||||
//
|
||||
@@ -744,33 +736,11 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data);
|
||||
int lfs2_fs_mkconsistent(lfs2_t *lfs2);
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_READONLY
|
||||
// Attempt any janitorial work
|
||||
//
|
||||
// This currently:
|
||||
// 1. Calls mkconsistent if not already consistent
|
||||
// 2. Compacts metadata > compact_thresh
|
||||
// 3. Populates the block allocator
|
||||
//
|
||||
// Though additional janitorial work may be added in the future.
|
||||
//
|
||||
// Calling this function is not required, but may allow the offloading of
|
||||
// expensive janitorial work to a less time-critical code path.
|
||||
//
|
||||
// Returns a negative error code on failure. Accomplishing nothing is not
|
||||
// an error.
|
||||
int lfs2_fs_gc(lfs2_t *lfs2);
|
||||
#endif
|
||||
|
||||
#ifndef LFS2_READONLY
|
||||
// Grows the filesystem to a new size, updating the superblock with the new
|
||||
// block count.
|
||||
//
|
||||
// If LFS2_SHRINKNONRELOCATING is defined, this function will also accept
|
||||
// block_counts smaller than the current configuration, after checking
|
||||
// that none of the blocks that are being removed are in use.
|
||||
// Note that littlefs's pseudorandom block allocation means that
|
||||
// this is very unlikely to work in the general case.
|
||||
// Note: This is irreversible.
|
||||
//
|
||||
// Returns a negative error code on failure.
|
||||
int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count);
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#ifndef LFS2_CONFIG
|
||||
|
||||
|
||||
// If user provides their own CRC impl we don't need this
|
||||
#ifndef LFS2_CRC
|
||||
// Software CRC implementation with small lookup table
|
||||
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
|
||||
static const uint32_t rtable[16] = {
|
||||
@@ -31,7 +29,6 @@ uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
|
||||
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
#ifndef LFS2_UTIL_H
|
||||
#define LFS2_UTIL_H
|
||||
|
||||
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
|
||||
#define LFS2_STRINGIZE2(x) #x
|
||||
|
||||
// Users can override lfs2_util.h with their own configuration by defining
|
||||
// LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h).
|
||||
//
|
||||
@@ -18,26 +15,11 @@
|
||||
// provided by the config file. To start, I would suggest copying lfs2_util.h
|
||||
// and modifying as needed.
|
||||
#ifdef LFS2_CONFIG
|
||||
#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x)
|
||||
#define LFS2_STRINGIZE2(x) #x
|
||||
#include LFS2_STRINGIZE(LFS2_CONFIG)
|
||||
#else
|
||||
|
||||
// Alternatively, users can provide a header file which defines
|
||||
// macros and other things consumed by littlefs.
|
||||
//
|
||||
// For example, provide my_defines.h, which contains
|
||||
// something like:
|
||||
//
|
||||
// #include <stddef.h>
|
||||
// extern void *my_malloc(size_t sz);
|
||||
// #define LFS2_MALLOC(sz) my_malloc(sz)
|
||||
//
|
||||
// And build littlefs with the header by defining LFS2_DEFINES.
|
||||
// (-DLFS2_DEFINES=my_defines.h)
|
||||
|
||||
#ifdef LFS2_DEFINES
|
||||
#include LFS2_STRINGIZE(LFS2_DEFINES)
|
||||
#endif
|
||||
|
||||
// System includes
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -195,10 +177,10 @@ static inline uint32_t lfs2_fromle32(uint32_t a) {
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
#else
|
||||
return ((uint32_t)((uint8_t*)&a)[0] << 0) |
|
||||
((uint32_t)((uint8_t*)&a)[1] << 8) |
|
||||
((uint32_t)((uint8_t*)&a)[2] << 16) |
|
||||
((uint32_t)((uint8_t*)&a)[3] << 24);
|
||||
return (((uint8_t*)&a)[0] << 0) |
|
||||
(((uint8_t*)&a)[1] << 8) |
|
||||
(((uint8_t*)&a)[2] << 16) |
|
||||
(((uint8_t*)&a)[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -218,10 +200,10 @@ static inline uint32_t lfs2_frombe32(uint32_t a) {
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
return a;
|
||||
#else
|
||||
return ((uint32_t)((uint8_t*)&a)[0] << 24) |
|
||||
((uint32_t)((uint8_t*)&a)[1] << 16) |
|
||||
((uint32_t)((uint8_t*)&a)[2] << 8) |
|
||||
((uint32_t)((uint8_t*)&a)[3] << 0);
|
||||
return (((uint8_t*)&a)[0] << 24) |
|
||||
(((uint8_t*)&a)[1] << 16) |
|
||||
(((uint8_t*)&a)[2] << 8) |
|
||||
(((uint8_t*)&a)[3] << 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -230,22 +212,12 @@ static inline uint32_t lfs2_tobe32(uint32_t a) {
|
||||
}
|
||||
|
||||
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
#ifdef LFS2_CRC
|
||||
static inline uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) {
|
||||
return LFS2_CRC(crc, buffer, size);
|
||||
}
|
||||
#else
|
||||
uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size);
|
||||
#endif
|
||||
|
||||
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
//
|
||||
// littlefs current has no alignment requirements, as it only allocates
|
||||
// byte-level buffers.
|
||||
// Note, memory must be 64-bit aligned
|
||||
static inline void *lfs2_malloc(size_t size) {
|
||||
#if defined(LFS2_MALLOC)
|
||||
return LFS2_MALLOC(size);
|
||||
#elif !defined(LFS2_NO_MALLOC)
|
||||
#ifndef LFS2_NO_MALLOC
|
||||
return malloc(size);
|
||||
#else
|
||||
(void)size;
|
||||
@@ -255,9 +227,7 @@ static inline void *lfs2_malloc(size_t size) {
|
||||
|
||||
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void lfs2_free(void *p) {
|
||||
#if defined(LFS2_FREE)
|
||||
LFS2_FREE(p);
|
||||
#elif !defined(LFS2_NO_MALLOC)
|
||||
#ifndef LFS2_NO_MALLOC
|
||||
free(p);
|
||||
#else
|
||||
(void)p;
|
||||
|
||||
2
lib/lwip
2
lib/lwip
Submodule lib/lwip updated: 77dcd25a72...0a0452b2c3
Submodule lib/micropython-lib updated: 34c4ee1647...5b496e944e
Submodule lib/stm32lib updated: 8b2bb4ef44...928df866e4
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user