kopia lustrzana https://github.com/micropython/micropython
Merge branch 'micropython:master' into object_dict_len_test_ecw
commit
0df3e4d265
|
@ -10,7 +10,7 @@ jobs:
|
||||||
code-formatting:
|
code-formatting:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_code_formatting_setup
|
run: source tools/ci.sh && ci_code_formatting_setup
|
||||||
|
@ -22,7 +22,7 @@ jobs:
|
||||||
code-spelling:
|
code-spelling:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_code_spell_setup
|
run: source tools/ci.sh && ci_code_spell_setup
|
||||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 100
|
fetch-depth: 100
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: '100'
|
fetch-depth: '100'
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
- name: Install Python packages
|
- name: Install Python packages
|
||||||
run: pip install Sphinx
|
run: pip install Sphinx
|
||||||
|
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
embedding:
|
embedding:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding
|
run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding
|
||||||
- name: Run
|
- name: Run
|
||||||
|
|
|
@ -11,7 +11,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
# Setting this to zero means fetch all history and tags,
|
# Setting this to zero means fetch all history and tags,
|
||||||
# which hatch-vcs can use to discover the version tag.
|
# which hatch-vcs can use to discover the version tag.
|
||||||
|
|
|
@ -17,7 +17,7 @@ jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-20.04 # use 20.04 to get python2
|
runs-on: ubuntu-20.04 # use 20.04 to get python2
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_mpy_format_setup
|
run: source tools/ci.sh && ci_mpy_format_setup
|
||||||
- name: Test mpy-tool.py
|
- name: Test mpy-tool.py
|
||||||
|
|
|
@ -17,6 +17,6 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build ports download metadata
|
- name: Build ports download metadata
|
||||||
run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards
|
run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_cc3200_setup
|
run: source tools/ci.sh && ci_cc3200_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build_idf50:
|
build_idf50:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_esp32_idf50_setup
|
run: source tools/ci.sh && ci_esp32_idf50_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH
|
run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_mimxrt_setup
|
run: source tools/ci.sh && ci_mimxrt_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_nrf_setup
|
run: source tools/ci.sh && ci_nrf_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_powerpc_setup
|
run: source tools/ci.sh && ci_powerpc_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
build_and_test:
|
build_and_test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_qemu_arm_setup
|
run: source tools/ci.sh && ci_qemu_arm_setup
|
||||||
- name: Build and run test suite
|
- name: Build and run test suite
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build_renesas_ra_board:
|
build_renesas_ra_board:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_renesas_ra_setup
|
run: source tools/ci.sh && ci_renesas_ra_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_rp2_setup
|
run: source tools/ci.sh && ci_rp2_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_samd_setup
|
run: source tools/ci.sh && ci_samd_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build_pyb:
|
build_pyb:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_stm32_setup
|
run: source tools/ci.sh && ci_stm32_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -30,7 +30,7 @@ jobs:
|
||||||
build_nucleo:
|
build_nucleo:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_stm32_setup
|
run: source tools/ci.sh && ci_stm32_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_teensy_setup
|
run: source tools/ci.sh && ci_teensy_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
minimal:
|
minimal:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_unix_minimal_build
|
run: source tools/ci.sh && ci_unix_minimal_build
|
||||||
- name: Run main test suite
|
- name: Run main test suite
|
||||||
|
@ -35,7 +35,7 @@ jobs:
|
||||||
reproducible:
|
reproducible:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build with reproducible date
|
- name: Build with reproducible date
|
||||||
run: source tools/ci.sh && ci_unix_minimal_build
|
run: source tools/ci.sh && ci_unix_minimal_build
|
||||||
env:
|
env:
|
||||||
|
@ -46,7 +46,7 @@ jobs:
|
||||||
standard:
|
standard:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_unix_standard_build
|
run: source tools/ci.sh && ci_unix_standard_build
|
||||||
- name: Run main test suite
|
- name: Run main test suite
|
||||||
|
@ -58,7 +58,7 @@ jobs:
|
||||||
coverage:
|
coverage:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_coverage_setup
|
run: source tools/ci.sh && ci_unix_coverage_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -87,7 +87,7 @@ jobs:
|
||||||
coverage_32bit:
|
coverage_32bit:
|
||||||
runs-on: ubuntu-20.04 # use 20.04 to get libffi-dev:i386
|
runs-on: ubuntu-20.04 # use 20.04 to get libffi-dev:i386
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_32bit_setup
|
run: source tools/ci.sh && ci_unix_32bit_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -105,7 +105,7 @@ jobs:
|
||||||
nanbox:
|
nanbox:
|
||||||
runs-on: ubuntu-20.04 # use 20.04 to get python2, and libffi-dev:i386
|
runs-on: ubuntu-20.04 # use 20.04 to get python2, and libffi-dev:i386
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_32bit_setup
|
run: source tools/ci.sh && ci_unix_32bit_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -119,7 +119,7 @@ jobs:
|
||||||
float:
|
float:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_unix_float_build
|
run: source tools/ci.sh && ci_unix_float_build
|
||||||
- name: Run main test suite
|
- name: Run main test suite
|
||||||
|
@ -131,7 +131,7 @@ jobs:
|
||||||
stackless_clang:
|
stackless_clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_clang_setup
|
run: source tools/ci.sh && ci_unix_clang_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -145,7 +145,7 @@ jobs:
|
||||||
float_clang:
|
float_clang:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_clang_setup
|
run: source tools/ci.sh && ci_unix_clang_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -159,7 +159,7 @@ jobs:
|
||||||
settrace:
|
settrace:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_unix_settrace_build
|
run: source tools/ci.sh && ci_unix_settrace_build
|
||||||
- name: Run main test suite
|
- name: Run main test suite
|
||||||
|
@ -171,7 +171,7 @@ jobs:
|
||||||
settrace_stackless:
|
settrace_stackless:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: source tools/ci.sh && ci_unix_settrace_stackless_build
|
run: source tools/ci.sh && ci_unix_settrace_stackless_build
|
||||||
- name: Run main test suite
|
- name: Run main test suite
|
||||||
|
@ -183,7 +183,7 @@ jobs:
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-11.0
|
runs-on: macos-11.0
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.8'
|
python-version: '3.8'
|
||||||
|
@ -198,7 +198,7 @@ jobs:
|
||||||
qemu_mips:
|
qemu_mips:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_qemu_mips_setup
|
run: source tools/ci.sh && ci_unix_qemu_mips_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
@ -212,7 +212,7 @@ jobs:
|
||||||
qemu_arm:
|
qemu_arm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_unix_qemu_arm_setup
|
run: source tools/ci.sh && ci_unix_qemu_arm_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_webassembly_setup
|
run: source tools/ci.sh && ci_webassembly_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_windows_setup
|
run: source tools/ci.sh && ci_windows_setup
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: source tools/ci.sh && ci_zephyr_setup
|
run: source tools/ci.sh && ci_zephyr_setup
|
||||||
- name: Install Zephyr
|
- name: Install Zephyr
|
||||||
|
|
|
@ -5,6 +5,6 @@ jobs:
|
||||||
ruff:
|
ruff:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: pip install --user ruff
|
- run: pip install --user ruff
|
||||||
- run: ruff --format=github .
|
- run: ruff --format=github .
|
||||||
|
|
|
@ -100,7 +100,7 @@ For the stm32 port, the ARM cross-compiler is required:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ sudo apt-get install arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib
|
$ sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi
|
||||||
|
|
||||||
See the `ARM GCC
|
See the `ARM GCC
|
||||||
toolchain <https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads>`_
|
toolchain <https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads>`_
|
||||||
|
@ -228,7 +228,7 @@ You can also specify which board to use:
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ cd ports/stm32
|
$ cd ports/stm32
|
||||||
$ make submodules
|
$ make BOARD=<board> submodules
|
||||||
$ make BOARD=<board>
|
$ make BOARD=<board>
|
||||||
|
|
||||||
See `ports/stm32/boards <https://github.com/micropython/micropython/tree/master/ports/stm32/boards>`_
|
See `ports/stm32/boards <https://github.com/micropython/micropython/tree/master/ports/stm32/boards>`_
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 200 KiB |
|
@ -42,3 +42,83 @@ for this:
|
||||||
|
|
||||||
The MCPWM0 peripheral is in bit position 17 of the above two registers, hence
|
The MCPWM0 peripheral is in bit position 17 of the above two registers, hence
|
||||||
the value of ``DPORT_PWM0_CLK_EN``.
|
the value of ``DPORT_PWM0_CLK_EN``.
|
||||||
|
|
||||||
|
Synchronous access to pins directly via registers
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
The following code shows how to access pins directly via registers. It has been
|
||||||
|
tested on a generic ESP32 board. It configures pins 16, 17, 32 and 33 in output
|
||||||
|
mode via registers, and switches pin output values via registers. Pins 16 and
|
||||||
|
17 are switched simultaneously.
|
||||||
|
|
||||||
|
.. code-block:: python3
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
from machine import mem32, Pin
|
||||||
|
|
||||||
|
GPIO_OUT_REG = const(0x3FF44004) # GPIO 0-31 output register
|
||||||
|
GPIO_OUT1_REG = const(0x3FF44010) # GPIO 32-39 output register
|
||||||
|
|
||||||
|
GPIO_ENABLE_REG = const(0x3FF44020) # GPIO 0-31 output enable register
|
||||||
|
GPIO_ENABLE1_REG = const(0x3FF4402C) # GPIO 32-39 output enable register
|
||||||
|
|
||||||
|
M16 = 1 << 16 # Pin(16) bit mask
|
||||||
|
M17 = 1 << 17 # Pin(17) bit mask
|
||||||
|
|
||||||
|
M32 = 1 << (32-32) # Pin(32) bit mask
|
||||||
|
M33 = 1 << (33-32) # Pin(33) bit mask
|
||||||
|
|
||||||
|
# Enable pin output mode like
|
||||||
|
# p16 = Pin(16, mode=Pin.OUT)
|
||||||
|
# p17 = Pin(17, mode=Pin.OUT)
|
||||||
|
# p32 = Pin(32, mode=Pin.OUT)
|
||||||
|
# p33 = Pin(33, mode=Pin.OUT)
|
||||||
|
mem32[GPIO_ENABLE_REG] = mem32[GPIO_ENABLE_REG] | M16 | M17
|
||||||
|
mem32[GPIO_ENABLE1_REG] = mem32[GPIO_ENABLE1_REG] | M32 | M33
|
||||||
|
|
||||||
|
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
|
||||||
|
|
||||||
|
# Set outputs to 1 like
|
||||||
|
# p16(1)
|
||||||
|
# p17(1)
|
||||||
|
# p32(1)
|
||||||
|
# p33(1)
|
||||||
|
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17
|
||||||
|
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33
|
||||||
|
|
||||||
|
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
|
||||||
|
|
||||||
|
# Set outputs to 0 like
|
||||||
|
# p16(0)
|
||||||
|
# p17(0)
|
||||||
|
# p32(0)
|
||||||
|
# p33(0)
|
||||||
|
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17)
|
||||||
|
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33)
|
||||||
|
|
||||||
|
print(hex(mem32[GPIO_OUT_REG]), hex(mem32[GPIO_OUT1_REG]))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# Set outputs to 1
|
||||||
|
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] | M16 | M17
|
||||||
|
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] | M32 | M33
|
||||||
|
|
||||||
|
# Set outputs to 0
|
||||||
|
mem32[GPIO_OUT_REG] = mem32[GPIO_OUT_REG] & ~(M16 | M17)
|
||||||
|
mem32[GPIO_OUT1_REG] = mem32[GPIO_OUT1_REG] & ~(M32 | M33)
|
||||||
|
|
||||||
|
|
||||||
|
Output is::
|
||||||
|
|
||||||
|
0x0 0x0
|
||||||
|
0x30000 0x3
|
||||||
|
0x0 0x0
|
||||||
|
|
||||||
|
Pins 16 and 17 are switched synchronously:
|
||||||
|
|
||||||
|
.. image:: img/mem32_gpio_output.jpg
|
||||||
|
|
||||||
|
Same image on pins 32 and 33.
|
||||||
|
|
||||||
|
Note that pins 34-36 and 39 are inputs only. Also pins 1 and 3 are Tx, Rx of the REPL UART,
|
||||||
|
pins 6-11 are connected to the built-in SPI flash.
|
||||||
|
|
|
@ -41,9 +41,15 @@ Classes
|
||||||
to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to
|
to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to
|
||||||
window sizes of 32 to 32k bytes).
|
window sizes of 32 to 32k bytes).
|
||||||
|
|
||||||
If *wbits* is set to ``0`` (the default), then a window size of 256 bytes
|
If *wbits* is set to ``0`` (the default), then for compression a window size
|
||||||
will be used (corresponding to *wbits* set to ``8``), except when
|
of 256 bytes will be used (as if *wbits* was set to 8). For decompression, it
|
||||||
:ref:`decompressing a zlib stream <deflate_wbits_zlib>`.
|
depends on the format:
|
||||||
|
|
||||||
|
* ``RAW`` will use 256 bytes (corresponding to *wbits* set to 8).
|
||||||
|
* ``ZLIB`` (or ``AUTO`` with zlib detected) will use the value from the zlib
|
||||||
|
header.
|
||||||
|
* ``GZIP`` (or ``AUTO`` with gzip detected) will use 32 kilobytes
|
||||||
|
(corresponding to *wbits* set to 15).
|
||||||
|
|
||||||
See the :ref:`window size <deflate_wbits>` notes below for more information
|
See the :ref:`window size <deflate_wbits>` notes below for more information
|
||||||
about the window size, zlib, and gzip streams.
|
about the window size, zlib, and gzip streams.
|
||||||
|
@ -134,44 +140,43 @@ Deflate window size
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
The window size limits how far back in the stream the (de)compressor can
|
The window size limits how far back in the stream the (de)compressor can
|
||||||
reference. Increasing the window size will improve compression, but will
|
reference. Increasing the window size will improve compression, but will require
|
||||||
require more memory.
|
more memory and make the compressor slower.
|
||||||
|
|
||||||
However, just because a given window size is used for compression, this does not
|
If an input stream was compressed a given window size, then `DeflateIO`
|
||||||
mean that the stream will require the same size window for decompression, as
|
using a smaller window size will fail mid-way during decompression with
|
||||||
the stream may not reference data as far back as the window allows (for example,
|
:exc:`OSError`, but only if a back-reference actually refers back further
|
||||||
if the length of the input is smaller than the window size).
|
than the decompressor's window size. This means it may be possible to decompress
|
||||||
|
with a smaller window size. For example, this would trivially be the case if the
|
||||||
|
original uncompressed data is shorter than the window size.
|
||||||
|
|
||||||
If the decompressor uses a smaller window size than necessary for the input data
|
Decompression
|
||||||
stream, it will fail mid-way through decompression with :exc:`OSError`.
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. _deflate_wbits_zlib:
|
The zlib format includes a header which specifies the window size that was used
|
||||||
|
to compress the data. This indicates the maximum window size required to
|
||||||
|
decompress this stream. If this header value is less than the specified *wbits*
|
||||||
|
value (or if *wbits* is unset), then the header value will be used.
|
||||||
|
|
||||||
The zlib format includes a header which specifies the window size used to
|
The gzip format does not include the window size in the header, and assumes that
|
||||||
compress the data (which due to the above, may be larger than the size required
|
all gzip compressors (e.g. the ``gzip`` utility, or CPython's implementation of
|
||||||
for the decompressor).
|
:class:`gzip.GzipFile`) use the maximum window size of 32kiB. For this reason,
|
||||||
|
if the *wbits* parameter is not set, the decompressor will use a 32 kiB window
|
||||||
|
size (corresponding to *wbits* set to 15). This means that to be able to
|
||||||
|
decompress an arbitrary gzip stream, you must have at least this much RAM
|
||||||
|
available. If you control the source data, consider instead using the zlib
|
||||||
|
format with a smaller window size.
|
||||||
|
|
||||||
If this header value is lower than the specified *wbits* value, then the header
|
The raw format has no header and therefore does not include any information
|
||||||
value will be used instead in order to reduce the memory allocation size. If
|
about the window size. If *wbits* is not set, then it will default to a window
|
||||||
the *wbits* parameter is zero (the default), then the header value will only be
|
size of 256 bytes, which may not be large enough for a given stream. Therefore
|
||||||
used if it is less than the maximum value of ``15`` (which is default value
|
it is recommended that you should always explicitly set *wbits* if using the raw
|
||||||
used by most compressors [#f1]_).
|
format.
|
||||||
|
|
||||||
In other words, if the source zlib stream has been compressed with a custom window
|
Compression
|
||||||
size (i.e. less than ``15``), then using the default *wbits* parameter of zero
|
~~~~~~~~~~~
|
||||||
will decompress any such stream.
|
|
||||||
|
|
||||||
The gzip file format does not include the window size in the header.
|
For compression, MicroPython will default to a window size of 256 bytes for all
|
||||||
Additionally, most compressor libraries (including CPython's implementation
|
formats. This provides a reasonable amount of compression with minimal memory
|
||||||
of :class:`gzip.GzipFile`) will default to the maximum possible window size.
|
usage and fast compression time, and will generate output that will work with
|
||||||
This makes it difficult to decompress most gzip streams on MicroPython unless
|
any decompressor.
|
||||||
your board has a lot of free RAM.
|
|
||||||
|
|
||||||
If you control the source of the compressed data, then prefer to use the zlib
|
|
||||||
format, with a window size that is suitable for your target device.
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
|
||||||
|
|
||||||
.. [#f1] The assumption here is that if the header value is the default used by
|
|
||||||
most compressors, then nothing is known about the likely required window
|
|
||||||
size and we should ignore it.
|
|
||||||
|
|
|
@ -51,13 +51,20 @@ Functions
|
||||||
buffers and other data. This data is useful to get a sense of how much memory
|
buffers and other data. This data is useful to get a sense of how much memory
|
||||||
is available to ESP-IDF and the networking stack in particular. It may shed
|
is available to ESP-IDF and the networking stack in particular. It may shed
|
||||||
some light on situations where ESP-IDF operations fail due to allocation failures.
|
some light on situations where ESP-IDF operations fail due to allocation failures.
|
||||||
The information returned is *not* useful to troubleshoot Python allocation failures,
|
|
||||||
use `micropython.mem_info()` instead.
|
|
||||||
|
|
||||||
The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the
|
The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the
|
||||||
two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and
|
two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and
|
||||||
`esp32.HEAP_EXEC` for executable regions as used by the native code emitter.
|
`esp32.HEAP_EXEC` for executable regions as used by the native code emitter.
|
||||||
|
|
||||||
|
Free IDF heap memory in the `esp32.HEAP_DATA` region is available to be
|
||||||
|
automatically added to the MicroPython heap to prevent a MicroPython
|
||||||
|
allocation from failing. However, the information returned here is otherwise
|
||||||
|
*not* useful to troubleshoot Python allocation failures, use
|
||||||
|
`micropython.mem_info()` instead. The "max new split" value in
|
||||||
|
`micropython.mem_info()` output corresponds to the largest free block of
|
||||||
|
ESP-IDF heap that could be automatically added on demand to the MicroPython
|
||||||
|
heap.
|
||||||
|
|
||||||
The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap
|
The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap
|
||||||
and contains: the total bytes, the free bytes, the largest free block, and
|
and contains: the total bytes, the free bytes, the largest free block, and
|
||||||
the minimum free seen over time.
|
the minimum free seen over time.
|
||||||
|
@ -107,6 +114,11 @@ methods to enable over-the-air (OTA) updates.
|
||||||
|
|
||||||
Sets the partition as the boot partition.
|
Sets the partition as the boot partition.
|
||||||
|
|
||||||
|
.. note:: Do not enter :func:`deepsleep<machine.deepsleep>` after changing
|
||||||
|
the OTA boot partition, without first performing a hard
|
||||||
|
:func:`reset<machine.reset>` or power cycle. This ensures the bootloader
|
||||||
|
will validate the new image before booting.
|
||||||
|
|
||||||
.. method:: Partition.get_next_update()
|
.. method:: Partition.get_next_update()
|
||||||
|
|
||||||
Gets the next update partition after this one, and returns a new Partition object.
|
Gets the next update partition after this one, and returns a new Partition object.
|
||||||
|
|
|
@ -71,6 +71,7 @@ library.
|
||||||
json.rst
|
json.rst
|
||||||
math.rst
|
math.rst
|
||||||
os.rst
|
os.rst
|
||||||
|
platform.rst
|
||||||
random.rst
|
random.rst
|
||||||
re.rst
|
re.rst
|
||||||
select.rst
|
select.rst
|
||||||
|
|
|
@ -9,9 +9,7 @@ This module provides a driver for WS2818 / NeoPixel LEDs.
|
||||||
.. note:: This module is only included by default on the ESP8266, ESP32 and RP2
|
.. note:: This module is only included by default on the ESP8266, ESP32 and RP2
|
||||||
ports. On STM32 / Pyboard and others, you can either install the
|
ports. On STM32 / Pyboard and others, you can either install the
|
||||||
``neopixel`` package using :term:`mip`, or you can download the module
|
``neopixel`` package using :term:`mip`, or you can download the module
|
||||||
directly from
|
directly from :term:`micropython-lib` and copy it to the filesystem.
|
||||||
<https://raw.githubusercontent.com/micropython/micropython-lib/master/micropython/drivers/led/neopixel/neopixel.py>`_
|
|
||||||
and copy it to the filesystem.
|
|
||||||
|
|
||||||
class NeoPixel
|
class NeoPixel
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -171,8 +171,8 @@ The following are functions available in the network module.
|
||||||
|
|
||||||
.. function:: hostname([name])
|
.. function:: hostname([name])
|
||||||
|
|
||||||
Get or set the hostname that will identify this device on the network. It is
|
Get or set the hostname that will identify this device on the network. It will
|
||||||
applied to all interfaces.
|
be used by all interfaces.
|
||||||
|
|
||||||
This hostname is used for:
|
This hostname is used for:
|
||||||
* Sending to the DHCP server in the client request. (If using DHCP)
|
* Sending to the DHCP server in the client request. (If using DHCP)
|
||||||
|
@ -182,6 +182,12 @@ The following are functions available in the network module.
|
||||||
If the function is called without parameters, it returns the current
|
If the function is called without parameters, it returns the current
|
||||||
hostname.
|
hostname.
|
||||||
|
|
||||||
|
A change in hostname is typically only applied during connection. For DHCP
|
||||||
|
this is because the hostname is part of the DHCP client request, and the
|
||||||
|
implementation of mDNS in most ports only initialises the hostname once
|
||||||
|
during connection. For this reason, you must set the hostname before
|
||||||
|
activating/connecting your network interfaces.
|
||||||
|
|
||||||
The default hostname is typically the name of the board.
|
The default hostname is typically the name of the board.
|
||||||
|
|
||||||
.. function:: phy_mode([mode])
|
.. function:: phy_mode([mode])
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
:mod:`platform` -- access to underlying platform’s identifying data
|
||||||
|
===================================================================
|
||||||
|
|
||||||
|
.. module:: platform
|
||||||
|
:synopsis: access to underlying platform’s identifying data
|
||||||
|
|
||||||
|
|see_cpython_module| :mod:`python:platform`.
|
||||||
|
|
||||||
|
This module tries to retrieve as much platform-identifying data as possible. It
|
||||||
|
makes this information available via function APIs.
|
||||||
|
|
||||||
|
Functions
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. function:: platform()
|
||||||
|
|
||||||
|
Returns a string identifying the underlying platform. This string is composed
|
||||||
|
of several substrings in the following order, delimited by dashes (``-``):
|
||||||
|
|
||||||
|
- the name of the platform system (e.g. Unix, Windows or MicroPython)
|
||||||
|
- the MicroPython version
|
||||||
|
- the architecture of the platform
|
||||||
|
- the version of the underlying platform
|
||||||
|
- the concatenation of the name of the libc that MicroPython is linked to
|
||||||
|
and its corresponding version.
|
||||||
|
|
||||||
|
For example, this could be
|
||||||
|
``"MicroPython-1.20.0-xtensa-IDFv4.2.4-with-newlib3.0.0"``.
|
||||||
|
|
||||||
|
.. function:: python_compiler()
|
||||||
|
|
||||||
|
Returns a string identifying the compiler used for compiling MicroPython.
|
||||||
|
|
||||||
|
.. function:: libc_ver()
|
||||||
|
|
||||||
|
Returns a tuple of strings *(lib, version)*, where *lib* is the name of the
|
||||||
|
libc that MicroPython is linked to, and *version* the corresponding version
|
||||||
|
of this libc.
|
|
@ -102,3 +102,39 @@ the second CPU, the RF core.
|
||||||
Execute a HCI command on the SYS channel. The execution is synchronous.
|
Execute a HCI command on the SYS channel. The execution is synchronous.
|
||||||
|
|
||||||
Returns a bytes object with the result of the SYS command.
|
Returns a bytes object with the result of the SYS command.
|
||||||
|
|
||||||
|
Functions specific to STM32WLxx MCUs
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
These functions are available on STM32WLxx microcontrollers, and interact with
|
||||||
|
the integrated "SUBGHZ" radio modem peripheral.
|
||||||
|
|
||||||
|
.. function:: subghz_cs(level)
|
||||||
|
|
||||||
|
Sets the internal SPI CS pin attached to the radio peripheral. The ``level``
|
||||||
|
argument is active-low: a truthy value means "CS pin high" and de-asserts the
|
||||||
|
signal, a falsey value means "CS pin low" and asserts the signal.
|
||||||
|
|
||||||
|
The internal-only SPI bus corresponding to this CS signal can be instantiated
|
||||||
|
using :ref:`machine.SPI()<machine.SPI>` ``id`` value ``"SUBGHZ"``.
|
||||||
|
|
||||||
|
.. function:: subghz_irq(handler)
|
||||||
|
|
||||||
|
Sets the internal SUBGHZ radio interrupt handler to the provided
|
||||||
|
function. The handler function is called as a "hard" interrupt in response to
|
||||||
|
radio peripheral interrupts. See :ref:`isr_rules` for more information about
|
||||||
|
interrupt handlers in MicroPython.
|
||||||
|
|
||||||
|
Calling this function with the handler argument set to None disables the IRQ.
|
||||||
|
|
||||||
|
Due to a hardware limitation, each time this IRQ fires MicroPython disables
|
||||||
|
it before calling the handler. In order to receive another interrupt, Python
|
||||||
|
code should call ``subghz_irq()`` to set the handler again. This has the side
|
||||||
|
effect of re-enabling the IRQ.
|
||||||
|
|
||||||
|
.. function:: subghz_is_busy()
|
||||||
|
|
||||||
|
Return a ``bool`` corresponding to the internal "RFBUSYS" signal from the
|
||||||
|
radio peripheral. Before sending a new command to the radio over SPI then
|
||||||
|
this function should be polled until it returns ``False``, to confirm the
|
||||||
|
busy signal is de-asserted.
|
||||||
|
|
|
@ -29,8 +29,6 @@
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "pin_static_af.h"
|
|
||||||
#include "uart.h"
|
|
||||||
#include "extmod/mpbthci.h"
|
#include "extmod/mpbthci.h"
|
||||||
|
|
||||||
#if MICROPY_PY_NETWORK_CYW43
|
#if MICROPY_PY_NETWORK_CYW43
|
||||||
|
@ -38,33 +36,41 @@
|
||||||
#include "lib/cyw43-driver/src/cyw43_config.h"
|
#include "lib/cyw43-driver/src/cyw43_config.h"
|
||||||
#include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h"
|
#include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h"
|
||||||
|
|
||||||
// Provided by the port.
|
|
||||||
extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
|
|
||||||
|
|
||||||
// Provided by the port, and also possibly shared with the stack.
|
// Provided by the port, and also possibly shared with the stack.
|
||||||
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
extern uint8_t mp_bluetooth_hci_cmd_buf[4 + 256];
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// CYW BT HCI low-level driver
|
// 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 pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
|
||||||
|
|
||||||
STATIC void cywbt_wait_cts_low(void) {
|
STATIC void cywbt_wait_cts_low(void) {
|
||||||
mp_hal_pin_config(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
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) {
|
for (int i = 0; i < 200; ++i) {
|
||||||
if (mp_hal_pin_read(pyb_pin_BT_CTS) == 0) {
|
if (mp_hal_pin_read(CYW43_PIN_BT_CTS) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mp_hal_delay_ms(1);
|
mp_hal_delay_ms(1);
|
||||||
}
|
}
|
||||||
mp_hal_pin_config_alt(pyb_pin_BT_CTS, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_UP, AF_FN_UART, mp_bluetooth_hci_uart_obj.uart_id);
|
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) {
|
STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||||
uart_tx_strn(&mp_bluetooth_hci_uart_obj, (void*)buf, len);
|
mp_bluetooth_hci_uart_write((void *)buf, len);
|
||||||
for (int i = 0; i < 6; ++i) {
|
for (int c, i = 0; i < 6; ++i) {
|
||||||
while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) {
|
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||||
MICROPY_EVENT_POLL_HOOK
|
MICROPY_EVENT_POLL_HOOK
|
||||||
}
|
}
|
||||||
buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj);
|
buf[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// expect a command complete event (event 0x0e)
|
// expect a command complete event (event 0x0e)
|
||||||
|
@ -80,11 +86,11 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int sz = buf[2] - 3;
|
int sz = buf[2] - 3;
|
||||||
for (int i = 0; i < sz; ++i) {
|
for (int c, i = 0; i < sz; ++i) {
|
||||||
while (!uart_rx_any(&mp_bluetooth_hci_uart_obj)) {
|
while ((c = mp_bluetooth_hci_uart_readchar()) == -1) {
|
||||||
MICROPY_EVENT_POLL_HOOK
|
MICROPY_EVENT_POLL_HOOK
|
||||||
}
|
}
|
||||||
buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj);
|
buf[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -150,12 +156,15 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) {
|
||||||
|
|
||||||
// RF switch must select high path during BT patch boot
|
// RF switch must select high path during BT patch boot
|
||||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
mp_hal_pin_config(CYW43_PIN_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_UP, 0);
|
||||||
#endif
|
#endif
|
||||||
mp_hal_delay_ms(10); // give some time for CTS to go high
|
mp_hal_delay_ms(10); // give some time for CTS to go high
|
||||||
|
#ifdef CYW43_PIN_BT_CTS
|
||||||
cywbt_wait_cts_low();
|
cywbt_wait_cts_low();
|
||||||
|
#endif
|
||||||
#if MICROPY_HW_ENABLE_RF_SWITCH
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_1, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_DOWN, 0); // Select chip antenna (could also select external)
|
// 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
|
#endif
|
||||||
|
|
||||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||||
|
@ -168,25 +177,33 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) {
|
||||||
int mp_bluetooth_hci_controller_init(void) {
|
int mp_bluetooth_hci_controller_init(void) {
|
||||||
// This is called immediately after the UART is initialised during stack initialisation.
|
// This is called immediately after the UART is initialised during stack initialisation.
|
||||||
|
|
||||||
mp_hal_pin_output(pyb_pin_BT_REG_ON);
|
mp_hal_pin_output(CYW43_PIN_BT_REG_ON);
|
||||||
mp_hal_pin_low(pyb_pin_BT_REG_ON);
|
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||||
mp_hal_pin_input(pyb_pin_BT_HOST_WAKE);
|
#ifdef CYW43_PIN_BT_HOST_WAKE
|
||||||
mp_hal_pin_output(pyb_pin_BT_DEV_WAKE);
|
mp_hal_pin_input(CYW43_PIN_BT_HOST_WAKE);
|
||||||
mp_hal_pin_low(pyb_pin_BT_DEV_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
|
#if MICROPY_HW_ENABLE_RF_SWITCH
|
||||||
// TODO don't select antenna if wifi is enabled
|
// TODO don't select antenna if wifi is enabled
|
||||||
mp_hal_pin_config(pyb_pin_WL_GPIO_4, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
|
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(pyb_pin_WL_GPIO_4); // Turn the RF-switch on
|
mp_hal_pin_high(CYW43_PIN_WL_GPIO_4); // Turn the RF-switch on
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t buf[256];
|
uint8_t buf[256];
|
||||||
|
|
||||||
mp_hal_pin_low(pyb_pin_BT_REG_ON);
|
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||||
mp_bluetooth_hci_uart_set_baudrate(115200);
|
mp_bluetooth_hci_uart_set_baudrate(115200);
|
||||||
mp_hal_delay_ms(100);
|
mp_hal_delay_ms(100);
|
||||||
mp_hal_pin_high(pyb_pin_BT_REG_ON);
|
mp_hal_pin_high(CYW43_PIN_BT_REG_ON);
|
||||||
|
#ifdef CYW43_PIN_BT_CTS
|
||||||
cywbt_wait_cts_low();
|
cywbt_wait_cts_low();
|
||||||
|
#else
|
||||||
|
mp_hal_delay_ms(100);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
||||||
|
@ -197,7 +214,7 @@ int mp_bluetooth_hci_controller_init(void) {
|
||||||
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
|
mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cywbt_download_firmware((const uint8_t*)&cyw43_btfw_4343A1[0]);
|
cywbt_download_firmware((const uint8_t *)&cyw43_btfw_4343A1[0]);
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
|
||||||
|
@ -219,31 +236,33 @@ int mp_bluetooth_hci_controller_init(void) {
|
||||||
// cywbt_hci_cmd(0x03, 0x0013, 248, buf);
|
// cywbt_hci_cmd(0x03, 0x0013, 248, buf);
|
||||||
|
|
||||||
// Configure sleep mode
|
// Configure sleep mode
|
||||||
cywbt_hci_cmd(0x3f, 0x27, 12, (const uint8_t*)"\x01\x02\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00");
|
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
|
// HCI_Write_LE_Host_Support
|
||||||
cywbt_hci_cmd(3, 109, 2, (const uint8_t*)"\x01\x00");
|
cywbt_hci_cmd(3, 109, 2, (const uint8_t *)"\x01\x00");
|
||||||
|
|
||||||
mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep
|
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||||
|
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mp_bluetooth_hci_controller_deinit(void) {
|
int mp_bluetooth_hci_controller_deinit(void) {
|
||||||
mp_hal_pin_low(pyb_pin_BT_REG_ON);
|
mp_hal_pin_low(CYW43_PIN_BT_REG_ON);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef pyb_pin_BT_DEV_WAKE
|
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||||
STATIC uint32_t bt_sleep_ticks;
|
STATIC uint32_t bt_sleep_ticks;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int mp_bluetooth_hci_controller_sleep_maybe(void) {
|
int mp_bluetooth_hci_controller_sleep_maybe(void) {
|
||||||
#ifdef pyb_pin_BT_DEV_WAKE
|
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||||
if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 0) {
|
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 0) {
|
||||||
if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) {
|
if (mp_hal_ticks_ms() - bt_sleep_ticks > 500) {
|
||||||
mp_hal_pin_high(pyb_pin_BT_DEV_WAKE); // let sleep
|
mp_hal_pin_high(CYW43_PIN_BT_DEV_WAKE); // let sleep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -251,8 +270,8 @@ int mp_bluetooth_hci_controller_sleep_maybe(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_bluetooth_hci_controller_woken(void) {
|
bool mp_bluetooth_hci_controller_woken(void) {
|
||||||
#ifdef pyb_pin_BT_HOST_WAKE
|
#ifdef CYW43_PIN_BT_HOST_WAKE
|
||||||
bool host_wake = mp_hal_pin_read(pyb_pin_BT_HOST_WAKE);
|
bool host_wake = mp_hal_pin_read(CYW43_PIN_BT_HOST_WAKE);
|
||||||
/*
|
/*
|
||||||
// this is just for info/tracing purposes
|
// this is just for info/tracing purposes
|
||||||
static bool last_host_wake = false;
|
static bool last_host_wake = false;
|
||||||
|
@ -268,11 +287,11 @@ bool mp_bluetooth_hci_controller_woken(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int mp_bluetooth_hci_controller_wakeup(void) {
|
int mp_bluetooth_hci_controller_wakeup(void) {
|
||||||
#ifdef pyb_pin_BT_DEV_WAKE
|
#ifdef CYW43_PIN_BT_DEV_WAKE
|
||||||
bt_sleep_ticks = mp_hal_ticks_ms();
|
bt_sleep_ticks = mp_hal_ticks_ms();
|
||||||
|
|
||||||
if (mp_hal_pin_read(pyb_pin_BT_DEV_WAKE) == 1) {
|
if (mp_hal_pin_read(CYW43_PIN_BT_DEV_WAKE) == 1) {
|
||||||
mp_hal_pin_low(pyb_pin_BT_DEV_WAKE); // wake up
|
mp_hal_pin_low(CYW43_PIN_BT_DEV_WAKE); // wake up
|
||||||
// Use delay_us rather than delay_ms to prevent running the scheduler (which
|
// Use delay_us rather than delay_ms to prevent running the scheduler (which
|
||||||
// might result in more BLE operations).
|
// might result in more BLE operations).
|
||||||
mp_hal_delay_us(5000); // can't go lower than this
|
mp_hal_delay_us(5000); // can't go lower than this
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# flash LED #1 using inline assembler
|
# flash LED #1 using inline assembler
|
||||||
# this version is overly verbose and uses word stores
|
# this version is overly verbose and uses word stores
|
||||||
|
#
|
||||||
|
# ruff: noqa: F821 - @asm_thumb decorator adds names to function scope
|
||||||
|
|
||||||
|
|
||||||
@micropython.asm_thumb
|
@micropython.asm_thumb
|
||||||
def flash_led(r0):
|
def flash_led(r0):
|
||||||
movw(r1, (stm.GPIOA + stm.GPIO_BSRRL) & 0xFFFF)
|
movw(r1, (stm.GPIOA + stm.GPIO_BSRRL) & 0xFFFF)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# ruff: noqa: F821 - @asm_thumb decorator adds names to function scope
|
||||||
|
|
||||||
|
|
||||||
@micropython.asm_thumb
|
@micropython.asm_thumb
|
||||||
def asm_sum_words(r0, r1):
|
def asm_sum_words(r0, r1):
|
||||||
# r0 = len
|
# r0 = len
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Helpers for generating BLE advertising payloads.
|
# Helpers for generating BLE advertising payloads.
|
||||||
|
|
||||||
|
# A more fully-featured (and easier to use) version of this is implemented in
|
||||||
|
# aioble. This code is provided just as a basic example. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
|
||||||
from micropython import const
|
from micropython import const
|
||||||
import struct
|
import struct
|
||||||
import bluetooth
|
import bluetooth
|
||||||
|
@ -19,6 +23,8 @@ _ADV_TYPE_UUID32_MORE = const(0x4)
|
||||||
_ADV_TYPE_UUID128_MORE = const(0x6)
|
_ADV_TYPE_UUID128_MORE = const(0x6)
|
||||||
_ADV_TYPE_APPEARANCE = const(0x19)
|
_ADV_TYPE_APPEARANCE = const(0x19)
|
||||||
|
|
||||||
|
_ADV_MAX_PAYLOAD = const(31)
|
||||||
|
|
||||||
|
|
||||||
# Generate a payload to be passed to gap_advertise(adv_data=...).
|
# Generate a payload to be passed to gap_advertise(adv_data=...).
|
||||||
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
|
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
|
||||||
|
@ -50,6 +56,9 @@ def advertising_payload(limited_disc=False, br_edr=False, name=None, services=No
|
||||||
if appearance:
|
if appearance:
|
||||||
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
|
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
|
||||||
|
|
||||||
|
if len(payload) > _ADV_MAX_PAYLOAD:
|
||||||
|
raise ValueError("advertising payload too large")
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
# any connected central every 10 seconds.
|
# any connected central every 10 seconds.
|
||||||
#
|
#
|
||||||
# Work-in-progress demo of implementing bonding and passkey auth.
|
# Work-in-progress demo of implementing bonding and passkey auth.
|
||||||
|
#
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library, which
|
||||||
|
# includes an implementation of the secret store. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
import random
|
import random
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
# This example finds and connects to a peripheral running the
|
# This example finds and connects to a peripheral running the
|
||||||
# UART service (e.g. ble_simple_peripheral.py).
|
# UART service (e.g. ble_simple_peripheral.py).
|
||||||
|
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library which takes
|
||||||
|
# care of all IRQ handling and connection management. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
import random
|
import random
|
||||||
import struct
|
import struct
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# This example demonstrates a UART periperhal.
|
# This example demonstrates a UART periperhal.
|
||||||
|
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library which takes
|
||||||
|
# care of all IRQ handling and connection management. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
import random
|
import random
|
||||||
import struct
|
import struct
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
# The sensor's local value updates every second, and it will notify
|
# The sensor's local value updates every second, and it will notify
|
||||||
# any connected central every 10 seconds.
|
# any connected central every 10 seconds.
|
||||||
|
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library which takes
|
||||||
|
# care of all IRQ handling and connection management. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
# and in particular the temp_sensor.py example included with aioble.
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
import random
|
import random
|
||||||
import struct
|
import struct
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
# This example finds and connects to a BLE temperature sensor (e.g. the one in ble_temperature.py).
|
# This example finds and connects to a BLE temperature sensor (e.g. the one in ble_temperature.py).
|
||||||
|
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library which takes
|
||||||
|
# care of all IRQ handling and connection management. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
# and in particular the temp_client.py example included with aioble.
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
import random
|
import random
|
||||||
import struct
|
import struct
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
# This example demonstrates a peripheral implementing the Nordic UART Service (NUS).
|
# This example demonstrates a peripheral implementing the Nordic UART Service (NUS).
|
||||||
|
|
||||||
|
# This example demonstrates the low-level bluetooth module. For most
|
||||||
|
# applications, we recommend using the higher-level aioble library which takes
|
||||||
|
# care of all IRQ handling and connection management. See
|
||||||
|
# https://github.com/micropython/micropython-lib/tree/master/micropython/bluetooth/aioble
|
||||||
|
|
||||||
import bluetooth
|
import bluetooth
|
||||||
from ble_advertising import advertising_payload
|
from ble_advertising import advertising_payload
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import bluetooth
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import micropython
|
import micropython
|
||||||
|
from micropython import const
|
||||||
import machine
|
import machine
|
||||||
|
|
||||||
from ble_uart_peripheral import BLEUART
|
from ble_uart_peripheral import BLEUART
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from machine import Signal
|
from machine import Pin, Signal
|
||||||
|
|
||||||
# 96Boards Carbon board
|
# 96Boards Carbon board
|
||||||
# USR1 - User controlled led, connected to PD2
|
# USR1 - User controlled led, connected to PD2
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Dynamic Native Modules
|
||||||
|
|
||||||
|
Dynamic Native Modules are .mpy files that contain native machine code from a
|
||||||
|
language other than Python. For more info see [the documentation]
|
||||||
|
(https://docs.micropython.org/en/latest/develop/natmod.html).
|
||||||
|
|
||||||
|
This should not be confused with [User C Modules]
|
||||||
|
(https://docs.micropython.org/en/latest/develop/cmodules.html) which are a
|
||||||
|
mechanism to add additional out-of-tree modules into the firmware build.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
This directory contains several examples of writing dynamic native modules, in
|
||||||
|
two main categories:
|
||||||
|
|
||||||
|
1. Feature examples.
|
||||||
|
|
||||||
|
* `features0` - A module containing a single "factorial" function which
|
||||||
|
demonstrates working with integers.
|
||||||
|
|
||||||
|
* `features1` - A module that demonstrates some common tasks:
|
||||||
|
- defining simple functions exposed to Python
|
||||||
|
- defining local, helper C functions
|
||||||
|
- defining constant integers and strings exposed to Python
|
||||||
|
- getting and creating integer objects
|
||||||
|
- creating Python lists
|
||||||
|
- raising exceptions
|
||||||
|
- allocating memory
|
||||||
|
- BSS and constant data (rodata)
|
||||||
|
- relocated pointers in rodata
|
||||||
|
|
||||||
|
* `features2` - This is a hybrid module containing both Python and C code,
|
||||||
|
and additionally the C code is spread over multiple files. It also
|
||||||
|
demonstrates using floating point (only when the target supports
|
||||||
|
hardware floating point).
|
||||||
|
|
||||||
|
* `features3` - A module that shows how to use types, constant objects,
|
||||||
|
and creating dictionary instances.
|
||||||
|
|
||||||
|
* `features4` - A module that demonstrates how to define a class.
|
||||||
|
|
||||||
|
2. Dynamic version of existing built-ins.
|
||||||
|
|
||||||
|
This provides a way to add missing functionality to firmware that doesn't
|
||||||
|
include certain built-in modules. See the `heapq`, `random`, `re`,
|
||||||
|
`deflate`, `btree`, and `framebuf` directories.
|
||||||
|
|
||||||
|
So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF`
|
||||||
|
disabled (e.g. to save flash space), then it would not include the
|
||||||
|
`framebuf` module. The `framebuf` native module provides a way to add the
|
||||||
|
`framebuf` module dynamically.
|
||||||
|
|
||||||
|
The way these work is they define a dynamic native module which
|
||||||
|
`#include`'s the original module and then does the necessary
|
||||||
|
initialisation of the module's globals dict.
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
To compile an example, you need to have the same toolchain available as
|
||||||
|
required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M
|
||||||
|
target. See the port instructions for details.
|
||||||
|
|
||||||
|
You also need to have the `pyelftools` Python package available, either via
|
||||||
|
your system package manager or installed from PyPI in a virtual environment
|
||||||
|
with `pip`.
|
||||||
|
|
||||||
|
Each example provides a Makefile. You should specify the `ARCH` argument to
|
||||||
|
make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin):
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd features0
|
||||||
|
$ make ARCH=armv7m
|
||||||
|
$ mpremote cp features0.mpy :
|
||||||
|
```
|
|
@ -1,3 +1,7 @@
|
||||||
# Implemented in Python to support keyword arguments
|
# Implemented in Python to support keyword arguments
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - this file is evaluated with C-defined names in scope
|
||||||
|
|
||||||
|
|
||||||
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
|
def open(stream, *, flags=0, cachesize=0, pagesize=0, minkeypage=0):
|
||||||
return _open(stream, flags, cachesize, pagesize, minkeypage)
|
return _open(stream, flags, cachesize, pagesize, minkeypage)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# This Python code will be merged with the C code in main.c
|
# This Python code will be merged with the C code in main.c
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - this file is evaluated with C-defined names in scope
|
||||||
|
|
||||||
import array
|
import array
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Location of top-level MicroPython directory
|
||||||
|
MPY_DIR = ../../..
|
||||||
|
|
||||||
|
# Name of module
|
||||||
|
MOD = features4
|
||||||
|
|
||||||
|
# Source files (.c or .py)
|
||||||
|
SRC = features4.c
|
||||||
|
|
||||||
|
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||||
|
ARCH = x64
|
||||||
|
|
||||||
|
# Include to get the rules for compiling and linking the module
|
||||||
|
include $(MPY_DIR)/py/dynruntime.mk
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
This example extends on features0 but demonstrates how to define a class.
|
||||||
|
|
||||||
|
The Factorial class constructor takes an integer, and then the calculate
|
||||||
|
method can be called to get the factorial.
|
||||||
|
|
||||||
|
>>> import features4
|
||||||
|
>>> f = features4.Factorial(4)
|
||||||
|
>>> f.calculate()
|
||||||
|
24
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Include the header file to get access to the MicroPython API
|
||||||
|
#include "py/dynruntime.h"
|
||||||
|
|
||||||
|
// This is type(Factorial)
|
||||||
|
mp_obj_full_type_t mp_type_factorial;
|
||||||
|
|
||||||
|
// This is the internal state of a Factorial instance.
|
||||||
|
typedef struct {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
mp_int_t n;
|
||||||
|
} mp_obj_factorial_t;
|
||||||
|
|
||||||
|
// Essentially Factorial.__new__ (but also kind of __init__).
|
||||||
|
// Takes a single argument (the number to find the factorial of)
|
||||||
|
STATIC mp_obj_t factorial_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, 1, 1, false);
|
||||||
|
|
||||||
|
mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type);
|
||||||
|
o->n = mp_obj_get_int(args_in[0]);
|
||||||
|
|
||||||
|
return MP_OBJ_FROM_PTR(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_int_t factorial_helper(mp_int_t x) {
|
||||||
|
if (x == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return x * factorial_helper(x - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Factorial.calculate()
|
||||||
|
STATIC mp_obj_t factorial_calculate(mp_obj_t self_in) {
|
||||||
|
mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
return mp_obj_new_int(factorial_helper(self->n));
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate);
|
||||||
|
|
||||||
|
// Locals dict for the Factorial type (will have a single method, calculate,
|
||||||
|
// added in mpy_init).
|
||||||
|
mp_map_elem_t factorial_locals_dict_table[1];
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table);
|
||||||
|
|
||||||
|
// This is the entry point and is called when the module is imported
|
||||||
|
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||||
|
// This must be first, it sets up the globals dict and other things
|
||||||
|
MP_DYNRUNTIME_INIT_ENTRY
|
||||||
|
|
||||||
|
// Initialise the type.
|
||||||
|
mp_type_factorial.base.type = (void*)&mp_type_type;
|
||||||
|
mp_type_factorial.flags = MP_TYPE_FLAG_NONE;
|
||||||
|
mp_type_factorial.name = MP_QSTR_Factorial;
|
||||||
|
MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0);
|
||||||
|
factorial_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) };
|
||||||
|
MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void*)&factorial_locals_dict, 1);
|
||||||
|
|
||||||
|
// Make the Factorial type available on the module.
|
||||||
|
mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial));
|
||||||
|
|
||||||
|
// This must be last, it restores the globals dict
|
||||||
|
MP_DYNRUNTIME_INIT_EXIT
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
# Example using PIO to blink an LED and raise an IRQ at 1Hz.
|
# Example using PIO to blink an LED and raise an IRQ at 1Hz.
|
||||||
# Note: this does not work on Pico W because it uses Pin(25) for LED output.
|
# Note: this does not work on Pico W because it uses Pin(25) for LED output.
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
import rp2
|
import rp2
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# - using set_init and set_base
|
# - using set_init and set_base
|
||||||
# - using StateMachine.exec
|
# - using StateMachine.exec
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
import rp2
|
import rp2
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
# - setting an irq handler for a StateMachine
|
# - setting an irq handler for a StateMachine
|
||||||
# - instantiating 2x StateMachine's with the same program and different pins
|
# - instantiating 2x StateMachine's with the same program and different pins
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
import rp2
|
import rp2
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Example of using PIO for PWM, and fading the brightness of an LED
|
# Example of using PIO for PWM, and fading the brightness of an LED
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
from rp2 import PIO, StateMachine, asm_pio
|
from rp2 import PIO, StateMachine, asm_pio
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
# - PIO irq handler
|
# - PIO irq handler
|
||||||
# - using the second core via _thread
|
# - using the second core via _thread
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import _thread
|
import _thread
|
||||||
from machine import Pin, UART
|
from machine import Pin, UART
|
||||||
from rp2 import PIO, StateMachine, asm_pio
|
from rp2 import PIO, StateMachine, asm_pio
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Example using PIO to create a UART TX interface
|
# Example using PIO to create a UART TX interface
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
from rp2 import PIO, StateMachine, asm_pio
|
from rp2 import PIO, StateMachine, asm_pio
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Example using PIO to drive a set of WS2812 LEDs.
|
# Example using PIO to drive a set of WS2812 LEDs.
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import array, time
|
import array, time
|
||||||
from machine import Pin
|
from machine import Pin
|
||||||
import rp2
|
import rp2
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Example using PWM to fade an LED.
|
# Example using PWM to fade an LED.
|
||||||
# Note: this does not work on Pico W because it uses Pin(25) for LED output.
|
# Note: this does not work on Pico W because it uses Pin(25) for LED output.
|
||||||
|
|
||||||
|
# ruff: noqa: F821 - @asm_pio decorator adds names to function scope
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from machine import Pin, PWM
|
from machine import Pin, PWM
|
||||||
|
|
||||||
|
|
|
@ -60,51 +60,62 @@ set(MICROPY_SOURCE_EXTMOD
|
||||||
|
|
||||||
if(MICROPY_PY_BTREE)
|
if(MICROPY_PY_BTREE)
|
||||||
set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx")
|
set(MICROPY_LIB_BERKELEY_DIR "${MICROPY_DIR}/lib/berkeley-db-1.xx")
|
||||||
|
string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/berkeley-db-1.xx)
|
||||||
|
|
||||||
add_library(micropy_extmod_btree OBJECT
|
if(ECHO_SUBMODULES)
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c
|
# No-op, we're just doing submodule/variant discovery.
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c
|
# Cannot run the add_library/target_include_directories rules (even though
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c
|
# the build won't run) because IDF will attempt verify the files exist.
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c
|
elseif(NOT EXISTS ${MICROPY_LIB_BERKELEY_DIR}/README)
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c
|
# Regular build, submodule not initialised -- fail with a clear error.
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c
|
message(FATAL_ERROR " MICROPY_PY_BTREE is enabled but the berkeley-db submodule is not initialised.\n Run 'make BOARD=${MICROPY_BOARD} submodules'")
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c
|
else()
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c
|
# Regular build, we have the submodule.
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c
|
add_library(micropy_extmod_btree OBJECT
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_close.c
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_conv.c
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_debug.c
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_delete.c
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_get.c
|
||||||
)
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_open.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_overflow.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_page.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_put.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_search.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_seq.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_split.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/btree/bt_utils.c
|
||||||
|
${MICROPY_LIB_BERKELEY_DIR}/mpool/mpool.c
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(micropy_extmod_btree PRIVATE
|
target_include_directories(micropy_extmod_btree PRIVATE
|
||||||
${MICROPY_LIB_BERKELEY_DIR}/PORT/include
|
${MICROPY_LIB_BERKELEY_DIR}/PORT/include
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(micropy_extmod_btree PRIVATE
|
target_compile_definitions(micropy_extmod_btree PRIVATE
|
||||||
__DBINTERFACE_PRIVATE=1
|
__DBINTERFACE_PRIVATE=1
|
||||||
mpool_error=printf
|
mpool_error=printf
|
||||||
abort=abort_
|
abort=abort_
|
||||||
"virt_fd_t=void*"
|
"virt_fd_t=void*"
|
||||||
)
|
)
|
||||||
|
|
||||||
# The include directories and compile definitions below are needed to build
|
# The include directories and compile definitions below are needed to build
|
||||||
# modbtree.c and should be added to the main MicroPython target.
|
# modbtree.c and should be added to the main MicroPython target.
|
||||||
|
|
||||||
list(APPEND MICROPY_INC_CORE
|
list(APPEND MICROPY_INC_CORE
|
||||||
"${MICROPY_LIB_BERKELEY_DIR}/PORT/include"
|
"${MICROPY_LIB_BERKELEY_DIR}/PORT/include"
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND MICROPY_DEF_CORE
|
list(APPEND MICROPY_DEF_CORE
|
||||||
MICROPY_PY_BTREE=1
|
MICROPY_PY_BTREE=1
|
||||||
__DBINTERFACE_PRIVATE=1
|
__DBINTERFACE_PRIVATE=1
|
||||||
"virt_fd_t=void*"
|
"virt_fd_t=void*"
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND MICROPY_SOURCE_EXTMOD
|
list(APPEND MICROPY_SOURCE_EXTMOD
|
||||||
${MICROPY_EXTMOD_DIR}/modbtree.c
|
${MICROPY_EXTMOD_DIR}/modbtree.c
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Library for mbedtls
|
# Library for mbedtls
|
||||||
|
|
|
@ -54,6 +54,8 @@ typedef enum {
|
||||||
DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP,
|
DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP,
|
||||||
} deflateio_format_t;
|
} deflateio_format_t;
|
||||||
|
|
||||||
|
// This is used when the wbits is unset in the DeflateIO constructor. Default
|
||||||
|
// to the smallest window size (faster compression, less RAM usage, etc).
|
||||||
const int DEFLATEIO_DEFAULT_WBITS = 8;
|
const int DEFLATEIO_DEFAULT_WBITS = 8;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -114,24 +116,32 @@ STATIC bool deflateio_init_read(mp_obj_deflateio_t *self) {
|
||||||
// Don't modify self->window_bits as it may also be used for write.
|
// Don't modify self->window_bits as it may also be used for write.
|
||||||
int wbits = self->window_bits;
|
int wbits = self->window_bits;
|
||||||
|
|
||||||
// Parse the header if we're in NONE/ZLIB/GZIP modes.
|
if (self->format == DEFLATEIO_FORMAT_RAW) {
|
||||||
if (self->format != DEFLATEIO_FORMAT_RAW) {
|
if (wbits == 0) {
|
||||||
int header_wbits = wbits;
|
// The docs recommends always setting wbits explicitly when using
|
||||||
|
// RAW, but we still allow a default.
|
||||||
|
wbits = DEFLATEIO_DEFAULT_WBITS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Parse the header if we're in NONE/ZLIB/GZIP modes.
|
||||||
|
int header_wbits;
|
||||||
int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits);
|
int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits);
|
||||||
if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) {
|
if (header_type < 0) {
|
||||||
|
// Stream header was invalid.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (wbits == 0 && header_wbits < 15) {
|
if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) {
|
||||||
// If the header specified something lower than the default, then
|
// Not what we expected.
|
||||||
// use that instead.
|
return false;
|
||||||
|
}
|
||||||
|
// header_wbits will either be 15 (gzip) or 8-15 (zlib).
|
||||||
|
if (wbits == 0 || header_wbits < wbits) {
|
||||||
|
// If the header specified something lower, then use that instead.
|
||||||
|
// No point doing a bigger allocation than we need to.
|
||||||
wbits = header_wbits;
|
wbits = header_wbits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wbits == 0) {
|
|
||||||
wbits = DEFLATEIO_DEFAULT_WBITS;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t window_len = 1 << wbits;
|
size_t window_len = 1 << wbits;
|
||||||
self->read->window = m_new(uint8_t, window_len);
|
self->read->window = m_new(uint8_t, window_len);
|
||||||
|
|
||||||
|
@ -163,6 +173,7 @@ STATIC bool deflateio_init_write(mp_obj_deflateio_t *self) {
|
||||||
|
|
||||||
int wbits = self->window_bits;
|
int wbits = self->window_bits;
|
||||||
if (wbits == 0) {
|
if (wbits == 0) {
|
||||||
|
// Same default wbits for all formats.
|
||||||
wbits = DEFLATEIO_DEFAULT_WBITS;
|
wbits = DEFLATEIO_DEFAULT_WBITS;
|
||||||
}
|
}
|
||||||
size_t window_len = 1 << wbits;
|
size_t window_len = 1 << wbits;
|
||||||
|
|
|
@ -1377,7 +1377,8 @@ STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
// level: SOL_SOCKET
|
// level: SOL_SOCKET
|
||||||
case SOF_REUSEADDR: {
|
case SOF_REUSEADDR:
|
||||||
|
case SOF_BROADCAST: {
|
||||||
mp_int_t val = mp_obj_get_int(args[3]);
|
mp_int_t val = mp_obj_get_int(args[3]);
|
||||||
// Options are common for UDP and TCP pcb's.
|
// Options are common for UDP and TCP pcb's.
|
||||||
if (val) {
|
if (val) {
|
||||||
|
@ -1786,6 +1787,7 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) },
|
{ MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) },
|
{ MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(SOF_BROADCAST) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) },
|
{ MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
|
{ MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
// Common option flags per-socket.
|
// Common option flags per-socket.
|
||||||
#define MOD_NETWORK_SO_REUSEADDR (0x0004)
|
#define MOD_NETWORK_SO_REUSEADDR (0x0004)
|
||||||
|
#define MOD_NETWORK_SO_BROADCAST (0x0020)
|
||||||
#define MOD_NETWORK_SO_KEEPALIVE (0x0008)
|
#define MOD_NETWORK_SO_KEEPALIVE (0x0008)
|
||||||
#define MOD_NETWORK_SO_SNDTIMEO (0x1005)
|
#define MOD_NETWORK_SO_SNDTIMEO (0x1005)
|
||||||
#define MOD_NETWORK_SO_RCVTIMEO (0x1006)
|
#define MOD_NETWORK_SO_RCVTIMEO (0x1006)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 Damien P. George
|
* Copyright (c) 2014-2023 Damien P. George
|
||||||
* Copyright (c) 2015-2017 Paul Sokolovsky
|
* Copyright (c) 2015-2017 Paul Sokolovsky
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -26,10 +26,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "py/mpconfig.h"
|
#include "py/mpconfig.h"
|
||||||
#if MICROPY_PY_SELECT
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/objlist.h"
|
#include "py/objlist.h"
|
||||||
|
@ -37,51 +33,248 @@
|
||||||
#include "py/mperrno.h"
|
#include "py/mperrno.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
|
|
||||||
// Flags for poll()
|
#if MICROPY_PY_SELECT
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_SELECT && MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
#error "select.select is not supported with MICROPY_PY_SELECT_POSIX_OPTIMISATIONS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#if !((MP_STREAM_POLL_RD) == (POLLIN) && \
|
||||||
|
(MP_STREAM_POLL_WR) == (POLLOUT) && \
|
||||||
|
(MP_STREAM_POLL_ERR) == (POLLERR) && \
|
||||||
|
(MP_STREAM_POLL_HUP) == (POLLHUP) && \
|
||||||
|
(MP_STREAM_POLL_NVAL) == (POLLNVAL))
|
||||||
|
#error "With MICROPY_PY_SELECT_POSIX_OPTIMISATIONS enabled, POLL constants must match"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When non-file-descriptor objects are on the list to be polled (the polling of
|
||||||
|
// which involves repeatedly calling ioctl(MP_STREAM_POLL)), this variable sets
|
||||||
|
// the period between polling these objects.
|
||||||
|
#define MICROPY_PY_SELECT_IOCTL_CALL_PERIOD_MS (1)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Flags for ipoll()
|
||||||
#define FLAG_ONESHOT (1)
|
#define FLAG_ONESHOT (1)
|
||||||
|
|
||||||
|
// A single pollable object.
|
||||||
typedef struct _poll_obj_t {
|
typedef struct _poll_obj_t {
|
||||||
mp_obj_t obj;
|
mp_obj_t obj;
|
||||||
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
|
||||||
mp_uint_t flags;
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
mp_uint_t flags_ret;
|
// If the pollable object has an associated file descriptor, then pollfd points to an entry
|
||||||
|
// in poll_set_t::pollfds, and the events/revents fields for this object are stored in the
|
||||||
|
// pollfd entry (and the nonfd_* members are unused).
|
||||||
|
// Otherwise the object is a non-file-descriptor object and pollfd==NULL, and the events/
|
||||||
|
// revents fields are stored in the nonfd_* members (which are named as such so that code
|
||||||
|
// doesn't accidentally mix the use of these members when this optimisation is used).
|
||||||
|
struct pollfd *pollfd;
|
||||||
|
uint16_t nonfd_events;
|
||||||
|
uint16_t nonfd_revents;
|
||||||
|
#else
|
||||||
|
mp_uint_t events;
|
||||||
|
mp_uint_t revents;
|
||||||
|
#endif
|
||||||
} poll_obj_t;
|
} poll_obj_t;
|
||||||
|
|
||||||
STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {
|
// A set of pollable objects.
|
||||||
|
typedef struct _poll_set_t {
|
||||||
|
// Map containing a dict with key=object to poll, value=its corresponding poll_obj_t.
|
||||||
|
mp_map_t map;
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
// Array of pollfd entries for objects that have a file descriptor.
|
||||||
|
unsigned short alloc; // memory allocated for pollfds
|
||||||
|
unsigned short max_used; // maximum number of used entries in pollfds
|
||||||
|
unsigned short used; // actual number of used entries in pollfds
|
||||||
|
struct pollfd *pollfds;
|
||||||
|
#endif
|
||||||
|
} poll_set_t;
|
||||||
|
|
||||||
|
STATIC void poll_set_init(poll_set_t *poll_set, size_t n) {
|
||||||
|
mp_map_init(&poll_set->map, n);
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
poll_set->alloc = 0;
|
||||||
|
poll_set->max_used = 0;
|
||||||
|
poll_set->used = 0;
|
||||||
|
poll_set->pollfds = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_SELECT
|
||||||
|
STATIC void poll_set_deinit(poll_set_t *poll_set) {
|
||||||
|
mp_map_deinit(&poll_set->map);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
|
||||||
|
STATIC mp_uint_t poll_obj_get_events(poll_obj_t *poll_obj) {
|
||||||
|
assert(poll_obj->pollfd == NULL);
|
||||||
|
return poll_obj->nonfd_events;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC void poll_obj_set_events(poll_obj_t *poll_obj, mp_uint_t events) {
|
||||||
|
if (poll_obj->pollfd != NULL) {
|
||||||
|
poll_obj->pollfd->events = events;
|
||||||
|
} else {
|
||||||
|
poll_obj->nonfd_events = events;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t poll_obj_get_revents(poll_obj_t *poll_obj) {
|
||||||
|
if (poll_obj->pollfd != NULL) {
|
||||||
|
return poll_obj->pollfd->revents;
|
||||||
|
} else {
|
||||||
|
return poll_obj->nonfd_revents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) {
|
||||||
|
if (poll_obj->pollfd != NULL) {
|
||||||
|
poll_obj->pollfd->revents = revents;
|
||||||
|
} else {
|
||||||
|
poll_obj->nonfd_revents = revents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC struct pollfd *poll_set_add_fd(poll_set_t *poll_set, int fd) {
|
||||||
|
struct pollfd *free_slot = NULL;
|
||||||
|
|
||||||
|
if (poll_set->used == poll_set->max_used) {
|
||||||
|
// No free slots below max_used, so expand max_used (and possibly allocate).
|
||||||
|
if (poll_set->max_used >= poll_set->alloc) {
|
||||||
|
poll_set->pollfds = m_renew(struct pollfd, poll_set->pollfds, poll_set->alloc, poll_set->alloc + 4);
|
||||||
|
poll_set->alloc += 4;
|
||||||
|
}
|
||||||
|
free_slot = &poll_set->pollfds[poll_set->max_used++];
|
||||||
|
} else {
|
||||||
|
// There should be a free slot below max_used.
|
||||||
|
for (unsigned int i = 0; i < poll_set->max_used; ++i) {
|
||||||
|
struct pollfd *slot = &poll_set->pollfds[i];
|
||||||
|
if (slot->fd == -1) {
|
||||||
|
free_slot = slot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(free_slot != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_slot->fd = fd;
|
||||||
|
++poll_set->used;
|
||||||
|
|
||||||
|
return free_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool poll_set_all_are_fds(poll_set_t *poll_set) {
|
||||||
|
return poll_set->map.used == poll_set->used;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline mp_uint_t poll_obj_get_events(poll_obj_t *poll_obj) {
|
||||||
|
return poll_obj->events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void poll_obj_set_events(poll_obj_t *poll_obj, mp_uint_t events) {
|
||||||
|
poll_obj->events = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mp_uint_t poll_obj_get_revents(poll_obj_t *poll_obj) {
|
||||||
|
return poll_obj->revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void poll_obj_set_revents(poll_obj_t *poll_obj, mp_uint_t revents) {
|
||||||
|
poll_obj->revents = revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC void poll_set_add_obj(poll_set_t *poll_set, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t events, bool or_events) {
|
||||||
for (mp_uint_t i = 0; i < obj_len; i++) {
|
for (mp_uint_t i = 0; i < obj_len; i++) {
|
||||||
mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
mp_map_elem_t *elem = mp_map_lookup(&poll_set->map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
||||||
if (elem->value == MP_OBJ_NULL) {
|
if (elem->value == MP_OBJ_NULL) {
|
||||||
// object not found; get its ioctl and add it to the poll list
|
// object not found; get its ioctl and add it to the poll list
|
||||||
const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
|
|
||||||
|
// If an exception is raised below when adding the new object then the map entry for that
|
||||||
|
// object remains unpopulated, and methods like poll() may crash. This case is not handled.
|
||||||
|
|
||||||
poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
|
poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
|
||||||
poll_obj->obj = obj[i];
|
poll_obj->obj = obj[i];
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
int fd = -1;
|
||||||
|
if (mp_obj_is_int(obj[i])) {
|
||||||
|
// A file descriptor integer passed in as the object, so use it directly.
|
||||||
|
fd = mp_obj_get_int(obj[i]);
|
||||||
|
if (fd < 0) {
|
||||||
|
mp_raise_ValueError(NULL);
|
||||||
|
}
|
||||||
|
poll_obj->ioctl = NULL;
|
||||||
|
} else {
|
||||||
|
// An object passed in. Check if it has a file descriptor.
|
||||||
|
const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
|
||||||
|
poll_obj->ioctl = stream_p->ioctl;
|
||||||
|
int err;
|
||||||
|
mp_uint_t res = stream_p->ioctl(obj[i], MP_STREAM_GET_FILENO, 0, &err);
|
||||||
|
if (res != MP_STREAM_ERROR) {
|
||||||
|
fd = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fd >= 0) {
|
||||||
|
// Object has a file descriptor so add it to pollfds.
|
||||||
|
poll_obj->pollfd = poll_set_add_fd(poll_set, fd);
|
||||||
|
} else {
|
||||||
|
// Object doesn't have a file descriptor.
|
||||||
|
poll_obj->pollfd = NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
|
||||||
poll_obj->ioctl = stream_p->ioctl;
|
poll_obj->ioctl = stream_p->ioctl;
|
||||||
poll_obj->flags = flags;
|
#endif
|
||||||
poll_obj->flags_ret = 0;
|
|
||||||
|
poll_obj_set_events(poll_obj, events);
|
||||||
|
poll_obj_set_revents(poll_obj, 0);
|
||||||
elem->value = MP_OBJ_FROM_PTR(poll_obj);
|
elem->value = MP_OBJ_FROM_PTR(poll_obj);
|
||||||
} else {
|
} else {
|
||||||
// object exists; update its flags
|
// object exists; update its events
|
||||||
if (or_flags) {
|
poll_obj_t *poll_obj = (poll_obj_t *)MP_OBJ_TO_PTR(elem->value);
|
||||||
((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags |= flags;
|
#if MICROPY_PY_SELECT_SELECT
|
||||||
} else {
|
if (or_events) {
|
||||||
((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = flags;
|
events |= poll_obj_get_events(poll_obj);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)or_events;
|
||||||
|
#endif
|
||||||
|
poll_obj_set_events(poll_obj, events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// poll each object in the map
|
// For each object in the poll set, poll it once.
|
||||||
STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
STATIC mp_uint_t poll_set_poll_once(poll_set_t *poll_set, size_t *rwx_num) {
|
||||||
mp_uint_t n_ready = 0;
|
mp_uint_t n_ready = 0;
|
||||||
for (mp_uint_t i = 0; i < poll_map->alloc; ++i) {
|
for (mp_uint_t i = 0; i < poll_set->map.alloc; ++i) {
|
||||||
if (!mp_map_slot_is_filled(poll_map, i)) {
|
if (!mp_map_slot_is_filled(&poll_set->map, i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value);
|
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set->map.table[i].value);
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
if (poll_obj->pollfd != NULL) {
|
||||||
|
// Object has file descriptor so will be polled separately by poll().
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int errcode;
|
int errcode;
|
||||||
mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode);
|
mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj_get_events(poll_obj), &errcode);
|
||||||
poll_obj->flags_ret = ret;
|
poll_obj_set_revents(poll_obj, ret);
|
||||||
|
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
// error doing ioctl
|
// error doing ioctl
|
||||||
|
@ -91,6 +284,7 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
// object is ready
|
// object is ready
|
||||||
n_ready += 1;
|
n_ready += 1;
|
||||||
|
#if MICROPY_PY_SELECT_SELECT
|
||||||
if (rwx_num != NULL) {
|
if (rwx_num != NULL) {
|
||||||
if (ret & MP_STREAM_POLL_RD) {
|
if (ret & MP_STREAM_POLL_RD) {
|
||||||
rwx_num[0] += 1;
|
rwx_num[0] += 1;
|
||||||
|
@ -102,11 +296,82 @@ STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
|
||||||
rwx_num[2] += 1;
|
rwx_num[2] += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)rwx_num;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n_ready;
|
return n_ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC mp_uint_t poll_set_poll_until_ready_or_timeout(poll_set_t *poll_set, size_t *rwx_num, mp_uint_t timeout) {
|
||||||
|
mp_uint_t start_ticks = mp_hal_ticks_ms();
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
|
|
||||||
|
// Compute the timeout.
|
||||||
|
int t = MICROPY_PY_SELECT_IOCTL_CALL_PERIOD_MS;
|
||||||
|
if (poll_set_all_are_fds(poll_set)) {
|
||||||
|
// All our pollables are file descriptors, so we can use a blocking
|
||||||
|
// poll and let it (the underlying system) handle the timeout.
|
||||||
|
if (timeout == (mp_uint_t)-1) {
|
||||||
|
t = -1;
|
||||||
|
} else {
|
||||||
|
mp_uint_t delta = mp_hal_ticks_ms() - start_ticks;
|
||||||
|
if (delta >= timeout) {
|
||||||
|
t = 0;
|
||||||
|
} else {
|
||||||
|
t = timeout - delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call system poll for those objects that have a file descriptor.
|
||||||
|
int n_ready = poll(poll_set->pollfds, poll_set->max_used, t);
|
||||||
|
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
|
|
||||||
|
// The call to poll() may have been interrupted, but per PEP 475 we must retry if the
|
||||||
|
// signal is EINTR (this implements a special case of calling MP_HAL_RETRY_SYSCALL()).
|
||||||
|
if (n_ready == -1) {
|
||||||
|
int err = errno;
|
||||||
|
if (err != EINTR) {
|
||||||
|
mp_raise_OSError(err);
|
||||||
|
}
|
||||||
|
n_ready = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly poll any objects that do not have a file descriptor.
|
||||||
|
if (!poll_set_all_are_fds(poll_set)) {
|
||||||
|
n_ready += poll_set_poll_once(poll_set, rwx_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if an object is ready, or if the timeout expired.
|
||||||
|
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) {
|
||||||
|
return n_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This would be MICROPY_EVENT_POLL_HOOK but the call to poll() above already includes a delay.
|
||||||
|
mp_handle_pending(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
// poll the objects
|
||||||
|
mp_uint_t n_ready = poll_set_poll_once(poll_set, rwx_num);
|
||||||
|
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_ticks >= timeout)) {
|
||||||
|
return n_ready;
|
||||||
|
}
|
||||||
|
MICROPY_EVENT_POLL_HOOK
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if MICROPY_PY_SELECT_SELECT
|
#if MICROPY_PY_SELECT_SELECT
|
||||||
// select(rlist, wlist, xlist[, timeout])
|
// select(rlist, wlist, xlist[, timeout])
|
||||||
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||||
|
@ -133,52 +398,46 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge separate lists and get the ioctl function for each object
|
// merge separate lists and get the ioctl function for each object
|
||||||
mp_map_t poll_map;
|
poll_set_t poll_set;
|
||||||
mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]);
|
poll_set_init(&poll_set, rwx_len[0] + rwx_len[1] + rwx_len[2]);
|
||||||
poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);
|
poll_set_add_obj(&poll_set, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);
|
||||||
poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);
|
poll_set_add_obj(&poll_set, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);
|
||||||
poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);
|
poll_set_add_obj(&poll_set, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);
|
||||||
|
|
||||||
mp_uint_t start_tick = mp_hal_ticks_ms();
|
// poll all objects
|
||||||
rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
|
rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
|
||||||
for (;;) {
|
poll_set_poll_until_ready_or_timeout(&poll_set, rwx_len, timeout);
|
||||||
// poll the objects
|
|
||||||
mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len);
|
|
||||||
|
|
||||||
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
|
// one or more objects are ready, or we had a timeout
|
||||||
// one or more objects are ready, or we had a timeout
|
mp_obj_t list_array[3];
|
||||||
mp_obj_t list_array[3];
|
list_array[0] = mp_obj_new_list(rwx_len[0], NULL);
|
||||||
list_array[0] = mp_obj_new_list(rwx_len[0], NULL);
|
list_array[1] = mp_obj_new_list(rwx_len[1], NULL);
|
||||||
list_array[1] = mp_obj_new_list(rwx_len[1], NULL);
|
list_array[2] = mp_obj_new_list(rwx_len[2], NULL);
|
||||||
list_array[2] = mp_obj_new_list(rwx_len[2], NULL);
|
rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
|
||||||
rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
|
for (mp_uint_t i = 0; i < poll_set.map.alloc; ++i) {
|
||||||
for (mp_uint_t i = 0; i < poll_map.alloc; ++i) {
|
if (!mp_map_slot_is_filled(&poll_set.map, i)) {
|
||||||
if (!mp_map_slot_is_filled(&poll_map, i)) {
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_set.map.table[i].value);
|
||||||
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value);
|
if (poll_obj->revents & MP_STREAM_POLL_RD) {
|
||||||
if (poll_obj->flags_ret & MP_STREAM_POLL_RD) {
|
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj;
|
||||||
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj;
|
}
|
||||||
}
|
if (poll_obj->revents & MP_STREAM_POLL_WR) {
|
||||||
if (poll_obj->flags_ret & MP_STREAM_POLL_WR) {
|
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj;
|
||||||
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj;
|
}
|
||||||
}
|
if ((poll_obj->revents & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
|
||||||
if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
|
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj;
|
||||||
((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mp_map_deinit(&poll_map);
|
|
||||||
return mp_obj_new_tuple(3, list_array);
|
|
||||||
}
|
}
|
||||||
MICROPY_EVENT_POLL_HOOK
|
|
||||||
}
|
}
|
||||||
|
poll_set_deinit(&poll_set);
|
||||||
|
return mp_obj_new_tuple(3, list_array);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
|
||||||
#endif // MICROPY_PY_SELECT_SELECT
|
#endif // MICROPY_PY_SELECT_SELECT
|
||||||
|
|
||||||
typedef struct _mp_obj_poll_t {
|
typedef struct _mp_obj_poll_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
mp_map_t poll_map;
|
poll_set_t poll_set;
|
||||||
short iter_cnt;
|
short iter_cnt;
|
||||||
short iter_idx;
|
short iter_idx;
|
||||||
int flags;
|
int flags;
|
||||||
|
@ -189,13 +448,13 @@ typedef struct _mp_obj_poll_t {
|
||||||
// register(obj[, eventmask])
|
// register(obj[, eventmask])
|
||||||
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
mp_uint_t flags;
|
mp_uint_t events;
|
||||||
if (n_args == 3) {
|
if (n_args == 3) {
|
||||||
flags = mp_obj_get_int(args[2]);
|
events = mp_obj_get_int(args[2]);
|
||||||
} else {
|
} else {
|
||||||
flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;
|
events = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;
|
||||||
}
|
}
|
||||||
poll_map_add(&self->poll_map, &args[1], 1, flags, false);
|
poll_set_add_obj(&self->poll_set, &args[1], 1, events, false);
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
||||||
|
@ -203,7 +462,21 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
|
||||||
// unregister(obj)
|
// unregister(obj)
|
||||||
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
mp_map_elem_t *elem = mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
|
||||||
|
|
||||||
|
#if MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
|
if (elem != NULL) {
|
||||||
|
poll_obj_t *poll_obj = (poll_obj_t *)MP_OBJ_TO_PTR(elem->value);
|
||||||
|
if (poll_obj->pollfd != NULL) {
|
||||||
|
poll_obj->pollfd->fd = -1;
|
||||||
|
--self->poll_set.used;
|
||||||
|
}
|
||||||
|
elem->value = MP_OBJ_NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)elem;
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO raise KeyError if obj didn't exist in map
|
// TODO raise KeyError if obj didn't exist in map
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
@ -212,11 +485,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
|
||||||
// modify(obj, eventmask)
|
// modify(obj, eventmask)
|
||||||
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
mp_map_elem_t *elem = mp_map_lookup(&self->poll_set.map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
|
||||||
if (elem == NULL) {
|
if (elem == NULL) {
|
||||||
mp_raise_OSError(MP_ENOENT);
|
mp_raise_OSError(MP_ENOENT);
|
||||||
}
|
}
|
||||||
((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in);
|
poll_obj_set_events((poll_obj_t *)MP_OBJ_TO_PTR(elem->value), mp_obj_get_int(eventmask_in));
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
|
MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
|
||||||
|
@ -241,18 +514,7 @@ STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) {
|
||||||
|
|
||||||
self->flags = flags;
|
self->flags = flags;
|
||||||
|
|
||||||
mp_uint_t start_tick = mp_hal_ticks_ms();
|
return poll_set_poll_until_ready_or_timeout(&self->poll_set, NULL, timeout);
|
||||||
mp_uint_t n_ready;
|
|
||||||
for (;;) {
|
|
||||||
// poll the objects
|
|
||||||
n_ready = poll_map_poll(&self->poll_map, NULL);
|
|
||||||
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MICROPY_EVENT_POLL_HOOK
|
|
||||||
}
|
|
||||||
|
|
||||||
return n_ready;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
|
||||||
|
@ -262,23 +524,19 @@ STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
|
||||||
// one or more objects are ready, or we had a timeout
|
// one or more objects are ready, or we had a timeout
|
||||||
mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));
|
mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));
|
||||||
n_ready = 0;
|
n_ready = 0;
|
||||||
for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) {
|
for (mp_uint_t i = 0; i < self->poll_set.map.alloc; ++i) {
|
||||||
if (!mp_map_slot_is_filled(&self->poll_map, i)) {
|
if (!mp_map_slot_is_filled(&self->poll_set.map, i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
|
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value);
|
||||||
if (poll_obj->flags_ret != 0) {
|
if (poll_obj_get_revents(poll_obj) != 0) {
|
||||||
mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)};
|
mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj_get_revents(poll_obj))};
|
||||||
ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);
|
ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);
|
||||||
if (self->flags & FLAG_ONESHOT) {
|
|
||||||
// Don't poll next time, until new event flags will be set explicitly
|
|
||||||
poll_obj->flags = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(ret_list);
|
return MP_OBJ_FROM_PTR(ret_list);
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);
|
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 2, poll_poll);
|
||||||
|
|
||||||
STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {
|
||||||
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||||
|
@ -304,19 +562,19 @@ STATIC mp_obj_t poll_iternext(mp_obj_t self_in) {
|
||||||
|
|
||||||
self->iter_cnt--;
|
self->iter_cnt--;
|
||||||
|
|
||||||
for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) {
|
for (mp_uint_t i = self->iter_idx; i < self->poll_set.map.alloc; ++i) {
|
||||||
self->iter_idx++;
|
self->iter_idx++;
|
||||||
if (!mp_map_slot_is_filled(&self->poll_map, i)) {
|
if (!mp_map_slot_is_filled(&self->poll_set.map, i)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
|
poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_set.map.table[i].value);
|
||||||
if (poll_obj->flags_ret != 0) {
|
if (poll_obj_get_revents(poll_obj) != 0) {
|
||||||
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);
|
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);
|
||||||
t->items[0] = poll_obj->obj;
|
t->items[0] = poll_obj->obj;
|
||||||
t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret);
|
t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj_get_revents(poll_obj));
|
||||||
if (self->flags & FLAG_ONESHOT) {
|
if (self->flags & FLAG_ONESHOT) {
|
||||||
// Don't poll next time, until new event flags will be set explicitly
|
// Don't poll next time, until new event mask will be set explicitly
|
||||||
poll_obj->flags = 0;
|
poll_obj_set_events(poll_obj, 0);
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(t);
|
return MP_OBJ_FROM_PTR(t);
|
||||||
}
|
}
|
||||||
|
@ -347,7 +605,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
// poll()
|
// poll()
|
||||||
STATIC mp_obj_t select_poll(void) {
|
STATIC mp_obj_t select_poll(void) {
|
||||||
mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll);
|
mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll);
|
||||||
mp_map_init(&poll->poll_map, 0);
|
poll_set_init(&poll->poll_set, 0);
|
||||||
poll->iter_cnt = 0;
|
poll->iter_cnt = 0;
|
||||||
poll->ret_tuple = MP_OBJ_NULL;
|
poll->ret_tuple = MP_OBJ_NULL;
|
||||||
return MP_OBJ_FROM_PTR(poll);
|
return MP_OBJ_FROM_PTR(poll);
|
||||||
|
|
|
@ -631,6 +631,7 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(MOD_NETWORK_SOL_SOCKET) },
|
{ MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(MOD_NETWORK_SOL_SOCKET) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(MOD_NETWORK_SO_REUSEADDR) },
|
{ MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(MOD_NETWORK_SO_REUSEADDR) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_SO_BROADCAST), MP_ROM_INT(MOD_NETWORK_SO_BROADCAST) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SO_KEEPALIVE), MP_ROM_INT(MOD_NETWORK_SO_KEEPALIVE) },
|
{ MP_ROM_QSTR(MP_QSTR_SO_KEEPALIVE), MP_ROM_INT(MOD_NETWORK_SO_KEEPALIVE) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SO_SNDTIMEO), MP_ROM_INT(MOD_NETWORK_SO_SNDTIMEO) },
|
{ MP_ROM_QSTR(MP_QSTR_SO_SNDTIMEO), MP_ROM_INT(MOD_NETWORK_SO_SNDTIMEO) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_SO_RCVTIMEO), MP_ROM_INT(MOD_NETWORK_SO_RCVTIMEO) },
|
{ MP_ROM_QSTR(MP_QSTR_SO_RCVTIMEO), MP_ROM_INT(MOD_NETWORK_SO_RCVTIMEO) },
|
||||||
|
|
|
@ -168,6 +168,12 @@ STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args
|
||||||
mbedtls_debug_set_threshold(3);
|
mbedtls_debug_set_threshold(3);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Whenever the PSA interface is used (if MBEDTLS_PSA_CRYPTO), psa_crypto_init() needs to be called before any TLS related operations.
|
||||||
|
// TLSv1.3 depends on the PSA interface, TLSv1.2 only uses the PSA stack if MBEDTLS_USE_PSA_CRYPTO is defined.
|
||||||
|
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) || defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||||
|
psa_crypto_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
const byte seed[] = "upy";
|
const byte seed[] = "upy";
|
||||||
int ret = mbedtls_ctr_drbg_seed(&self->ctr_drbg, mbedtls_entropy_func, &self->entropy, seed, sizeof(seed));
|
int ret = mbedtls_ctr_drbg_seed(&self->ctr_drbg, mbedtls_entropy_func, &self->entropy, seed, sizeof(seed));
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
|
@ -394,6 +400,7 @@ STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t
|
||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
o->sock = MP_OBJ_NULL;
|
||||||
mbedtls_ssl_free(&o->ssl);
|
mbedtls_ssl_free(&o->ssl);
|
||||||
mbedtls_raise_error(ret);
|
mbedtls_raise_error(ret);
|
||||||
}
|
}
|
||||||
|
@ -436,6 +443,14 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
|
||||||
// renegotiation.
|
// renegotiation.
|
||||||
ret = MP_EWOULDBLOCK;
|
ret = MP_EWOULDBLOCK;
|
||||||
o->poll_mask = MP_STREAM_POLL_WR;
|
o->poll_mask = MP_STREAM_POLL_WR;
|
||||||
|
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
|
||||||
|
} else if (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) {
|
||||||
|
// It appears a new session ticket being issued by the server right after
|
||||||
|
// completed handshake is not uncommon and shouldn't be treated as fatal.
|
||||||
|
// mbedtls itself states "This error code is experimental and may be
|
||||||
|
// changed or removed without notice."
|
||||||
|
ret = MP_EWOULDBLOCK;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
o->last_error = ret;
|
o->last_error = ret;
|
||||||
}
|
}
|
||||||
|
@ -486,15 +501,20 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
|
||||||
mp_uint_t ret = 0;
|
mp_uint_t ret = 0;
|
||||||
uintptr_t saved_arg = 0;
|
uintptr_t saved_arg = 0;
|
||||||
mp_obj_t sock = self->sock;
|
mp_obj_t sock = self->sock;
|
||||||
if (sock == MP_OBJ_NULL || (request != MP_STREAM_CLOSE && self->last_error != 0)) {
|
|
||||||
// Closed or error socket:
|
|
||||||
return MP_STREAM_POLL_NVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request == MP_STREAM_CLOSE) {
|
if (request == MP_STREAM_CLOSE) {
|
||||||
|
if (sock == MP_OBJ_NULL) {
|
||||||
|
// Already closed socket, do nothing.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
self->sock = MP_OBJ_NULL;
|
self->sock = MP_OBJ_NULL;
|
||||||
mbedtls_ssl_free(&self->ssl);
|
mbedtls_ssl_free(&self->ssl);
|
||||||
} else if (request == MP_STREAM_POLL) {
|
} else if (request == MP_STREAM_POLL) {
|
||||||
|
if (sock == MP_OBJ_NULL || self->last_error != 0) {
|
||||||
|
// Closed or error socket, return NVAL flag.
|
||||||
|
return MP_STREAM_POLL_NVAL;
|
||||||
|
}
|
||||||
|
|
||||||
// If the library signaled us that it needs reading or writing, only check that direction,
|
// If the library signaled us that it needs reading or writing, only check that direction,
|
||||||
// but save what the caller asked because we need to restore it later
|
// but save what the caller asked because we need to restore it later
|
||||||
if (self->poll_mask && (arg & MP_STREAM_POLL_RDWR)) {
|
if (self->poll_mask && (arg & MP_STREAM_POLL_RDWR)) {
|
||||||
|
@ -514,6 +534,10 @@ STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Unsupported ioctl.
|
||||||
|
*errcode = MP_EINVAL;
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass all requests down to the underlying socket
|
// Pass all requests down to the underlying socket
|
||||||
|
|
|
@ -153,12 +153,17 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case MP_STREAM_FLUSH: {
|
case MP_STREAM_FLUSH: {
|
||||||
int ret;
|
int ret;
|
||||||
|
// fsync(stdin/stdout/stderr) may fail with EINVAL (or ENOTSUP on macos),
|
||||||
|
// but don't propagate that error out. Because data is not buffered by
|
||||||
|
// us, and stdin/out/err.flush() should just be a no-op.
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL || err == ENOTSUP)
|
||||||
|
#else
|
||||||
|
#define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL)
|
||||||
|
#endif
|
||||||
MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), {
|
MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), {
|
||||||
if (err == EINVAL
|
if (VFS_POSIX_STREAM_STDIO_ERR_CATCH
|
||||||
&& (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) {
|
&& (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) {
|
||||||
// fsync(stdin/stdout/stderr) may fail with EINVAL, but don't propagate that
|
|
||||||
// error out. Because data is not buffered by us, and stdin/out/err.flush()
|
|
||||||
// should just be a no-op.
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*errcode = err;
|
*errcode = err;
|
||||||
|
@ -188,7 +193,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||||
return 0;
|
return 0;
|
||||||
case MP_STREAM_GET_FILENO:
|
case MP_STREAM_GET_FILENO:
|
||||||
return o->fd;
|
return o->fd;
|
||||||
#if MICROPY_PY_SELECT
|
#if MICROPY_PY_SELECT && !MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
|
||||||
case MP_STREAM_POLL: {
|
case MP_STREAM_POLL: {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
|
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
|
||||||
|
@ -209,6 +214,15 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
|
||||||
if (pfd.revents & POLLOUT) {
|
if (pfd.revents & POLLOUT) {
|
||||||
ret |= MP_STREAM_POLL_WR;
|
ret |= MP_STREAM_POLL_WR;
|
||||||
}
|
}
|
||||||
|
if (pfd.revents & POLLERR) {
|
||||||
|
ret |= MP_STREAM_POLL_ERR;
|
||||||
|
}
|
||||||
|
if (pfd.revents & POLLHUP) {
|
||||||
|
ret |= MP_STREAM_POLL_HUP;
|
||||||
|
}
|
||||||
|
if (pfd.revents & POLLNVAL) {
|
||||||
|
ret |= MP_STREAM_POLL_NVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
|
@ -260,12 +274,58 @@ STATIC const mp_stream_p_t vfs_posix_textio_stream_p = {
|
||||||
.is_text = true,
|
.is_text = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if MICROPY_PY_SYS_STDIO_BUFFER
|
||||||
|
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stdin_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDIN_FILENO};
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stdout_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDOUT_FILENO};
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stderr_buffer_obj = {{&mp_type_vfs_posix_fileio}, STDERR_FILENO};
|
||||||
|
|
||||||
|
// Forward declarations.
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stdin_obj;
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj;
|
||||||
|
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj;
|
||||||
|
|
||||||
|
STATIC void vfs_posix_textio_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||||
|
if (dest[0] != MP_OBJ_NULL) {
|
||||||
|
// These objects are read-only.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr == MP_QSTR_buffer) {
|
||||||
|
// Implement the `buffer` attribute only on std{in,out,err} instances.
|
||||||
|
if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdin_obj) {
|
||||||
|
dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdin_buffer_obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stdout_obj) {
|
||||||
|
dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stdout_buffer_obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (MP_OBJ_TO_PTR(self_in) == &mp_sys_stderr_obj) {
|
||||||
|
dest[0] = MP_OBJ_FROM_PTR(&mp_sys_stderr_buffer_obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other attribute - forward to locals dict.
|
||||||
|
dest[1] = MP_OBJ_SENTINEL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VFS_POSIX_TEXTIO_TYPE_ATTR attr, vfs_posix_textio_attr,
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define VFS_POSIX_TEXTIO_TYPE_ATTR
|
||||||
|
|
||||||
|
#endif // MICROPY_PY_SYS_STDIO_BUFFER
|
||||||
|
|
||||||
MP_DEFINE_CONST_OBJ_TYPE(
|
MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
mp_type_vfs_posix_textio,
|
mp_type_vfs_posix_textio,
|
||||||
MP_QSTR_TextIOWrapper,
|
MP_QSTR_TextIOWrapper,
|
||||||
MP_TYPE_FLAG_ITER_IS_STREAM,
|
MP_TYPE_FLAG_ITER_IS_STREAM,
|
||||||
print, vfs_posix_file_print,
|
print, vfs_posix_file_print,
|
||||||
protocol, &vfs_posix_textio_stream_p,
|
protocol, &vfs_posix_textio_stream_p,
|
||||||
|
VFS_POSIX_TEXTIO_TYPE_ATTR
|
||||||
locals_dict, &vfs_posix_rawfile_locals_dict
|
locals_dict, &vfs_posix_rawfile_locals_dict
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,10 @@ int uzlib_parse_zlib_gzip_header(uzlib_uncomp_t *d, int *wbits)
|
||||||
d->checksum_type = UZLIB_CHKSUM_CRC;
|
d->checksum_type = UZLIB_CHKSUM_CRC;
|
||||||
d->checksum = ~0;
|
d->checksum = ~0;
|
||||||
|
|
||||||
|
/* gzip does not include the window size in the header, as it is expected that a
|
||||||
|
compressor will use wbits=15 (32kiB).*/
|
||||||
|
*wbits = 15;
|
||||||
|
|
||||||
return UZLIB_HEADER_GZIP;
|
return UZLIB_HEADER_GZIP;
|
||||||
} else {
|
} else {
|
||||||
/* check checksum */
|
/* check checksum */
|
||||||
|
|
|
@ -100,7 +100,7 @@ def compile(src, dest=None, src_path=None, opt=None, march=None, mpy_cross=None,
|
||||||
if not src:
|
if not src:
|
||||||
raise ValueError("src is required")
|
raise ValueError("src is required")
|
||||||
if not os.path.exists(src):
|
if not os.path.exists(src):
|
||||||
raise CrossCompileError("Input .py file not found: {}.".format(src_py))
|
raise CrossCompileError("Input .py file not found: {}.".format(src))
|
||||||
|
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ endif
|
||||||
|
|
||||||
# Make 'release' the default build type
|
# Make 'release' the default build type
|
||||||
BTYPE ?= release
|
BTYPE ?= release
|
||||||
|
# Make the 'application' by default ('bootloader' can be built explicitly)
|
||||||
|
BTARGET ?= application
|
||||||
|
|
||||||
# Port for flashing firmware
|
# Port for flashing firmware
|
||||||
PORT ?= /dev/ttyUSB1
|
PORT ?= /dev/ttyUSB1
|
||||||
|
|
|
@ -198,7 +198,7 @@ WIPY_IP ?= '192.168.1.1'
|
||||||
WIPY_USER ?= 'micro'
|
WIPY_USER ?= 'micro'
|
||||||
WIPY_PWD ?= 'python'
|
WIPY_PWD ?= 'python'
|
||||||
|
|
||||||
all: $(BUILD)/mcuimg.bin
|
all: $(BUILD)/firmware.zip
|
||||||
|
|
||||||
.PHONY: deploy-ota
|
.PHONY: deploy-ota
|
||||||
|
|
||||||
|
@ -219,6 +219,10 @@ $(BUILD)/mcuimg.bin: $(BUILD)/application.bin
|
||||||
$(ECHO) "Create $@"
|
$(ECHO) "Create $@"
|
||||||
$(Q)$(SHELL) $(APP_SIGN) $(BUILD)
|
$(Q)$(SHELL) $(APP_SIGN) $(BUILD)
|
||||||
|
|
||||||
|
$(BUILD)/firmware.zip: $(BUILD)/mcuimg.bin
|
||||||
|
$(ECHO) "Create $@"
|
||||||
|
$(Q)$(ZIP) -j $@ $<
|
||||||
|
|
||||||
MAKE_PINS = boards/make-pins.py
|
MAKE_PINS = boards/make-pins.py
|
||||||
BOARD_PINS = boards/$(BOARD)/pins.csv
|
BOARD_PINS = boards/$(BOARD)/pins.csv
|
||||||
AF_FILE = boards/cc3200_af.csv
|
AF_FILE = boards/cc3200_af.csv
|
||||||
|
|
|
@ -5,13 +5,11 @@
|
||||||
"docs": "https://docs.pycom.io/datasheets/development/wipy3/",
|
"docs": "https://docs.pycom.io/datasheets/development/wipy3/",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
"Breadboard Friendly",
|
"External Flash",
|
||||||
"MicroSD",
|
|
||||||
"RGB LED",
|
"RGB LED",
|
||||||
"SPI Flash",
|
"WiFi",
|
||||||
"WiFi"
|
"microSD"
|
||||||
],
|
],
|
||||||
"id": "wipy",
|
|
||||||
"images": [
|
"images": [
|
||||||
"wipy.jpg"
|
"wipy.jpg"
|
||||||
],
|
],
|
||||||
|
|
|
@ -89,6 +89,10 @@ void mp_thread_set_state(mp_state_thread_t *state) {
|
||||||
vTaskSetThreadLocalStoragePointer(NULL, 0, state);
|
vTaskSetThreadLocalStoragePointer(NULL, 0, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_uint_t mp_thread_get_id(void) {
|
||||||
|
return (mp_uint_t)xTaskGetCurrentTaskHandle();
|
||||||
|
}
|
||||||
|
|
||||||
void mp_thread_start(void) {
|
void mp_thread_start(void) {
|
||||||
mp_thread_mutex_lock(&thread_mutex, 1);
|
mp_thread_mutex_lock(&thread_mutex, 1);
|
||||||
for (mp_thread_t *th = thread; th != NULL; th = th->next) {
|
for (mp_thread_t *th = thread; th != NULL; th = th->next) {
|
||||||
|
@ -111,7 +115,7 @@ STATIC void freertos_entry(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) {
|
mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) {
|
||||||
// store thread entry function into a global variable so we can access it
|
// store thread entry function into a global variable so we can access it
|
||||||
ext_thread_entry = entry;
|
ext_thread_entry = entry;
|
||||||
|
|
||||||
|
@ -148,6 +152,9 @@ void mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) {
|
||||||
|
|
||||||
// adjust stack_size to provide room to recover from hitting the limit
|
// adjust stack_size to provide room to recover from hitting the limit
|
||||||
*stack_size -= 512;
|
*stack_size -= 512;
|
||||||
|
|
||||||
|
MP_STATIC_ASSERT(sizeof(mp_uint_t) >= sizeof(TaskHandle_t));
|
||||||
|
return (mp_uint_t)id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_thread_finish(void) {
|
void mp_thread_finish(void) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ def execute(command):
|
||||||
if exitCode == 0:
|
if exitCode == 0:
|
||||||
return cmd_log
|
return cmd_log
|
||||||
else:
|
else:
|
||||||
raise ProcessException(command, exitCode, output)
|
raise subprocess.CalledProcessError(exitCode, command, output)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.12)
|
||||||
|
|
||||||
# Set the board if it's not already set.
|
# Set the board if it's not already set.
|
||||||
if(NOT MICROPY_BOARD)
|
if(NOT MICROPY_BOARD)
|
||||||
set(MICROPY_BOARD GENERIC)
|
set(MICROPY_BOARD ESP32_GENERIC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set the board directory and check that it exists.
|
# Set the board directory and check that it exists.
|
||||||
|
|
|
@ -8,17 +8,25 @@ ifdef BOARD_DIR
|
||||||
# the path as the board name.
|
# the path as the board name.
|
||||||
BOARD ?= $(notdir $(BOARD_DIR:/=))
|
BOARD ?= $(notdir $(BOARD_DIR:/=))
|
||||||
else
|
else
|
||||||
# If not given on the command line, then default to GENERIC.
|
# If not given on the command line, then default to ESP32_GENERIC.
|
||||||
BOARD ?= GENERIC
|
BOARD ?= ESP32_GENERIC
|
||||||
BOARD_DIR ?= boards/$(BOARD)
|
BOARD_DIR ?= boards/$(BOARD)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(wildcard $(BOARD_DIR)/.),)
|
ifeq ($(wildcard $(BOARD_DIR)/.),)
|
||||||
|
ifeq ($(findstring boards/GENERIC,$(BOARD_DIR)),boards/GENERIC)
|
||||||
|
$(warning The GENERIC* boards have been renamed to ESP32_GENERIC*)
|
||||||
|
endif
|
||||||
$(error Invalid BOARD specified: $(BOARD_DIR))
|
$(error Invalid BOARD specified: $(BOARD_DIR))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# If the build directory is not given, make it reflect the board name.
|
# If the build directory is not given, make it reflect the board name (and
|
||||||
|
# optionally the board variant).
|
||||||
|
ifneq ($(BOARD_VARIANT),)
|
||||||
|
BUILD ?= build-$(BOARD)-$(BOARD_VARIANT)
|
||||||
|
else
|
||||||
BUILD ?= build-$(BOARD)
|
BUILD ?= build-$(BOARD)
|
||||||
|
endif
|
||||||
|
|
||||||
# Device serial settings.
|
# Device serial settings.
|
||||||
PORT ?= /dev/ttyUSB0
|
PORT ?= /dev/ttyUSB0
|
||||||
|
@ -26,12 +34,6 @@ BAUD ?= 460800
|
||||||
|
|
||||||
PYTHON ?= python3
|
PYTHON ?= python3
|
||||||
|
|
||||||
# Would be good to use cmake to discover submodules (see how rp2/Makefile does
|
|
||||||
# it), but on ESP32 the same trick doesn't work because "idf.py build" fails
|
|
||||||
# on berkeley-db dependency before printing out the submodule list.
|
|
||||||
# For now just force the submodule dependencies here.
|
|
||||||
GIT_SUBMODULES += lib/berkeley-db-1.xx lib/micropython-lib
|
|
||||||
|
|
||||||
.PHONY: all clean deploy erase submodules FORCE
|
.PHONY: all clean deploy erase submodules FORCE
|
||||||
|
|
||||||
CMAKE_ARGS =
|
CMAKE_ARGS =
|
||||||
|
@ -40,20 +42,24 @@ ifdef USER_C_MODULES
|
||||||
CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES}
|
CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR=$(abspath $(BOARD_DIR)) -B $(BUILD) $(CMAKE_ARGS)
|
IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR=$(abspath $(BOARD_DIR)) $(CMAKE_ARGS)
|
||||||
|
|
||||||
ifdef FROZEN_MANIFEST
|
ifdef FROZEN_MANIFEST
|
||||||
IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
|
IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef BOARD_VARIANT
|
||||||
|
IDFPY_FLAGS += -D MICROPY_BOARD_VARIANT=$(BOARD_VARIANT)
|
||||||
|
endif
|
||||||
|
|
||||||
HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m"
|
HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m"
|
||||||
|
|
||||||
define RUN_IDF_PY
|
define RUN_IDF_PY
|
||||||
idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) $(1)
|
idf.py $(IDFPY_FLAGS) -B $(BUILD) -p $(PORT) -b $(BAUD) $(1)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
all:
|
all:
|
||||||
idf.py $(IDFPY_FLAGS) build || (echo -e $(HELP_BUILD_ERROR); false)
|
idf.py $(IDFPY_FLAGS) -B $(BUILD) build || (echo -e $(HELP_BUILD_ERROR); false)
|
||||||
@$(PYTHON) makeimg.py \
|
@$(PYTHON) makeimg.py \
|
||||||
$(BUILD)/sdkconfig \
|
$(BUILD)/sdkconfig \
|
||||||
$(BUILD)/bootloader/bootloader.bin \
|
$(BUILD)/bootloader/bootloader.bin \
|
||||||
|
@ -85,5 +91,12 @@ size-components:
|
||||||
size-files:
|
size-files:
|
||||||
$(call RUN_IDF_PY,size-files)
|
$(call RUN_IDF_PY,size-files)
|
||||||
|
|
||||||
|
# Running the build with ECHO_SUBMODULES set will trigger py/mkrules.cmake to
|
||||||
|
# print out the value of the GIT_SUBMODULES variable, prefixed with
|
||||||
|
# "GIT_SUBMODULES", and then abort. This extracts out that line from the idf.py
|
||||||
|
# output and passes the list of submodules to py/mkrules.mk which does the
|
||||||
|
# `git submodule init` on each.
|
||||||
submodules:
|
submodules:
|
||||||
$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules
|
@GIT_SUBMODULES=$$(idf.py $(IDFPY_FLAGS) -B $(BUILD)/submodules -D ECHO_SUBMODULES=1 build 2>&1 | \
|
||||||
|
grep '^GIT_SUBMODULES=' | cut -d= -f2); \
|
||||||
|
$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$${GIT_SUBMODULES}" submodules
|
||||||
|
|
|
@ -93,7 +93,7 @@ $ make submodules
|
||||||
$ make
|
$ make
|
||||||
```
|
```
|
||||||
|
|
||||||
This will produce a combined `firmware.bin` image in the `build-GENERIC/`
|
This will produce a combined `firmware.bin` image in the `build-ESP32_GENERIC/`
|
||||||
subdirectory (this firmware image is made up of: bootloader.bin, partitions.bin
|
subdirectory (this firmware image is made up of: bootloader.bin, partitions.bin
|
||||||
and micropython.bin).
|
and micropython.bin).
|
||||||
|
|
||||||
|
@ -123,12 +123,12 @@ To flash the MicroPython firmware to your ESP32 use:
|
||||||
$ make deploy
|
$ make deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
The default ESP32 board build by the above commands is the `GENERIC` one, which
|
The default ESP32 board build by the above commands is the `ESP32_GENERIC`
|
||||||
should work on most ESP32 modules. You can specify a different board by passing
|
one, which should work on most ESP32 modules. You can specify a different
|
||||||
`BOARD=<board>` to the make commands, for example:
|
board by passing `BOARD=<board>` to the make commands, for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ make BOARD=GENERIC_SPIRAM
|
$ make BOARD=ESP32_GENERIC_S3
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: the above "make" commands are thin wrappers for the underlying `idf.py`
|
Note: the above "make" commands are thin wrappers for the underlying `idf.py`
|
||||||
|
@ -137,10 +137,25 @@ for example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ idf.py build
|
$ idf.py build
|
||||||
$ idf.py -D MICROPY_BOARD=GENERIC_SPIRAM build
|
$ idf.py -D MICROPY_BOARD=ESP32_GENERIC build
|
||||||
$ idf.py flash
|
$ idf.py flash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Some boards also support "variants", which are allow for small variations of
|
||||||
|
an otherwise similar board. For example different flash sizes or features. For
|
||||||
|
example to build the `OTA` variant of `ESP32_GENERIC`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make BOARD=ESP32_GENERIC BOARD_VARIANT=OTA
|
||||||
|
```
|
||||||
|
|
||||||
|
or to enable octal-SPIRAM support for the `ESP32_GENERIC_S3` board:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ make BOARD=ESP32_GENERIC BOARD_VARIANT=SPIRAM_OCT
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Getting a Python prompt on the device
|
Getting a Python prompt on the device
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
@ -202,10 +217,10 @@ antenna = machine.Pin(16, machine.Pin.OUT, value=0)
|
||||||
Defining a custom ESP32 board
|
Defining a custom ESP32 board
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
The default ESP-IDF configuration settings are provided by the `GENERIC`
|
The default ESP-IDF configuration settings are provided by the `ESP32_GENERIC`
|
||||||
board definition in the directory `boards/GENERIC`. For a custom configuration
|
board definition in the directory `boards/ESP32_GENERIC`. For a custom configuration
|
||||||
you can define your own board directory. Start a new board configuration by
|
you can define your own board directory. Start a new board configuration by
|
||||||
copying an existing one (like `GENERIC`) and modifying it to suit your board.
|
copying an existing one (like `ESP32_GENERIC`) and modifying it to suit your board.
|
||||||
|
|
||||||
MicroPython specific configuration values are defined in the board-specific
|
MicroPython specific configuration values are defined in the board-specific
|
||||||
`mpconfigboard.h` file, which is included by `mpconfigport.h`. Additional
|
`mpconfigboard.h` file, which is included by `mpconfigport.h`. Additional
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
"docs": "",
|
"docs": "",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
"WiFi",
|
"External Flash",
|
||||||
|
"RGB LED",
|
||||||
"USB-C",
|
"USB-C",
|
||||||
"RGB LED"
|
"WiFi"
|
||||||
],
|
],
|
||||||
"images": [
|
"images": [
|
||||||
"ABX00092_01.iso_1000x750.jpg"
|
"ABX00092_01.iso_1000x750.jpg"
|
||||||
|
|
|
@ -4,5 +4,10 @@ This board can programmed via DFU bootloader, using e.g. [dfu-util](http://dfu-u
|
||||||
To enter the DFU bootloader, double tap the reset (blue) button, or you can use `machine.bootloader()` from the MicroPython REPL.
|
To enter the DFU bootloader, double tap the reset (blue) button, or you can use `machine.bootloader()` from the MicroPython REPL.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.bin
|
dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.app-bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Please note that the DFU bootloader comes factory flashed. Should you for any reason erase the
|
||||||
|
entire flash, the DFU bootloader will have to be re-installed. Please follow the instructions
|
||||||
|
[here](https://support.arduino.cc/hc/en-us/articles/9810414060188-Reset-the-Arduino-bootloader-on-the-Nano-ESP32)
|
||||||
|
to do so.
|
||||||
|
|
|
@ -5,18 +5,22 @@
|
||||||
"docs": "",
|
"docs": "",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
|
"External Flash",
|
||||||
"WiFi"
|
"WiFi"
|
||||||
],
|
],
|
||||||
"id": "esp32",
|
|
||||||
"images": [
|
"images": [
|
||||||
"esp32_devkitc.jpg"
|
"esp32_devkitc.jpg"
|
||||||
],
|
],
|
||||||
"mcu": "esp32",
|
"mcu": "esp32",
|
||||||
"product": "ESP32",
|
"product": "ESP32 / WROOM",
|
||||||
"thumbnail": "",
|
"thumbnail": "",
|
||||||
"url": "https://www.espressif.com/en/products/modules",
|
"url": "https://www.espressif.com/en/products/modules",
|
||||||
"variants": {
|
"variants": {
|
||||||
"idf3": "Compiled with IDF 3.x"
|
"IDF3": "Compiled with IDF 3.x",
|
||||||
|
"D2WD": "ESP32 D2WD",
|
||||||
|
"SPIRAM": "Support for SPIRAM / WROVER",
|
||||||
|
"UNICORE": "ESP32 Unicore",
|
||||||
|
"OTA": "Support for OTA"
|
||||||
},
|
},
|
||||||
"vendor": "Espressif"
|
"vendor": "Espressif"
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
The following files are firmware that should work on most ESP32-based boards
|
||||||
|
with 4MiB of flash, including WROOM WROVER, SOLO, PICO, and MINI modules.
|
||||||
|
|
||||||
|
If your board is based on a WROVER module, or otherwise has SPIRAM (also known
|
||||||
|
as PSRAM), then use the "spiram" variant.
|
||||||
|
|
||||||
|
The "d2wd" variant is for ESP32-D2WD chips (with 2MiB flash), and "unicore" is
|
||||||
|
for single-core ESP32 chips (e.g. the "SOLO" modules). The "ota" variant sets
|
||||||
|
up the partition table to allow for Over-the-Air updates.
|
|
@ -0,0 +1,48 @@
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.ble
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MICROPY_BOARD_VARIANT STREQUAL "D2WD")
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
${SDKCONFIG_DEFAULTS}
|
||||||
|
boards/ESP32_GENERIC/sdkconfig.d2wd
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND MICROPY_DEF_BOARD
|
||||||
|
MICROPY_HW_MCU_NAME="ESP32-D2WD"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MICROPY_BOARD_VARIANT STREQUAL "OTA")
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
${SDKCONFIG_DEFAULTS}
|
||||||
|
boards/ESP32_GENERIC/sdkconfig.ota
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND MICROPY_DEF_BOARD
|
||||||
|
MICROPY_HW_BOARD_NAME="Generic ESP32 module with OTA"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MICROPY_BOARD_VARIANT STREQUAL "SPIRAM")
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
${SDKCONFIG_DEFAULTS}
|
||||||
|
boards/sdkconfig.spiram
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND MICROPY_DEF_BOARD
|
||||||
|
MICROPY_HW_BOARD_NAME="Generic ESP32 module with SPIRAM"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MICROPY_BOARD_VARIANT STREQUAL "UNICORE")
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
${SDKCONFIG_DEFAULTS}
|
||||||
|
boards/ESP32_GENERIC/sdkconfig.unicore
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND MICROPY_DEF_BOARD
|
||||||
|
MICROPY_HW_MCU_NAME="ESP32-UNICORE"
|
||||||
|
)
|
||||||
|
endif()
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Both of these can be set by mpconfigboard.cmake if a BOARD_VARIANT is
|
||||||
|
// specified.
|
||||||
|
|
||||||
|
#ifndef MICROPY_HW_BOARD_NAME
|
||||||
|
#define MICROPY_HW_BOARD_NAME "Generic ESP32 module"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MICROPY_HW_MCU_NAME
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32"
|
||||||
|
#endif
|
|
@ -1,6 +1,6 @@
|
||||||
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-ota.csv"
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4MiB-ota.csv"
|
||||||
|
|
||||||
# Reduce firmware size to fit in the OTA partition.
|
# Reduce firmware size to fit in the OTA partition.
|
||||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
|
@ -5,9 +5,9 @@
|
||||||
"docs": "",
|
"docs": "",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
|
"External Flash",
|
||||||
"WiFi"
|
"WiFi"
|
||||||
],
|
],
|
||||||
"id": "esp32c3",
|
|
||||||
"images": [
|
"images": [
|
||||||
"esp32c3_devkitmini.jpg"
|
"esp32c3_devkitmini.jpg"
|
||||||
],
|
],
|
|
@ -0,0 +1,7 @@
|
||||||
|
The following files are firmware images that should work on most
|
||||||
|
ESP32-C3-based boards with 4MiB of flash, including WROOM and MINI modules,
|
||||||
|
that use the revision 3 silicon (or newer).
|
||||||
|
|
||||||
|
USB serial/JTAG support is enabled on pin 18 and 19. Note that this
|
||||||
|
is not a full USB stack, the C3 just provides a CDC/ACM class serial
|
||||||
|
and JTAG interface.
|
|
@ -3,4 +3,5 @@ set(IDF_TARGET esp32c3)
|
||||||
set(SDKCONFIG_DEFAULTS
|
set(SDKCONFIG_DEFAULTS
|
||||||
boards/sdkconfig.base
|
boards/sdkconfig.base
|
||||||
boards/sdkconfig.ble
|
boards/sdkconfig.ble
|
||||||
|
boards/ESP32_GENERIC_C3/sdkconfig.c3usb
|
||||||
)
|
)
|
|
@ -6,3 +6,6 @@
|
||||||
#define MICROPY_HW_ENABLE_SDCARD (0)
|
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||||
#define MICROPY_PY_MACHINE_DAC (0)
|
#define MICROPY_PY_MACHINE_DAC (0)
|
||||||
#define MICROPY_PY_MACHINE_I2S (0)
|
#define MICROPY_PY_MACHINE_I2S (0)
|
||||||
|
|
||||||
|
// Enable UART REPL for modules that have an external USB-UART and don't use native USB.
|
||||||
|
#define MICROPY_HW_ENABLE_UART_REPL (1)
|
|
@ -5,6 +5,8 @@
|
||||||
"docs": "",
|
"docs": "",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
|
"External Flash",
|
||||||
|
"External RAM",
|
||||||
"WiFi"
|
"WiFi"
|
||||||
],
|
],
|
||||||
"images": [
|
"images": [
|
|
@ -0,0 +1,6 @@
|
||||||
|
The following files are firmware that should work on most ESP32-S2-based
|
||||||
|
boards with 4MiB of flash, including WROOM, WROVER, and MINI modules.
|
||||||
|
|
||||||
|
This firmware supports configurations with and without SPIRAM (also known as
|
||||||
|
PSRAM) and will auto-detect a connected SPIRAM chip at startup and allocate
|
||||||
|
the MicroPython heap accordingly.
|
|
@ -3,4 +3,5 @@ set(IDF_TARGET esp32s2)
|
||||||
set(SDKCONFIG_DEFAULTS
|
set(SDKCONFIG_DEFAULTS
|
||||||
boards/sdkconfig.base
|
boards/sdkconfig.base
|
||||||
boards/sdkconfig.usb
|
boards/sdkconfig.usb
|
||||||
|
boards/sdkconfig.spiram_sx
|
||||||
)
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
#define MICROPY_HW_BOARD_NAME "Generic ESP32S2 module"
|
||||||
|
#define MICROPY_HW_MCU_NAME "ESP32S2"
|
||||||
|
|
||||||
|
#define MICROPY_PY_BLUETOOTH (0)
|
||||||
|
#define MICROPY_HW_ENABLE_SDCARD (0)
|
||||||
|
|
||||||
|
// Enable UART REPL for modules that have an external USB-UART and don't use native USB.
|
||||||
|
#define MICROPY_HW_ENABLE_UART_REPL (1)
|
|
@ -5,6 +5,8 @@
|
||||||
"docs": "",
|
"docs": "",
|
||||||
"features": [
|
"features": [
|
||||||
"BLE",
|
"BLE",
|
||||||
|
"External Flash",
|
||||||
|
"External RAM",
|
||||||
"WiFi"
|
"WiFi"
|
||||||
],
|
],
|
||||||
"images": [
|
"images": [
|
||||||
|
@ -14,5 +16,8 @@
|
||||||
"product": "ESP32-S3",
|
"product": "ESP32-S3",
|
||||||
"thumbnail": "",
|
"thumbnail": "",
|
||||||
"url": "https://www.espressif.com/en/products/modules",
|
"url": "https://www.espressif.com/en/products/modules",
|
||||||
"vendor": "Espressif"
|
"vendor": "Espressif",
|
||||||
|
"variants": {
|
||||||
|
"SPIRAM_OCT": "Support for Octal-SPIRAM"
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
The following files are firmware that should work on most ESP32-S3-based
|
||||||
|
boards with 8MiB of flash, including WROOM and MINI modules.
|
||||||
|
|
||||||
|
This firmware supports configurations with and without SPIRAM (also known as
|
||||||
|
PSRAM) and will auto-detect a connected SPIRAM chip at startup and allocate
|
||||||
|
the MicroPython heap accordingly. However if your board has Octal SPIRAM, then
|
||||||
|
use the "spiram-oct" variant.
|
|
@ -0,0 +1,21 @@
|
||||||
|
set(IDF_TARGET esp32s3)
|
||||||
|
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
boards/sdkconfig.base
|
||||||
|
boards/sdkconfig.usb
|
||||||
|
boards/sdkconfig.ble
|
||||||
|
boards/sdkconfig.spiram_sx
|
||||||
|
boards/ESP32_GENERIC_S3/sdkconfig.board
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MICROPY_BOARD_VARIANT STREQUAL "SPIRAM_OCT")
|
||||||
|
set(SDKCONFIG_DEFAULTS
|
||||||
|
${SDKCONFIG_DEFAULTS}
|
||||||
|
boards/sdkconfig.240mhz
|
||||||
|
boards/sdkconfig.spiram_oct
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND MICROPY_DEF_BOARD
|
||||||
|
MICROPY_HW_BOARD_NAME="Generic ESP32S3 module with Octal-SPIRAM"
|
||||||
|
)
|
||||||
|
endif()
|
|
@ -1,4 +1,7 @@
|
||||||
#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram)"
|
#ifndef MICROPY_HW_BOARD_NAME
|
||||||
|
// Can be set by mpconfigboard.cmake.
|
||||||
|
#define MICROPY_HW_BOARD_NAME "Generic ESP32S3 module"
|
||||||
|
#endif
|
||||||
#define MICROPY_HW_MCU_NAME "ESP32S3"
|
#define MICROPY_HW_MCU_NAME "ESP32S3"
|
||||||
|
|
||||||
#define MICROPY_PY_MACHINE_DAC (0)
|
#define MICROPY_PY_MACHINE_DAC (0)
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue