diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 0ffa4fcfd952..6f84de6f60ea 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +1,10 @@ -#all: Reformat remaining C code that doesn't have a space after a comma. +# all: Fix spelling mistakes based on codespell check. +b1229efbd1509654dec6053865ab828d769e29db + +# top: Update Python formatting to black "2023 stable style". +8b2748269244304854b3462cb8902952b4dcb892 + +# all: Reformat remaining C code that doesn't have a space after a comma. 5b700b0af90591d6b1a2c087bb8de6b7f1bfdd2d # ports: Reformat more C and Python source code. diff --git a/.github/ISSUE_TEMPLATE/security.md b/.github/ISSUE_TEMPLATE/security.md index 2bbfede6ce06..cfe4a4befdb1 100644 --- a/.github/ISSUE_TEMPLATE/security.md +++ b/.github/ISSUE_TEMPLATE/security.md @@ -1,6 +1,6 @@ --- name: Security report -about: Report a security issue or vunerability in MicroPython +about: Report a security issue or vulnerability in MicroPython title: '' labels: security assignees: '' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..2c7d1708395e --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/code_formatting.yml b/.github/workflows/code_formatting.yml index 5c0196d2edbf..81a2715f1b33 100644 --- a/.github/workflows/code_formatting.yml +++ b/.github/workflows/code_formatting.yml @@ -2,15 +2,29 @@ name: Check code formatting on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + code-formatting: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 - name: Install packages run: source tools/ci.sh && ci_code_formatting_setup - name: Run code formatting run: source tools/ci.sh && ci_code_formatting_run - name: Check code formatting run: git diff --exit-code + + code-spelling: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - name: Install packages + run: source tools/ci.sh && ci_code_spell_setup + - name: Run spell checker + run: source tools/ci.sh && ci_code_spell_run diff --git a/.github/workflows/code_size.yml b/.github/workflows/code_size.yml index 7570261e7d23..5d955703b666 100644 --- a/.github/workflows/code_size.yml +++ b/.github/workflows/code_size.yml @@ -12,11 +12,15 @@ on: - 'ports/bare-arm/**' - 'ports/minimal/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 100 - name: Install packages @@ -24,4 +28,18 @@ jobs: - name: Build run: source tools/ci.sh && ci_code_size_build - name: Compute code size difference - run: tools/metrics.py diff --error-threshold 0 ~/size0 ~/size1 + run: tools/metrics.py diff ~/size0 ~/size1 | tee diff + - name: Save PR number + if: github.event_name == 'pull_request' + env: + PR_NUMBER: ${{ github.event.number }} + run: echo $PR_NUMBER > pr_number + - name: Upload diff + if: github.event_name == 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: code-size-report + path: | + diff + pr_number + retention-days: 1 diff --git a/.github/workflows/code_size_comment.yml b/.github/workflows/code_size_comment.yml new file mode 100644 index 000000000000..8baf76a47a7f --- /dev/null +++ b/.github/workflows/code_size_comment.yml @@ -0,0 +1,105 @@ +name: Code size comment + +on: + workflow_run: + workflows: [Check code size] + types: [completed] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + comment: + runs-on: ubuntu-20.04 + steps: + - name: 'Download artifact' + id: download-artifact + uses: actions/github-script@v6 + with: + result-encoding: string + script: | + const fs = require('fs'); + + const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + + const matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "code-size-report" + }); + + if (matchArtifact.length === 0) { + console.log('no matching artifact found'); + console.log('result: "skip"'); + + return 'skip'; + } + + const download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact[0].id, + archive_format: 'zip', + }); + + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/code-size-report.zip`, Buffer.from(download.data)); + + console.log('artifact downloaded to `code-size-report.zip`'); + console.log('result: "ok"'); + + return 'ok'; + - name: 'Unzip artifact' + if: steps.download-artifact.outputs.result == 'ok' + run: unzip code-size-report.zip + - name: Post comment to pull request + if: steps.download-artifact.outputs.result == 'ok' + uses: actions/github-script@v6 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const fs = require('fs'); + + const prNumber = Number(fs.readFileSync('pr_number')); + const codeSizeReport = `Code size report: + + \`\`\` + ${fs.readFileSync('diff')} + \`\`\` + `; + + const comments = await github.paginate( + github.rest.issues.listComments, + { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + } + ); + + comments.reverse(); + + const previousComment = comments.find(comment => + comment.user.login === 'github-actions[bot]' + ) + + // if github-actions[bot] already made a comment, update it, + // otherwise create a new comment. + + if (previousComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: previousComment.id, + body: codeSizeReport, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body: codeSizeReport, + }); + } diff --git a/.github/workflows/commit_formatting.yml b/.github/workflows/commit_formatting.yml index 5f96fbb93442..0b27038f2d26 100644 --- a/.github/workflows/commit_formatting.yml +++ b/.github/workflows/commit_formatting.yml @@ -2,13 +2,17 @@ name: Check commit message formatting on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: '100' - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 - name: Check commit message formatting run: source tools/ci.sh && ci_commit_formatting_run diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ec6b4c7f1962..e9b17007476c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -5,13 +5,17 @@ on: paths: - docs/** +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 - name: Install Python packages run: pip install Sphinx - name: Build docs diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 53a817af2b31..450805a6bde4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -10,12 +10,16 @@ on: - 'py/**' - 'shared/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: embedding: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build - run: make -C examples/embedding + run: make -C examples/embedding -f micropython_embed.mk && make -C examples/embedding - name: Run - run: test "$(./examples/embedding/hello-embed)" = "Hello world of easy embedding!" + run: ./examples/embedding/embed | grep "hello world" diff --git a/.github/workflows/mpremote.yml b/.github/workflows/mpremote.yml new file mode 100644 index 000000000000..14aef03e0773 --- /dev/null +++ b/.github/workflows/mpremote.yml @@ -0,0 +1,29 @@ +name: Package mpremote + +on: + push: + pull_request: + paths: + - '.github/workflows/*.yml' + - 'tools/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + # Setting this to zero means fetch all history and tags, + # which hatch-vcs can use to discover the version tag. + fetch-depth: 0 + - uses: actions/setup-python@v4 + - name: Install build tools + run: pip install build + - name: Build mpremote wheel + run: cd tools/mpremote && python -m build --wheel + - name: Archive mpremote wheel + uses: actions/upload-artifact@v3 + with: + name: mpremote + path: | + tools/mpremote/dist/mpremote*.whl diff --git a/.github/workflows/mpy_format.yml b/.github/workflows/mpy_format.yml index ab90bb339aa1..66abb19b81a4 100644 --- a/.github/workflows/mpy_format.yml +++ b/.github/workflows/mpy_format.yml @@ -5,13 +5,19 @@ on: pull_request: paths: - '.github/workflows/*.yml' + - 'examples/**' + - 'tests/**' - 'tools/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 # use 20.04 to get python2 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_mpy_format_setup - name: Test mpy-tool.py diff --git a/.github/workflows/ports.yml b/.github/workflows/ports.yml index e9e6de284cfa..fb574ad98190 100644 --- a/.github/workflows/ports.yml +++ b/.github/workflows/ports.yml @@ -8,11 +8,15 @@ on: - 'tools/**' - ports/** +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build ports download metadata run: mkdir boards && ./tools/autobuild/build-downloads.py . ./boards diff --git a/.github/workflows/ports_cc3200.yml b/.github/workflows/ports_cc3200.yml index 0eaa36da3796..b58bc24b58b0 100644 --- a/.github/workflows/ports_cc3200.yml +++ b/.github/workflows/ports_cc3200.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/cc3200/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_cc3200_setup - name: Build diff --git a/.github/workflows/ports_esp32.yml b/.github/workflows/ports_esp32.yml index de88de375542..2cc9f592bf23 100644 --- a/.github/workflows/ports_esp32.yml +++ b/.github/workflows/ports_esp32.yml @@ -8,25 +8,21 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/esp32/**' -jobs: - build_idf402: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - name: Install packages - run: source tools/ci.sh && ci_esp32_idf402_setup - - name: Build - run: source tools/ci.sh && ci_esp32_build +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true - build_idf44: +jobs: + build_idf50: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages - run: source tools/ci.sh && ci_esp32_idf44_setup + run: source tools/ci.sh && ci_esp32_idf50_setup - name: Build run: source tools/ci.sh && ci_esp32_build diff --git a/.github/workflows/ports_esp8266.yml b/.github/workflows/ports_esp8266.yml index f4ce1f8212d8..ba89d5e9529e 100644 --- a/.github/workflows/ports_esp8266.yml +++ b/.github/workflows/ports_esp8266.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/esp8266/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH - name: Build diff --git a/.github/workflows/ports_mimxrt.yml b/.github/workflows/ports_mimxrt.yml index 8fbc2209e413..d91562534188 100644 --- a/.github/workflows/ports_mimxrt.yml +++ b/.github/workflows/ports_mimxrt.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/mimxrt/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_mimxrt_setup - name: Build diff --git a/.github/workflows/ports_nrf.yml b/.github/workflows/ports_nrf.yml index 1ba3b0ce61e9..89211217800b 100644 --- a/.github/workflows/ports_nrf.yml +++ b/.github/workflows/ports_nrf.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/nrf/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_nrf_setup - name: Build diff --git a/.github/workflows/ports_powerpc.yml b/.github/workflows/ports_powerpc.yml index 88fa59767b75..a15c4da97fa6 100644 --- a/.github/workflows/ports_powerpc.yml +++ b/.github/workflows/ports_powerpc.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/powerpc/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_powerpc_setup - name: Build diff --git a/.github/workflows/ports_qemu-arm.yml b/.github/workflows/ports_qemu-arm.yml index 0489a93d5ad1..93ec4da76700 100644 --- a/.github/workflows/ports_qemu-arm.yml +++ b/.github/workflows/ports_qemu-arm.yml @@ -8,16 +8,21 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/qemu-arm/**' - 'tests/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build_and_test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_qemu_arm_setup - name: Build and run test suite diff --git a/.github/workflows/ports_renesas-ra.yml b/.github/workflows/ports_renesas-ra.yml index 20e068ee75d7..33e17a385a1e 100644 --- a/.github/workflows/ports_renesas-ra.yml +++ b/.github/workflows/ports_renesas-ra.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/renesas-ra/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build_renesas_ra_board: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_renesas_ra_setup - name: Build diff --git a/.github/workflows/ports_rp2.yml b/.github/workflows/ports_rp2.yml index 668b79cae256..f042ff1151ab 100644 --- a/.github/workflows/ports_rp2.yml +++ b/.github/workflows/ports_rp2.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/rp2/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_rp2_setup - name: Build diff --git a/.github/workflows/ports_samd.yml b/.github/workflows/ports_samd.yml index bde4ed965faa..9833a2fae2ef 100644 --- a/.github/workflows/ports_samd.yml +++ b/.github/workflows/ports_samd.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/samd/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_samd_setup - name: Build diff --git a/.github/workflows/ports_stm32.yml b/.github/workflows/ports_stm32.yml index 4634339c96a6..b278ea862ce6 100644 --- a/.github/workflows/ports_stm32.yml +++ b/.github/workflows/ports_stm32.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/stm32/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build_pyb: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_stm32_setup - name: Build @@ -25,7 +30,7 @@ jobs: build_nucleo: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_stm32_setup - name: Build diff --git a/.github/workflows/ports_teensy.yml b/.github/workflows/ports_teensy.yml index 7ae77c80af60..f1299603259a 100644 --- a/.github/workflows/ports_teensy.yml +++ b/.github/workflows/ports_teensy.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'drivers/**' - 'ports/teensy/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_teensy_setup - name: Build diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index 3b738634a67f..87c58055b988 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -8,16 +8,22 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'examples/**' + - 'mpy-cross/**' - 'ports/unix/**' - 'tests/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: minimal: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: source tools/ci.sh && ci_unix_minimal_build - name: Run main test suite @@ -29,7 +35,7 @@ jobs: reproducible: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build with reproducible date run: source tools/ci.sh && ci_unix_minimal_build env: @@ -40,7 +46,7 @@ jobs: standard: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: source tools/ci.sh && ci_unix_standard_build - name: Run main test suite @@ -52,7 +58,7 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_coverage_setup - name: Build @@ -70,7 +76,7 @@ jobs: (cd ports/unix && gcov -o build-coverage/py ../../py/*.c || true) (cd ports/unix && gcov -o build-coverage/extmod ../../extmod/*.c || true) - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: fail_ci_if_error: true verbose: true @@ -79,9 +85,9 @@ jobs: run: tests/run-tests.py --print-failures coverage_32bit: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 # use 20.04 to get libffi-dev:i386 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -97,9 +103,9 @@ jobs: run: tests/run-tests.py --print-failures nanbox: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 # use 20.04 to get python2, and libffi-dev:i386 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_32bit_setup - name: Build @@ -113,7 +119,7 @@ jobs: float: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: source tools/ci.sh && ci_unix_float_build - name: Run main test suite @@ -125,7 +131,7 @@ jobs: stackless_clang: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -139,7 +145,7 @@ jobs: float_clang: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_clang_setup - name: Build @@ -153,7 +159,7 @@ jobs: settrace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: source tools/ci.sh && ci_unix_settrace_build - name: Run main test suite @@ -165,7 +171,7 @@ jobs: settrace_stackless: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: source tools/ci.sh && ci_unix_settrace_stackless_build - name: Run main test suite @@ -177,8 +183,8 @@ jobs: macos: runs-on: macos-11.0 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 with: python-version: '3.8' - name: Build @@ -192,7 +198,7 @@ jobs: qemu_mips: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_mips_setup - name: Build @@ -206,7 +212,7 @@ jobs: qemu_arm: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_unix_qemu_arm_setup - name: Build diff --git a/.github/workflows/ports_webassembly.yml b/.github/workflows/ports_webassembly.yml index 861039c0fcff..2e0865662f06 100644 --- a/.github/workflows/ports_webassembly.yml +++ b/.github/workflows/ports_webassembly.yml @@ -8,17 +8,25 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'ports/webassembly/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_webassembly_setup - name: Build run: source tools/ci.sh && ci_webassembly_build - name: Run tests run: source tools/ci.sh && ci_webassembly_run_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures diff --git a/.github/workflows/ports_windows.yml b/.github/workflows/ports_windows.yml index 1bfe40c7fded..b31718c59140 100644 --- a/.github/workflows/ports_windows.yml +++ b/.github/workflows/ports_windows.yml @@ -8,15 +8,20 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'ports/unix/**' - 'ports/windows/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_windows_setup - name: Build diff --git a/.github/workflows/ports_zephyr.yml b/.github/workflows/ports_zephyr.yml index d9ae2b8c55a2..f64401b316a5 100644 --- a/.github/workflows/ports_zephyr.yml +++ b/.github/workflows/ports_zephyr.yml @@ -8,14 +8,19 @@ on: - 'tools/**' - 'py/**' - 'extmod/**' + - 'shared/**' - 'lib/**' - 'ports/zephyr/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: source tools/ci.sh && ci_zephyr_setup - name: Install Zephyr diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 000000000000..b8e43dc78f17 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,10 @@ +# https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python +name: Python code lint with ruff +on: [push, pull_request] +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: pip install --user ruff + - run: ruff --format=github . diff --git a/.gitignore b/.gitignore index 734248992788..2d20cb18970e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,48 +1,25 @@ -# Compiled Sources -################### -*.o -*.a -*.elf -*.bin -*.map -*.hex -*.dis -*.exe - -# Packages -############ - -# Logs and Databases -###################### -*.log - -# VIM Swap Files -###################### -*.swp +# This .gitignore file is intended to be minimal. +# +# If you find that you need additional rules, such as IDE temporary +# files, please do so either via a global .gitignore file (registered +# with core.excludesFile), or by adding private repository-specific +# rules to .git/info/exclude. See https://git-scm.com/docs/gitignore +# for more information. # Build directories -###################### build/ build-*/ +docs/genrst/ # Test failure outputs -###################### tests/results/* # Python cache files -###################### __pycache__/ -*.pyc # Customized Makefile/project overrides -###################### GNUmakefile user.props -# Generated rst files -###################### -genrst/ - # MacOS desktop metadata files -###################### .DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 12f3d79c9353..e9815a4b2e64 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,3 +11,7 @@ repos: language: python verbose: true stages: [commit-msg] + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.0.265 + hooks: + - id: ruff diff --git a/CODECONVENTIONS.md b/CODECONVENTIONS.md index 53b202ea371e..d44b382b25ea 100644 --- a/CODECONVENTIONS.md +++ b/CODECONVENTIONS.md @@ -11,7 +11,7 @@ It's also ok to drop file extensions. Besides prefix, first line of a commit message should describe a change clearly and to the point, and be a grammatical sentence with -final full stop. First line should fit within 72 characters. Examples +final full stop. First line must fit within 72 characters. Examples of good first line of commit messages: py/objstr: Add splitlines() method. @@ -27,12 +27,9 @@ change beyond 5 lines would likely require such detailed description. To get good practical examples of good commits and their messages, browse the `git log` of the project. -When committing you are encouraged to sign-off your commit by adding -"Signed-off-by" lines and similar, eg using "git commit -s". If you don't -explicitly sign-off in this way then the commit message, which includes your -name and email address in the "Author" line, implies your sign-off. In either -case, of explicit or implicit sign-off, you are certifying and signing off -against the following: +When committing you must sign-off your commit by adding "Signed-off-by:" +line(s) at the end of the commit message, e.g. using `git commit -s`. You +are then certifying and signing off against the following: * That you wrote the change yourself, or took it from a project with a compatible license (in the latter case the commit message, and possibly @@ -49,10 +46,9 @@ against the following: * Your contribution including commit message will be publicly and indefinitely available for anyone to access, including redistribution under the terms of the project's license. -* Your signature for all of the above, which is the "Signed-off-by" line - or the "Author" line in the commit message, includes your full real name and - a valid and active email address by which you can be contacted in the - foreseeable future. +* Your signature for all of the above, which is the "Signed-off-by" line, + includes your full real name and a valid and active email address by + which you can be contacted in the foreseeable future. Code auto-formatting ==================== @@ -65,16 +61,52 @@ changes to the correct style. Without arguments this tool will reformat all source code (and may take some time to run). Otherwise pass as arguments to the tool the files that changed and it will only reformat those. -**Important**: Use only [uncrustify](https://github.com/uncrustify/uncrustify) -v0.71 or v0.72 for MicroPython. Different uncrustify versions produce slightly -different formatting, and the configuration file formats are often incompatible. +uncrustify +========== + +Only [uncrustify](https://github.com/uncrustify/uncrustify) v0.71 or v0.72 can +be used for MicroPython. Different uncrustify versions produce slightly +different formatting, and the configuration file formats are often +incompatible. v0.73 or newer *will not work*. + +Depending on your operating system version, it may be possible to install a pre-compiled +uncrustify version: + +Ubuntu, Debian +-------------- + +Ubuntu versions 21.10 or 22.04LTS, and Debian versions bullseye or bookworm all +include v0.72 so can be installed directly: + +``` +$ apt install uncrustify +``` + +Arch Linux +---------- + +The current Arch uncrustify version is too new. There is an [old Arch package +for v0.72](https://archive.archlinux.org/packages/u/uncrustify/) that can be +installed from the Arch Linux archive ([more +information](https://wiki.archlinux.org/title/Downgrading_packages#Arch_Linux_Archive)). Use +the [IgnorePkg feature](https://wiki.archlinux.org/title/Pacman#Skip_package_from_being_upgraded) +to prevent it re-updating. + +Brew +---- + +This command may work, please raise a new Issue if it doesn't: + +``` +curl -L https://github.com/Homebrew/homebrew-core/raw/2b07d8192623365078a8b855a164ebcdf81494a6/Formula/uncrustify.rb > uncrustify.rb && brew install uncrustify.rb && rm uncrustify.rb +``` Automatic Pre-Commit Hooks ========================== To have code formatting and commit message conventions automatically checked, -a configuration file is provided for the [pre-commit] -(https://pre-commit.com/) tool. +a configuration file is provided for the [pre-commit](https://pre-commit.com/) +tool. First install `pre-commit`, either from your system package manager or via `pip`. When installing `pre-commit` via pip, it is recommended to use a @@ -82,13 +114,17 @@ virtual environment. Other sources, such as Brew are also available, see [the docs](https://pre-commit.com/index.html#install) for details. ``` -$ apt install pre-commit # Ubuntu +$ apt install pre-commit # Ubuntu, Debian $ pacman -Sy python-precommit # Arch Linux $ brew install pre-commit # Brew $ pip install pre-commit # PyPI ``` -Then inside the MicroPython repository, register the git hooks for pre-commit +Next, install [uncrustify (see above)](#uncrustify). Other dependencies are managed by +pre-commit automatically, but uncrustify needs to be installed and available on +the PATH. + +Then, inside the MicroPython repository, register the git hooks for pre-commit by running: ``` @@ -115,7 +151,6 @@ Tips: * To ignore the pre-commit message format check temporarily, start the commit message subject line with "WIP" (for "Work In Progress"). - Python code conventions ======================= @@ -216,7 +251,7 @@ Documentation conventions ========================= MicroPython generally follows CPython in documentation process and -conventions. reStructuredText syntax is used for the documention. +conventions. reStructuredText syntax is used for the documentation. Specific conventions/suggestions: diff --git a/LICENSE b/LICENSE index 5a91df195fd4..07c88b0a0323 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2022 Damien P. George +Copyright (c) 2013-2023 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,6 @@ used during the build process and is not part of the compiled source code. / (MIT) /drivers /cc3100 (BSD-3-clause) - /wiznet5k (BSD-3-clause) /lib /asf4 (Apache-2.0) /axtls (BSD-3-clause) @@ -61,12 +60,15 @@ used during the build process and is not part of the compiled source code. /tinytest (BSD-3-clause) /tinyusb (MIT) /uzlib (Zlib) + /wiznet5k (MIT) /logo (uses OFL-1.1) /ports /cc3200 /hal (BSD-3-clause) /simplelink (BSD-3-clause) /FreeRTOS (GPL-2.0 with FreeRTOS exception) + /esp32 + /ppp_set_auth.* (Apache-2.0) /stm32 /usbd*.c (MCD-ST Liberty SW License Agreement V2) /stm32_it.* (MIT + BSD-3-clause) diff --git a/docs/conf.py b/docs/conf.py index 5533bf01918a..a966b3a02570 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,6 +33,7 @@ 'downloads':[ ('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'), ], + 'is_release': micropy_version != 'latest', } @@ -66,7 +67,7 @@ # General information about the project. project = 'MicroPython' -copyright = '- The MicroPython Documentation is Copyright © 2014-2022, Damien P. George, Paul Sokolovsky, and contributors' +copyright = '- The MicroPython Documentation is Copyright © 2014-2023, Damien P. George, Paul Sokolovsky, and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -74,7 +75,7 @@ # # We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags" # breakdown, so use the same version identifier for both to avoid confusion. -version = release = '1.19.1' +version = release = micropy_version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -232,7 +233,7 @@ # Additional stuff for the LaTeX preamble. #'preamble': '', # Include 3 levels of headers in PDF ToC -'preamble': '\setcounter{tocdepth}{2}', +'preamble': r'\setcounter{tocdepth}{2}', } # Grouping the document tree into LaTeX files. List of tuples diff --git a/docs/develop/cmodules.rst b/docs/develop/cmodules.rst index 1b3ba04da4af..75dbc953c06f 100644 --- a/docs/develop/cmodules.rst +++ b/docs/develop/cmodules.rst @@ -53,7 +53,7 @@ A MicroPython user C module is a directory with the following files: ``SRC_USERMOD_C`` or ``SRC_USERMOD_LIB_C`` variables. The former will be processed for ``MP_QSTR_`` and ``MP_REGISTER_MODULE`` definitions, the latter will not (e.g. helpers and library code that isn't MicroPython-specific). - These paths should include your expaned copy of ``$(USERMOD_DIR)``, e.g.:: + These paths should include your expanded copy of ``$(USERMOD_DIR)``, e.g.:: SRC_USERMOD_C += $(EXAMPLE_MOD_DIR)/modexample.c SRC_USERMOD_LIB_C += $(EXAMPLE_MOD_DIR)/utils/algorithm.c @@ -95,9 +95,12 @@ A MicroPython user C module is a directory with the following files: Basic example ------------- -This simple module named ``cexample`` provides a single function -``cexample.add_ints(a, b)`` which adds the two integer args together and returns -the result. It can be found in the MicroPython source tree +The ``cexample`` module provides examples for a function and a class. The +``cexample.add_ints(a, b)`` function adds two integer args together and returns +the result. The ``cexample.Timer()`` type creates timers that can be used to +measure the elapsed time since the object is instantiated. + +The module can be found in the MicroPython source tree `in the examples directory `_ and has a source file and a Makefile fragment with content as described above:: @@ -272,3 +275,13 @@ can now be accessed in Python just like any other builtin module, e.g. import cexample print(cexample.add_ints(1, 3)) # should display 4 + +.. code-block:: python + + from cexample import Timer + from time import sleep_ms + + watch = Timer() + sleep_ms(1000) + print(watch.time()) + # should display approximately 1000 diff --git a/docs/develop/compiler.rst b/docs/develop/compiler.rst index 2007657490f5..cac92585ff4e 100644 --- a/docs/develop/compiler.rst +++ b/docs/develop/compiler.rst @@ -147,10 +147,17 @@ The most relevant method you should know about is this: .. code-block:: c mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) { + // Create a context for this module, and set its globals dict. + mp_module_context_t *context = m_new_obj(mp_module_context_t); + context->module.globals = mp_globals_get(); + // Compile the input parse_tree to a raw-code structure. - mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl); + mp_compiled_module_t cm; + cm.context = context; + mp_compile_to_raw_code(parse_tree, source_file, is_repl, &cm); + // Create and return a function object that executes the outer module. - return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); + return mp_make_function_from_raw_code(cm.rc, cm.context, NULL); } The compiler compiles the code in four passes: scope, stack size, code size and emit. diff --git a/docs/develop/porting.rst b/docs/develop/porting.rst index 74974a39e1b4..63919b97a6cc 100644 --- a/docs/develop/porting.rst +++ b/docs/develop/porting.rst @@ -38,6 +38,7 @@ The basic MicroPython firmware is implemented in the main port file, e.g ``main. .. code-block:: c + #include "py/builtin.h" #include "py/compile.h" #include "py/gc.h" #include "py/mperrno.h" @@ -110,6 +111,9 @@ We also need a Makefile at this point for the port: shared/runtime/pyexec.c \ shared/runtime/stdout_helpers.c \ + # Define source files containung qstrs. + SRC_QSTR += shared/readline/readline.c shared/runtime/pyexec.c + # Define the required object files. OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -147,9 +151,6 @@ The following is an example of an ``mpconfigport.h`` file: #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) - // Enable u-modules to be imported with their standard name, like sys. - #define MICROPY_MODULE_WEAK_LINKS (1) - // Fine control over Python builtins, classes, modules, etc. #define MICROPY_PY_ASYNC_AWAIT (0) #define MICROPY_PY_BUILTINS_SET (0) diff --git a/docs/differences/index_template.txt b/docs/differences/index_template.txt index dbbd7fc099a2..1bbfbfedce92 100644 --- a/docs/differences/index_template.txt +++ b/docs/differences/index_template.txt @@ -13,6 +13,7 @@ above. The sections below describe the current status of these features. ../differences/python_37.rst ../differences/python_38.rst ../differences/python_39.rst + ../differences/python_310.rst For the features of Python that are implemented by MicroPython, there are sometimes differences in their behaviour compared to standard Python. The diff --git a/docs/differences/python_310.rst b/docs/differences/python_310.rst new file mode 100644 index 000000000000..f9d92db65537 --- /dev/null +++ b/docs/differences/python_310.rst @@ -0,0 +1,238 @@ +.. _python_310: + +Python 3.10 +=========== + +Python 3.10.0 (final) was released on the 4 October 2021. The Features for 3.10 are +defined in `PEP 619 `_ +and a detailed description of the changes can be found in +`What's New in Python 3.10 `_. + +.. table:: + :widths: 20 60 20 + + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **New syntax features** | **Status** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 634 `_ | Structural Pattern Matching: Specification | [#spm]_ | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 635 `_ | Structural Pattern Matching: Motivation and | [#spm]_ | + | | Rationale | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 636 `_ | Structural Pattern Matching: Tutorial | [#spm]_ | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `bpo-12782 | Parenthesized context managers are now officially | | + | `_ | allowed | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **New features in the standard library** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 618 `_ | Add Optional Length-Checking To zip | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **Interpreter improvements** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 626 `_ | Precise line numbers for debugging and other tools | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **New typing features** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 604 `_ | Allow writing union types as X | Y | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 613 `_ | Explicit Type Aliases | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 612 `_ | Parameter Specification Variables | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | **Important deprecations, removals or restrictions** | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 644 `_ | Require OpenSSL 1.1.1 or newer | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 632 `_ | Deprecate distutils module. | Not relevant | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 623 `_ | Deprecate and prepare for the removal of the wstr | Not relevant | + | | member in PyUnicodeObject. | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 624 `_ | Remove Py_UNICODE encoder APIs | Not relevant | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + | `PEP 597 `_ | Add optional EncodingWarning | | + +--------------------------------------------------------+----------------------------------------------------+--------------+ + + +Other Language Changes: + +.. table:: + :widths: 90 10 + + +-------------------------------------------------------------------------------------------------------------+---------------+ + | The :class:`int` type has a new method :meth:`int.bit_count`, returning the | | + | number of ones in the binary expansion of a given integer, also known | | + | as the population count. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | The views returned by :meth:`dict.keys`, :meth:`dict.values` and | | + | :meth:`dict.items` now all have a ``mapping`` attribute that gives a | | + | :class:`types.MappingProxyType` object wrapping the original | | + | dictionary. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | :pep:`618`: The :func:`zip` function now has an optional ``strict`` flag, used | | + | to require that all the iterables have an equal length. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Builtin and extension functions that take integer arguments no longer accept | | + | :class:`~decimal.Decimal`\ s, :class:`~fractions.Fraction`\ s and other | | + | objects that can be converted to integers only with a loss (e.g. that have | | + | the :meth:`~object.__int__` method but do not have the | | + | :meth:`~object.__index__` method). | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | If :func:`object.__ipow__` returns :const:`NotImplemented`, the operator will | | + | correctly fall back to :func:`object.__pow__` and :func:`object.__rpow__` as expected. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Assignment expressions can now be used unparenthesized within set literals | | + | and set comprehensions, as well as in sequence indexes (but not slices). | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Functions have a new ``__builtins__`` attribute which is used to look for | | + | builtin symbols when a function is executed, instead of looking into | | + | ``__globals__['__builtins__']``. The attribute is initialized from | | + | ``__globals__["__builtins__"]`` if it exists, else from the current builtins. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Two new builtin functions -- :func:`aiter` and :func:`anext` have been added | | + | to provide asynchronous counterparts to :func:`iter` and :func:`next`, | | + | respectively. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Static methods (:func:`@staticmethod `) and class methods | | + | (:func:`@classmethod `) now inherit the method attributes | | + | (``__module__``, ``__name__``, ``__qualname__``, ``__doc__``, | | + | ``__annotations__``) and have a new ``__wrapped__`` attribute. | | + | Moreover, static methods are now callable as regular functions. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Annotations for complex targets (everything beside ``simple name`` targets | | + | defined by :pep:`526`) no longer cause any runtime effects with ``from __future__ import annotations``. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Class and module objects now lazy-create empty annotations dicts on demand. | | + | The annotations dicts are stored in the object’s ``__dict__`` for | | + | backwards compatibility. This improves the best practices for working | | + | with ``__annotations__``. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Annotations consist of ``yield``, ``yield from``, ``await`` or named expressions | | + | are now forbidden under ``from __future__ import annotations`` due to their side | | + | effects. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Usage of unbound variables, ``super()`` and other expressions that might | | + | alter the processing of symbol table as annotations are now rendered | | + | effectless under ``from __future__ import annotations``. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | Hashes of NaN values of both :class:`float` type and | | + | :class:`decimal.Decimal` type now depend on object identity. Formerly, they | | + | always hashed to ``0`` even though NaN values are not equal to one another. | | + | This caused potentially quadratic runtime behavior due to excessive hash | | + | collisions when creating dictionaries and sets containing multiple NaNs. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | A :exc:`SyntaxError` (instead of a :exc:`NameError`) will be raised when deleting | | + | the :const:`__debug__` constant. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + | :exc:`SyntaxError` exceptions now have ``end_lineno`` and | | + | ``end_offset`` attributes. They will be ``None`` if not determined. | | + +-------------------------------------------------------------------------------------------------------------+---------------+ + +Changes to built-in modules: + +.. table:: + :widths: 90 10 + + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `asyncio `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add missing :meth:`~asyncio.events.AbstractEventLoop.connect_accepted_socket` | | + | method. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `array `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The :meth:`~array.array.index` method of :class:`array.array` now has | | + | optional *start* and *stop* parameters. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `gc `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add audit hooks for :func:`gc.get_objects`, :func:`gc.get_referrers` and | | + | :func:`gc.get_referents`. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `hashlib `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The hashlib module requires OpenSSL 1.1.1 or newer. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The hashlib module has preliminary support for OpenSSL 3.0.0. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The pure-Python fallback of :func:`~hashlib.pbkdf2_hmac` is deprecated. In | | + | the future PBKDF2-HMAC will only be available when Python has been built with | | + | OpenSSL support. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `os `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :func:`os.cpu_count()` support for VxWorks RTOS. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add a new function :func:`os.eventfd` and related helpers to wrap the | | + | ``eventfd2`` syscall on Linux. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :func:`os.splice()` that allows to move data between two file | | + | descriptors without copying between kernel address space and user | | + | address space, where one of the file descriptors must refer to a | | + | pipe. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :data:`~os.O_EVTONLY`, :data:`~os.O_FSYNC`, :data:`~os.O_SYMLINK` | | + | and :data:`~os.O_NOFOLLOW_ANY` for macOS. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `platform `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :func:`platform.freedesktop_os_release()` to retrieve operation system | | + | identification from `freedesktop.org os-release | | + | `_ standard file. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `socket `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The exception :exc:`socket.timeout` is now an alias of :exc:`TimeoutError`. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add option to create MPTCP sockets with ``IPPROTO_MPTCP``. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add ``IP_RECVTOS`` option to receive the type of service (ToS) or DSCP/ECN fields. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `ssl `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The ssl module requires OpenSSL 1.1.1 or newer. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The ssl module has preliminary support for OpenSSL 3.0.0 and new option | | + | :data:`~ssl.OP_IGNORE_UNEXPECTED_EOF`. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Deprecated function and use of deprecated constants now result in | | + | a :exc:`DeprecationWarning`. :attr:`ssl.SSLContext.options` has | | + | :data:`~ssl.OP_NO_SSLv2` and :data:`~ssl.OP_NO_SSLv3` set by default and | | + | therefore cannot warn about setting the flag again. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The ssl module now has more secure default settings. Ciphers without forward | | + | secrecy or SHA-1 MAC are disabled by default. Security level 2 prohibits | | + | weak RSA, DH, and ECC keys with less than 112 bits of security. | | + | :class:`~ssl.SSLContext` defaults to minimum protocol version TLS 1.2. | | + | Settings are based on Hynek Schlawack's research. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The deprecated protocols SSL 3.0, TLS 1.0, and TLS 1.1 are no longer | | + | officially supported. Python does not block them actively. However | | + | OpenSSL build options, distro configurations, vendor patches, and cipher | | + | suites may prevent a successful handshake. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add a *timeout* parameter to the :func:`ssl.get_server_certificate` function. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | The ssl module uses heap-types and multi-phase initialization. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | A new verify flag :data:`~ssl.VERIFY_X509_PARTIAL_CHAIN` has been added. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `sys `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :data:`sys.orig_argv` attribute: the list of the original command line | | + | arguments passed to the Python executable. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | Add :data:`sys.stdlib_module_names`, containing the list of the standard library | | + | module names. | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | `_thread `_ | + +---------------------------------------------------------------------------------------------------------------+---------------+ + | :func:`_thread.interrupt_main` now takes an optional signal number to | | + | simulate (the default is still :data:`signal.SIGINT`). | | + +---------------------------------------------------------------------------------------------------------------+---------------+ + +.. rubric:: Notes + +.. [#spm] The structural pattern matching feature is discussed in `issue #7847 `_. + diff --git a/docs/differences/python_39.rst b/docs/differences/python_39.rst index 023c6d7c1e39..f68abc50740a 100644 --- a/docs/differences/python_39.rst +++ b/docs/differences/python_39.rst @@ -11,30 +11,30 @@ and a detailed description of the changes can be found in .. table:: :widths: 20 60 20 - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | **Features** | | **Status** | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 573 `_ | Fast access to module state from methods of C | | - | | extension types | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 584 `_ | Union operators added to dict | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 585 `_ | Type hinting generics in standard collections | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 593 `_ | Flexible function and variable annotations | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 602 `_ | CPython adopts an annual release cycle. Instead of | | - | | annual, aiming for two month release cycle | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 614 `_ | Relaxed grammar restrictions on decorators | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 615 `_ | The IANA Time Zone Database is now present in the | | - | | standard library in the zoneinfo module | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 616 `_ | String methods to remove prefixes and suffixes | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ - | `PEP 617 `_ | CPython now uses a new parser based on PEG | | - +--------------------------------------------------------+----------------------------------------------------+--------------+ + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | **Features** | | **Status** | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 573 `_ | Fast access to module state from methods of C | Not relevant | + | | extension types | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 584 `_ | Union operators added to dict | Complete [#pep584]_ | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 585 `_ | Type hinting generics in standard collections | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 593 `_ | Flexible function and variable annotations | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 602 `_ | CPython adopts an annual release cycle. Instead of | Not relevant | + | | annual, aiming for two month release cycle | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 614 `_ | Relaxed grammar restrictions on decorators | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 615 `_ | The IANA Time Zone Database is now present in the | | + | | standard library in the zoneinfo module | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 616 `_ | String methods to remove prefixes and suffixes | | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ + | `PEP 617 `_ | CPython now uses a new parser based on PEG | Not relevant | + +--------------------------------------------------------+----------------------------------------------------+----------------------+ Other Language Changes: @@ -128,3 +128,7 @@ Changes to built-in modules: | Previously, *sys.stderr* was block-buffered when non-interactive. Now stderr defaults to always being | | | line-buffered | | +---------------------------------------------------------------------------------------------------------------+---------------+ + +.. rubric:: Notes + +.. [#pep584] PEP 584 ``dict`` union operator is only available on MicroPython builds with ``MICROPY_CPYTHON_COMPAT`` enabled. diff --git a/docs/esp32/quickref.rst b/docs/esp32/quickref.rst index 03ca97c7a7df..5be737fa2d76 100644 --- a/docs/esp32/quickref.rst +++ b/docs/esp32/quickref.rst @@ -57,7 +57,6 @@ The :mod:`esp32` module:: import esp32 - esp32.hall_sensor() # read the internal hall sensor esp32.raw_temperature() # read the internal temperature of the MCU, in Fahrenheit esp32.ULP() # access to the Ultra-Low-Power Co-processor @@ -68,6 +67,9 @@ by reading the temperature sensor immediately after waking up from sleep. Networking ---------- +WLAN +^^^^ + The :mod:`network` module:: import network @@ -110,6 +112,55 @@ calling ``wlan.config(reconnects=n)``, where n are the number of desired reconne attempts (0 means it won't retry, -1 will restore the default behaviour of trying to reconnect forever). +LAN +^^^ + +To use the wired interfaces one has to specify the pins and mode :: + + import network + + lan = network.LAN(mdc=PIN_MDC, ...) # Set the pin and mode configuration + lan.active(True) # activate the interface + lan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses + + +The keyword arguments for the constructor defining the PHY type and interface are: + +- mdc=pin-object # set the mdc and mdio pins. +- mdio=pin-object +- power=pin-object # set the pin which switches the power of the PHY device. +- phy_type= # Select the PHY device type. Supported devices are PHY_LAN8710, + PHY_LAN8720, PH_IP101, PHY_RTL8201, PHY_DP83848 and PHY_KSZ8041 +- phy_addr=number # The address number of the PHY device. +- ref_clk_mode=mode # Defines, whether the ref_clk at the ESP32 is an input + or output. Suitable values are Pin.IN and Pin.OUT. +- ref_clk=pin-object # defines the Pin used for ref_clk. + +These are working configurations for LAN interfaces of popular boards:: + + # Olimex ESP32-GATEWAY: power controlled by Pin(5) + # Olimex ESP32 PoE and ESP32-PoE ISO: power controlled by Pin(12) + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(5), + phy_type=network.PHY_LAN8720, phy_addr=0, + ref_clk=machine.Pin(17), ref_clk_mode=machine.Pin.OUT) + + # Wireless-Tag's WT32-ETH01 + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), + phy_type=network.PHY_LAN8720, phy_addr=1, power=None) + + # Wireless-Tag's WT32-ETH01 v1.4 + + lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), + phy_type=network.PHY_LAN8720, phy_addr=1, + power=machine.Pin(16)) + + # Espressif ESP32-Ethernet-Kit_A_V1.2 + + lan = network.LAN(id=0, mdc=Pin(23), mdio=Pin(18), power=Pin(5), + phy_type=network.PHY_IP101, phy_addr=1) + Delay and timing ---------------- @@ -241,8 +292,8 @@ Use the :ref:`machine.PWM ` class:: from machine import Pin, PWM - pwm0 = PWM(Pin(0)) # create PWM object from a pin - freq = pwm0.freq() # get current frequency (default 5kHz) + pwm0 = PWM(Pin(0), freq=5000, duty_u16=32768) # create PWM object from a pin + freq = pwm0.freq() # get current frequency pwm0.freq(1000) # set PWM frequency from 1Hz to 40MHz duty = pwm0.duty() # get current duty cycle, range 0-1023 (default 512, 50%) diff --git a/docs/esp32/tutorial/intro.rst b/docs/esp32/tutorial/intro.rst index 8ed42dbd3dc9..be09599871ce 100644 --- a/docs/esp32/tutorial/intro.rst +++ b/docs/esp32/tutorial/intro.rst @@ -17,7 +17,7 @@ Requirements The first thing you need is a board with an ESP32 chip. The MicroPython software supports the ESP32 chip itself and any board should work. The main characteristic of a board is how the GPIO pins are connected to the outside -world, and whether it includes a built-in USB-serial convertor to make the +world, and whether it includes a built-in USB-serial converter to make the UART available to your PC. Names of pins will be given in this tutorial using the chip names (eg GPIO2) @@ -59,7 +59,7 @@ bootloader mode, and second you need to copy across the firmware. The exact procedure for these steps is highly dependent on the particular board and you will need to refer to its documentation for details. -Fortunately, most boards have a USB connector, a USB-serial convertor, and the DTR +Fortunately, most boards have a USB connector, a USB-serial converter, and the DTR and RTS pins wired in a special way then deploying the firmware should be easy as all steps can be done automatically. Boards that have such features include the Adafruit Feather HUZZAH32, M5Stack, Wemos LOLIN32, and TinyPICO @@ -104,7 +104,7 @@ Serial prompt Once you have the firmware on the device you can access the REPL (Python prompt) over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial -convertor, depending on your board. The baudrate is 115200. +converter, depending on your board. The baudrate is 115200. From here you can now follow the ESP8266 tutorial, because these two Espressif chips are very similar when it comes to using MicroPython on them. The ESP8266 tutorial @@ -124,7 +124,7 @@ after it, here are troubleshooting recommendations: * The flashing instructions above use flashing speed of 460800 baud, which is good compromise between speed and stability. However, depending on your - module/board, USB-UART convertor, cables, host OS, etc., the above baud + module/board, USB-UART converter, cables, host OS, etc., the above baud rate may be too high and lead to errors. Try a more common 115200 baud rate instead in such cases. diff --git a/docs/esp32/tutorial/pwm.rst b/docs/esp32/tutorial/pwm.rst index 12d10a86b947..2650284d35f4 100644 --- a/docs/esp32/tutorial/pwm.rst +++ b/docs/esp32/tutorial/pwm.rst @@ -50,7 +50,7 @@ low all of the time. * Example of a smooth frequency change:: - from utime import sleep + from time import sleep from machine import Pin, PWM F_MIN = 500 @@ -75,7 +75,7 @@ low all of the time. * Example of a smooth duty change:: - from utime import sleep + from time import sleep from machine import Pin, PWM DUTY_MAX = 2**16 - 1 diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index 75739bd6f96f..0d4bc42e2dab 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -18,7 +18,7 @@ The first thing you need is a board with an ESP8266 chip. The MicroPython software supports the ESP8266 chip itself and any board should work. The main characteristic of a board is how much flash it has, how the GPIO pins are connected to the outside world, and whether it includes a built-in USB-serial -convertor to make the UART available to your PC. +converter to make the UART available to your PC. The minimum requirement for flash size is 1Mbyte. There is also a special build for boards with 512KB, but it is highly limited comparing to the @@ -70,7 +70,7 @@ need to put your device in boot-loader mode, and second you need to copy across the firmware. The exact procedure for these steps is highly dependent on the particular board and you will need to refer to its documentation for details. -If you have a board that has a USB connector, a USB-serial convertor, and has +If you have a board that has a USB connector, a USB-serial converter, and has the DTR and RTS pins wired in a special way then deploying the firmware should be easy as all steps can be done automatically. Boards that have such features include the Adafruit Feather HUZZAH and NodeMCU boards. @@ -128,7 +128,7 @@ Serial prompt Once you have the firmware on the device you can access the REPL (Python prompt) over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial -convertor, depending on your board. The baudrate is 115200. The next part of +converter, depending on your board. The baudrate is 115200. The next part of the tutorial will discuss the prompt in more detail. WiFi @@ -137,7 +137,7 @@ WiFi After a fresh install and boot the device configures itself as a WiFi access point (AP) that you can connect to. The ESSID is of the form MicroPython-xxxxxx where the x's are replaced with part of the MAC address of your device (so will -be the same everytime, and most likely different for all ESP8266 chips). The +be the same every time, and most likely different for all ESP8266 chips). The password for the WiFi is micropythoN (note the upper-case N). Its IP address will be 192.168.4.1 once you connect to its network. WiFi configuration will be discussed in more detail later in the tutorial. @@ -169,7 +169,7 @@ after it, here are troubleshooting recommendations: * The flashing instructions above use flashing speed of 460800 baud, which is good compromise between speed and stability. However, depending on your - module/board, USB-UART convertor, cables, host OS, etc., the above baud + module/board, USB-UART converter, cables, host OS, etc., the above baud rate may be too high and lead to errors. Try a more common 115200 baud rate instead in such cases. diff --git a/docs/esp8266/tutorial/repl.rst b/docs/esp8266/tutorial/repl.rst index 196541bd02cb..bc0142aaef5f 100644 --- a/docs/esp8266/tutorial/repl.rst +++ b/docs/esp8266/tutorial/repl.rst @@ -13,7 +13,7 @@ REPL over the serial port The REPL is always available on the UART0 serial peripheral, which is connected to the pins GPIO1 for TX and GPIO3 for RX. The baudrate of the REPL is 115200. -If your board has a USB-serial convertor on it then you should be able to access +If your board has a USB-serial converter on it then you should be able to access the REPL directly from your PC. Otherwise you will need to have a way of communicating with the UART. diff --git a/docs/index.rst b/docs/index.rst index 9a021b3906d4..64b83618da14 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,3 +17,4 @@ MicroPython documentation and references unix/quickref.rst zephyr/quickref.rst renesas-ra/quickref.rst + samd/quickref.rst diff --git a/docs/library/array.rst b/docs/library/array.rst index 88d6d2263ca6..f417a7046e2f 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -27,3 +27,55 @@ Classes Append new elements as contained in *iterable* to the end of array, growing it. + + .. method:: __getitem__(index) + + Indexed read of the array, called as ``a[index]`` (where ``a`` is an ``array``). + Returns a value if *index* is an ``int`` and an ``array`` if *index* is a slice. + Negative indices count from the end and ``IndexError`` is thrown if the index is + out of range. + + **Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(index)`` fails) and + is not present in ``__dict__``, however ``a[index]`` does work. + + .. method:: __setitem__(index, value) + + Indexed write into the array, called as ``a[index] = value`` (where ``a`` is an ``array``). + ``value`` is a single value if *index* is an ``int`` and an ``array`` if *index* is a slice. + Negative indices count from the end and ``IndexError`` is thrown if the index is out of range. + + **Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and + is not present in ``__dict__``, however ``a[index] = value`` does work. + + .. method:: __len__() + + Returns the number of items in the array, called as ``len(a)`` (where ``a`` is an ``array``). + + **Note:** ``__len__`` cannot be called directly (``a.__len__()`` fails) and the + method is not present in ``__dict__``, however ``len(a)`` does work. + + .. method:: __add__(other) + + Return a new ``array`` that is the concatenation of the array with *other*, called as + ``a + other`` (where ``a`` and *other* are both ``arrays``). + + **Note:** ``__add__`` cannot be called directly (``a.__add__(other)`` fails) and + is not present in ``__dict__``, however ``a + other`` does work. + + .. method:: __iadd__(other) + + Concatenates the array with *other* in-place, called as ``a += other`` (where ``a`` and *other* + are both ``arrays``). Equivalent to ``extend(other)``. + + **Note:** ``__iadd__`` cannot be called directly (``a.__iadd__(other)`` fails) and + is not present in ``__dict__``, however ``a += other`` does work. + + .. method:: __repr__() + + Returns the string representation of the array, called as ``str(a)`` or ``repr(a)``` + (where ``a`` is an ``array``). Returns the string ``"array(, [])"``, + where ```` is the type code letter for the array and ```` is a comma + separated list of the elements of the array. + + **Note:** ``__repr__`` cannot be called directly (``a.__repr__()`` fails) and + is not present in ``__dict__``, however ``str(a)`` and ``repr(a)`` both work. diff --git a/docs/library/asyncio.rst b/docs/library/asyncio.rst new file mode 100644 index 000000000000..9a2c14e7e015 --- /dev/null +++ b/docs/library/asyncio.rst @@ -0,0 +1,360 @@ +:mod:`asyncio` --- asynchronous I/O scheduler +============================================= + +.. module:: asyncio + :synopsis: asynchronous I/O scheduler for writing concurrent code + +|see_cpython_module| +`asyncio `_ + +Example:: + + import asyncio + + async def blink(led, period_ms): + while True: + led.on() + await asyncio.sleep_ms(5) + led.off() + await asyncio.sleep_ms(period_ms) + + async def main(led1, led2): + asyncio.create_task(blink(led1, 700)) + asyncio.create_task(blink(led2, 400)) + await asyncio.sleep_ms(10_000) + + # Running on a pyboard + from pyb import LED + asyncio.run(main(LED(1), LED(2))) + + # Running on a generic board + from machine import Pin + asyncio.run(main(Pin(1), Pin(2))) + +Core functions +-------------- + +.. function:: create_task(coro) + + Create a new task from the given coroutine and schedule it to run. + + Returns the corresponding `Task` object. + +.. function:: current_task() + + Return the `Task` object associated with the currently running task. + +.. function:: run(coro) + + Create a new task from the given coroutine and run it until it completes. + + Returns the value returned by *coro*. + +.. function:: sleep(t) + + Sleep for *t* seconds (can be a float). + + This is a coroutine. + +.. function:: sleep_ms(t) + + Sleep for *t* milliseconds. + + This is a coroutine, and a MicroPython extension. + +Additional functions +-------------------- + +.. function:: wait_for(awaitable, timeout) + + Wait for the *awaitable* to complete, but cancel it if it takes longer + than *timeout* seconds. If *awaitable* is not a task then a task will be + created from it. + + If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``: + this should be trapped by the caller. The task receives + ``asyncio.CancelledError`` which may be ignored or trapped using ``try...except`` + or ``try...finally`` to run cleanup code. + + Returns the return value of *awaitable*. + + This is a coroutine. + +.. function:: wait_for_ms(awaitable, timeout) + + Similar to `wait_for` but *timeout* is an integer in milliseconds. + + This is a coroutine, and a MicroPython extension. + +.. function:: gather(*awaitables, return_exceptions=False) + + Run all *awaitables* concurrently. Any *awaitables* that are not tasks are + promoted to tasks. + + Returns a list of return values of all *awaitables*. + + This is a coroutine. + +class Task +---------- + +.. class:: Task() + + This object wraps a coroutine into a running task. Tasks can be waited on + using ``await task``, which will wait for the task to complete and return + the return value of the task. + + Tasks should not be created directly, rather use `create_task` to create them. + +.. method:: Task.cancel() + + Cancel the task by injecting ``asyncio.CancelledError`` into it. The task may + ignore this exception. Cleanup code may be run by trapping it, or via + ``try ... finally``. + +class Event +----------- + +.. class:: Event() + + Create a new event which can be used to synchronise tasks. Events start + in the cleared state. + +.. method:: Event.is_set() + + Returns ``True`` if the event is set, ``False`` otherwise. + +.. method:: Event.set() + + Set the event. Any tasks waiting on the event will be scheduled to run. + + Note: This must be called from within a task. It is not safe to call this + from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`. + +.. method:: Event.clear() + + Clear the event. + +.. method:: Event.wait() + + Wait for the event to be set. If the event is already set then it returns + immediately. + + This is a coroutine. + +class ThreadSafeFlag +-------------------- + +.. class:: ThreadSafeFlag() + + Create a new flag which can be used to synchronise a task with code running + outside the asyncio loop, such as other threads, IRQs, or scheduler + callbacks. Flags start in the cleared state. The class does not currently + work under the Unix build of MicroPython. + +.. method:: ThreadSafeFlag.set() + + Set the flag. If there is a task waiting on the flag, it will be scheduled + to run. + +.. method:: ThreadSafeFlag.clear() + + Clear the flag. This may be used to ensure that a possibly previously-set + flag is clear before waiting for it. + +.. method:: ThreadSafeFlag.wait() + + Wait for the flag to be set. If the flag is already set then it returns + immediately. The flag is automatically reset upon return from ``wait``. + + A flag may only be waited on by a single task at a time. + + This is a coroutine. + +class Lock +---------- + +.. class:: Lock() + + Create a new lock which can be used to coordinate tasks. Locks start in + the unlocked state. + + In addition to the methods below, locks can be used in an ``async with`` statement. + +.. method:: Lock.locked() + + Returns ``True`` if the lock is locked, otherwise ``False``. + +.. method:: Lock.acquire() + + Wait for the lock to be in the unlocked state and then lock it in an atomic + way. Only one task can acquire the lock at any one time. + + This is a coroutine. + +.. method:: Lock.release() + + Release the lock. If any tasks are waiting on the lock then the next one in the + queue is scheduled to run and the lock remains locked. Otherwise, no tasks are + waiting an the lock becomes unlocked. + +TCP stream connections +---------------------- + +.. function:: open_connection(host, port) + + Open a TCP connection to the given *host* and *port*. The *host* address will be + resolved using `socket.getaddrinfo`, which is currently a blocking call. + + Returns a pair of streams: a reader and a writer stream. + Will raise a socket-specific ``OSError`` if the host could not be resolved or if + the connection could not be made. + + This is a coroutine. + +.. function:: start_server(callback, host, port, backlog=5) + + Start a TCP server on the given *host* and *port*. The *callback* will be + called with incoming, accepted connections, and be passed 2 arguments: reader + and writer streams for the connection. + + Returns a `Server` object. + + This is a coroutine. + +.. class:: Stream() + + This represents a TCP stream connection. To minimise code this class implements + both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to + this class. + +.. method:: Stream.get_extra_info(v) + + Get extra information about the stream, given by *v*. The valid values for *v* are: + ``peername``. + +.. method:: Stream.close() + + Close the stream. + +.. method:: Stream.wait_closed() + + Wait for the stream to close. + + This is a coroutine. + +.. method:: Stream.read(n=-1) + + Read up to *n* bytes and return them. If *n* is not provided or -1 then read all + bytes until EOF. The returned value will be an empty bytes object if EOF is + encountered before any bytes are read. + + This is a coroutine. + +.. method:: Stream.readinto(buf) + + Read up to n bytes into *buf* with n being equal to the length of *buf*. + + Return the number of bytes read into *buf*. + + This is a coroutine, and a MicroPython extension. + +.. method:: Stream.readexactly(n) + + Read exactly *n* bytes and return them as a bytes object. + + Raises an ``EOFError`` exception if the stream ends before reading *n* bytes. + + This is a coroutine. + +.. method:: Stream.readline() + + Read a line and return it. + + This is a coroutine. + +.. method:: Stream.write(buf) + + Accumulated *buf* to the output buffer. The data is only flushed when + `Stream.drain` is called. It is recommended to call `Stream.drain` immediately + after calling this function. + +.. method:: Stream.drain() + + Drain (write) all buffered output data out to the stream. + + This is a coroutine. + +.. class:: Server() + + This represents the server class returned from `start_server`. It can be used + in an ``async with`` statement to close the server upon exit. + +.. method:: Server.close() + + Close the server. + +.. method:: Server.wait_closed() + + Wait for the server to close. + + This is a coroutine. + +Event Loop +---------- + +.. function:: get_event_loop() + + Return the event loop used to schedule and run tasks. See `Loop`. + +.. function:: new_event_loop() + + Reset the event loop and return it. + + Note: since MicroPython only has a single event loop this function just + resets the loop's state, it does not create a new one. + +.. class:: Loop() + + This represents the object which schedules and runs tasks. It cannot be + created, use `get_event_loop` instead. + +.. method:: Loop.create_task(coro) + + Create a task from the given *coro* and return the new `Task` object. + +.. method:: Loop.run_forever() + + Run the event loop until `stop()` is called. + +.. method:: Loop.run_until_complete(awaitable) + + Run the given *awaitable* until it completes. If *awaitable* is not a task + then it will be promoted to one. + +.. method:: Loop.stop() + + Stop the event loop. + +.. method:: Loop.close() + + Close the event loop. + +.. method:: Loop.set_exception_handler(handler) + + Set the exception handler to call when a Task raises an exception that is not + caught. The *handler* should accept two arguments: ``(loop, context)``. + +.. method:: Loop.get_exception_handler() + + Get the current exception handler. Returns the handler, or ``None`` if no + custom handler is set. + +.. method:: Loop.default_exception_handler(context) + + The default exception handler that is called. + +.. method:: Loop.call_exception_handler(context) + + Call the current exception handler. The argument *context* is passed through and + is a dictionary containing keys: ``'message'``, ``'exception'``, ``'future'``. diff --git a/docs/library/bluetooth.rst b/docs/library/bluetooth.rst index 8f7041e8d3fb..78cb4cc28148 100644 --- a/docs/library/bluetooth.rst +++ b/docs/library/bluetooth.rst @@ -44,7 +44,7 @@ Configuration Get or set configuration values of the BLE interface. To get a value the parameter name should be quoted as a string, and just one parameter is - queried at a time. To set values use the keyword syntax, and one ore more + queried at a time. To set values use the keyword syntax, and one or more parameter can be set at a time. Currently supported values are: @@ -183,12 +183,10 @@ Event Handling conn_handle, value_handle, char_data = data elif event == _IRQ_GATTC_READ_DONE: # A gattc_read() has completed. - # Note: The value_handle will be zero on btstack (but present on NimBLE). # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, value_handle, status = data elif event == _IRQ_GATTC_WRITE_DONE: # A gattc_write() has completed. - # Note: The value_handle will be zero on btstack (but present on NimBLE). # Note: Status will be zero on success, implementation-specific value otherwise. conn_handle, value_handle, status = data elif event == _IRQ_GATTC_NOTIFY: @@ -514,19 +512,24 @@ writes from a client to a given characteristic, use Sends a notification request to a connected client. - If *data* is not ``None``, then that value is sent to the client as part of - the notification. The local value will not be modified. + If *data* is ``None`` (the default), then the current local value (as set + with :meth:`gatts_write `) will be sent. - Otherwise, if *data* is ``None``, then the current local value (as - set with :meth:`gatts_write `) will be sent. + Otherwise, if *data* is not ``None``, then that value is sent to the client + as part of the notification. The local value will not be modified. **Note:** The notification will be sent regardless of the subscription status of the client to this characteristic. -.. method:: BLE.gatts_indicate(conn_handle, value_handle, /) +.. method:: BLE.gatts_indicate(conn_handle, value_handle, data=None, /) - Sends an indication request containing the characteristic's current value to - a connected client. + Sends a indication request to a connected client. + + If *data* is ``None`` (the default), then the current local value (as set + with :meth:`gatts_write `) will be sent. + + Otherwise, if *data* is not ``None``, then that value is sent to the client + as part of the indication. The local value will not be modified. On acknowledgment (or failure, e.g. timeout), the ``_IRQ_GATTS_INDICATE_DONE`` event will be raised. diff --git a/docs/library/deflate.rst b/docs/library/deflate.rst new file mode 100644 index 000000000000..9752af5925fc --- /dev/null +++ b/docs/library/deflate.rst @@ -0,0 +1,177 @@ +:mod:`deflate` -- deflate compression & decompression +===================================================== + +.. module:: deflate + :synopsis: deflate compression & decompression + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ +(commonly used in the zlib library and gzip archiver). + +**Availability:** + +* Added in MicroPython v1.21. + +* Decompression: Enabled via the ``MICROPY_PY_DEFLATE`` build option, on by default + on ports with the "extra features" level or higher (which is most boards). + +* Compression: Enabled via the ``MICROPY_PY_DEFLATE_COMPRESS`` build option, on + by default on ports with the "full features" level or higher (generally this means + you need to build your own firmware to enable this). + +Classes +------- + +.. class:: DeflateIO(stream, format=AUTO, wbits=0, close=False, /) + + This class can be used to wrap a *stream* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + The *stream* must be a blocking stream. Non-blocking streams are currently + not supported. + + The *format* can be set to any of the constants defined below, and defaults + to ``AUTO`` which for decompressing will auto-detect gzip or zlib streams, + and for compressing it will generate a raw stream. + + The *wbits* parameter sets the base-2 logarithm of the DEFLATE dictionary + window size. So for example, setting *wbits* to ``10`` sets the window size + to 1024 bytes. Valid values are ``5`` to ``15`` inclusive (corresponding to + window sizes of 32 to 32k bytes). + + If *wbits* is set to ``0`` (the default), then a window size of 256 bytes + will be used (corresponding to *wbits* set to ``8``), except when + :ref:`decompressing a zlib stream `. + + See the :ref:`window size ` notes below for more information + about the window size, zlib, and gzip streams. + + If *close* is set to ``True`` then the underlying stream will be closed + automatically when the :class:`deflate.DeflateIO` stream is closed. This is + useful if you want to return a :class:`deflate.DeflateIO` stream that wraps + another stream and not have the caller need to know about managing the + underlying stream. + + If compression is enabled, a given :class:`deflate.DeflateIO` instance + supports both reading and writing. For example, a bidirectional stream like + a socket can be wrapped, which allows for compression/decompression in both + directions. + +Constants +--------- + +.. data:: deflate.AUTO + deflate.RAW + deflate.ZLIB + deflate.GZIP + + Supported values for the *format* parameter. + +Examples +-------- + +A typical use case for :class:`deflate.DeflateIO` is to read or write a compressed +file from storage: + +.. code:: python + + import deflate + + # Writing a zlib-compressed stream (uses the default window size of 256 bytes). + with open("data.gz", "wb") as f: + with deflate.DeflateIO(f, deflate.ZLIB) as d: + # Use d.write(...) etc + + # Reading a zlib-compressed stream (auto-detect window size). + with open("data.z", "rb") as f: + with deflate.DeflateIO(f, deflate.ZLIB) as d: + # Use d.read(), d.readinto(), etc. + +Because :class:`deflate.DeflateIO` is a stream, it can be used for example +with :meth:`json.dump` and :meth:`json.load` (and any other places streams can +be used): + +.. code:: python + + import deflate, json + + # Write a dictionary as JSON in gzip format, with a + # small (64 byte) window size. + config = { ... } + with open("config.gz", "wb") as f: + with deflate.DeflateIO(f, deflate.GZIP, 6) as f: + json.dump(config, f) + + # Read back that dictionary. + with open("config.gz", "rb") as f: + with deflate.DeflateIO(f, deflate.GZIP, 6) as f: + config = json.load(f) + +If your source data is not in a stream format, you can use :class:`io.BytesIO` +to turn it into a stream suitable for use with :class:`deflate.DeflateIO`: + +.. code:: python + + import deflate, io + + # Decompress a bytes/bytearray value. + compressed_data = get_data_z() + with deflate.DeflateIO(io.BytesIO(compressed_data), deflate.ZLIB) as d: + decompressed_data = d.read() + + # Compress a bytes/bytearray value. + uncompressed_data = get_data() + stream = io.BytesIO() + with deflate.DeflateIO(stream, deflate.ZLIB) as d: + d.write(uncompressed_data) + compressed_data = stream.getvalue() + +.. _deflate_wbits: + +Deflate window size +------------------- + +The window size limits how far back in the stream the (de)compressor can +reference. Increasing the window size will improve compression, but will +require more memory. + +However, just because a given window size is used for compression, this does not +mean that the stream will require the same size window for decompression, as +the stream may not reference data as far back as the window allows (for example, +if the length of the input is smaller than the window size). + +If the decompressor uses a smaller window size than necessary for the input data +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 used to +compress the data (which due to the above, may be larger than the size required +for the decompressor). + +If this header value is lower than the specified *wbits* value, then the header +value will be used instead in order to reduce the memory allocation size. If +the *wbits* parameter is zero (the default), then the header value will only be +used if it is less than the maximum value of ``15`` (which is default value +used by most compressors [#f1]_). + +In other words, if the source zlib stream has been compressed with a custom window +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. +Additionally, most compressor libraries (including CPython's implementation +of :class:`gzip.GzipFile`) will default to the maximum possible window size. +This makes it difficult to decompress most gzip streams on MicroPython unless +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. diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index f0f0c8ef1f56..efdd6c1be289 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -44,10 +44,6 @@ Functions Read the raw value of the internal temperature sensor, returning an integer. -.. function:: hall_sensor() - - Read the raw value of the internal Hall sensor, returning an integer. - .. function:: idf_heap_info(capabilities) Returns information about the ESP-IDF heap memory regions. One of them contains @@ -126,7 +122,7 @@ methods to enable over-the-air (OTA) updates. and an ``OSError(-261)`` is raised if called on firmware that doesn't have the feature enabled. It is OK to call ``mark_app_valid_cancel_rollback`` on every boot and it is not - necessary when booting firmare that was loaded using esptool. + necessary when booting firmware that was loaded using esptool. Constants ~~~~~~~~~ @@ -279,6 +275,14 @@ For more details see Espressif's `ESP-IDF RMT documentation. Ultra-Low-Power co-processor ---------------------------- +This class gives access to the Ultra Low Power (ULP) co-processor on the ESP32, +ESP32-S2 and ESP32-S3 chips. + +.. warning:: + + This class does not provide access to the RISCV ULP co-processor available + on the ESP32-S2 and ESP32-S3 chips. + .. class:: ULP() This class provides access to the Ultra-Low-Power co-processor. diff --git a/docs/library/espnow.rst b/docs/library/espnow.rst new file mode 100644 index 000000000000..f344983700a1 --- /dev/null +++ b/docs/library/espnow.rst @@ -0,0 +1,936 @@ +:mod:`espnow` --- support for the ESP-NOW wireless protocol +=========================================================== + +.. module:: espnow + :synopsis: ESP-NOW wireless protocol support + +This module provides an interface to the `ESP-NOW `_ protocol provided by Espressif on +ESP32 and ESP8266 devices (`API docs `_). + +Table of Contents: +------------------ + + - `Introduction`_ + - `Configuration`_ + - `Sending and Receiving Data`_ + - `Peer Management`_ + - `Callback Methods`_ + - `Exceptions`_ + - `Constants`_ + - `Wifi Signal Strength (RSSI) - (ESP32 Only)`_ + - `Supporting asyncio`_ + - `Broadcast and Multicast`_ + - `ESPNow and Wifi Operation`_ + - `ESPNow and Sleep Modes`_ + +Introduction +------------ + +ESP-NOW is a connection-less wireless communication protocol supporting: + +- Direct communication between up to 20 registered peers: + + - Without the need for a wireless access point (AP), + +- Encrypted and unencrypted communication (up to 6 encrypted peers), + +- Message sizes up to 250 bytes, + +- Can operate alongside Wifi operation (:doc:`network.WLAN`) on + ESP32 and ESP8266 devices. + +It is especially useful for small IoT networks, latency sensitive or power +sensitive applications (such as battery operated devices) and for long-range +communication between devices (hundreds of metres). + +This module also supports tracking the Wifi signal strength (RSSI) of peer +devices. + +A simple example would be: + +**Sender:** :: + + import network + import espnow + + # A WLAN interface must be active to send()/recv() + sta = network.WLAN(network.STA_IF) # Or network.AP_IF + sta.active(True) + sta.disconnect() # For ESP8266 + + e = espnow.ESPNow() + e.active(True) + peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' # MAC address of peer's wifi interface + e.add_peer(peer) # Must add_peer() before send() + + e.send(peer, "Starting...") + for i in range(100): + e.send(peer, str(i)*20, True) + e.send(peer, b'end') + +**Receiver:** :: + + import network + import espnow + + # A WLAN interface must be active to send()/recv() + sta = network.WLAN(network.STA_IF) + sta.active(True) + sta.disconnect() # Because ESP8266 auto-connects to last Access Point + + e = espnow.ESPNow() + e.active(True) + + while True: + host, msg = e.recv() + if msg: # msg == None if timeout in recv() + print(host, msg) + if msg == b'end': + break + +class ESPNow +------------ + +Constructor +----------- + +.. class:: ESPNow() + + Returns the singleton ESPNow object. As this is a singleton, all calls to + `espnow.ESPNow()` return a reference to the same object. + + .. note:: + Some methods are available only on the ESP32 due to code size + restrictions on the ESP8266 and differences in the Espressif API. + +Configuration +------------- + +.. method:: ESPNow.active([flag]) + + Initialise or de-initialise the ESP-NOW communication protocol depending on + the value of the ``flag`` optional argument. + + .. data:: Arguments: + + - *flag*: Any python value which can be converted to a boolean type. + + - ``True``: Prepare the software and hardware for use of the ESP-NOW + communication protocol, including: + + - initialise the ESPNow data structures, + - allocate the recv data buffer, + - invoke esp_now_init() and + - register the send and recv callbacks. + + - ``False``: De-initialise the Espressif ESP-NOW software stack + (esp_now_deinit()), disable callbacks, deallocate the recv + data buffer and deregister all peers. + + If *flag* is not provided, return the current status of the ESPNow + interface. + + .. data:: Returns: + + ``True`` if interface is currently *active*, else ``False``. + +.. method:: ESPNow.config(param=value, ...) + ESPNow.config('param') (ESP32 only) + + Set or get configuration values of the ESPNow interface. To set values, use + the keyword syntax, and one or more parameters can be set at a time. To get + a value the parameter name should be quoted as a string, and just one + parameter is queried at a time. + + **Note:** *Getting* parameters is not supported on the ESP8266. + + .. data:: Options: + + *rxbuf*: (default=526) Get/set the size in bytes of the internal + buffer used to store incoming ESPNow packet data. The default size is + selected to fit two max-sized ESPNow packets (250 bytes) with associated + mac_address (6 bytes), a message byte count (1 byte) and RSSI data plus + buffer overhead. Increase this if you expect to receive a lot of large + packets or expect bursty incoming traffic. + + **Note:** The recv buffer is allocated by `ESPNow.active()`. Changing + this value will have no effect until the next call of + `ESPNow.active(True)`. + + *timeout_ms*: (default=300,000) Default timeout (in milliseconds) + for receiving ESPNow messages. If *timeout_ms* is less than zero, then + wait forever. The timeout can also be provided as arg to + `recv()`/`irecv()`/`recvinto()`. + + *rate*: (ESP32 only, IDF>=4.3.0 only) Set the transmission speed for + ESPNow packets. Must be set to a number from the allowed numeric values + in `enum wifi_phy_rate_t + `_. + + .. data:: Returns: + + ``None`` or the value of the parameter being queried. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``ValueError()`` on invalid configuration options or values. + +Sending and Receiving Data +-------------------------- + +A wifi interface (``network.STA_IF`` or ``network.AP_IF``) must be +`active()` before messages can be sent or received, +but it is not necessary to connect or configure the WLAN interface. +For example:: + + import network + + sta = network.WLAN(network.STA_IF) + sta.active(True) + sta.disconnect() # For ESP8266 + +**Note:** The ESP8266 has a *feature* that causes it to automatically reconnect +to the last wifi Access Point when set `active(True)` (even +after reboot/reset). This reduces the reliability of receiving ESP-NOW messages +(see `ESPNow and Wifi Operation`_). You can avoid this by calling +`disconnect()` after +`active(True)`. + +.. method:: ESPNow.send(mac, msg[, sync]) + ESPNow.send(msg) (ESP32 only) + + Send the data contained in ``msg`` to the peer with given network ``mac`` + address. In the second form, ``mac=None`` and ``sync=True``. The peer must + be registered with `ESPNow.add_peer()` before the + message can be sent. + + .. data:: Arguments: + + - *mac*: byte string exactly ``espnow.ADDR_LEN`` (6 bytes) long or + ``None``. If *mac* is ``None`` (ESP32 only) the message will be sent + to all registered peers, except any broadcast or multicast MAC + addresses. + + - *msg*: string or byte-string up to ``espnow.MAX_DATA_LEN`` (250) + bytes long. + + - *sync*: + + - ``True``: (default) send ``msg`` to the peer(s) and wait for a + response (or not). + + - ``False`` send ``msg`` and return immediately. Responses from the + peers will be discarded. + + .. data:: Returns: + + ``True`` if ``sync=False`` or if ``sync=True`` and *all* peers respond, + else ``False``. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if peer is not registered. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` the wifi interface is not + `active()`. + - ``OSError(num, "ESP_ERR_ESPNOW_NO_MEM")`` internal ESP-NOW buffers are + full. + - ``ValueError()`` on invalid values for the parameters. + + **Note**: A peer will respond with success if its wifi interface is + `active()` and set to the same channel as the sender, + regardless of whether it has initialised it's ESP-NOW system or is + actively listening for ESP-NOW traffic (see the Espressif ESP-NOW docs). + +.. method:: ESPNow.recv([timeout_ms]) + + Wait for an incoming message and return the ``mac`` address of the peer and + the message. **Note**: It is **not** necessary to register a peer (using + `add_peer()`) to receive a message from that peer. + + .. data:: Arguments: + + - *timeout_ms*: (Optional): May have the following values. + + - ``0``: No timeout. Return immediately if no data is available; + - ``> 0``: Specify a timeout value in milliseconds; + - ``< 0``: Do not timeout, ie. wait forever for new messages; or + - ``None`` (or not provided): Use the default timeout value set with + `ESPNow.config()`. + + .. data:: Returns: + + - ``(None, None)`` if timeout is reached before a message is received, or + + - ``[mac, msg]``: where: + + - ``mac`` is a bytestring containing the address of the device which + sent the message, and + - ``msg`` is a bytestring containing the message. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_IF")`` if the wifi interface is not + `active()`. + - ``ValueError()`` on invalid *timeout_ms* values. + + `ESPNow.recv()` will allocate new storage for the returned list and the + ``peer`` and ``msg`` bytestrings. This can lead to memory fragmentation if + the data rate is high. See `ESPNow.irecv()` for a memory-friendly + alternative. + + +.. method:: ESPNow.irecv([timeout_ms]) + + Works like `ESPNow.recv()` but will re-use internal bytearrays to store the + return values: ``[mac, msg]``, so that no new memory is allocated on each + call. + + .. data:: Arguments: + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + .. data:: Returns: + + - As for `ESPNow.recv()`, except that ``msg`` is a bytearray, instead of + a bytestring. On the ESP8266, ``mac`` will also be a bytearray. + + .. data:: Raises: + + - See `ESPNow.recv()`. + + **Note:** You may also read messages by iterating over the ESPNow object, + which will use the `irecv()` method for alloc-free reads, eg: :: + + import espnow + e = espnow.ESPNow(); e.active(True) + for mac, msg in e: + print(mac, msg) + if mac is None: # mac, msg will equal (None, None) on timeout + break + +.. method:: ESPNow.recvinto(data[, timeout_ms]) + + Wait for an incoming message and return the length of the message in bytes. + This is the low-level method used by both `recv()` and + `irecv()` to read messages. + + .. data:: Arguments: + + *data*: A list of at least two elements, ``[peer, msg]``. ``msg`` must + be a bytearray large enough to hold the message (250 bytes). On the + ESP8266, ``peer`` should be a bytearray of 6 bytes. The MAC address of + the sender and the message will be stored in these bytearrays (see Note + on ESP32 below). + + *timeout_ms*: (Optional) Timeout in milliseconds (see `ESPNow.recv()`). + + .. data:: Returns: + + - Length of message in bytes or 0 if *timeout_ms* is reached before a + message is received. + + .. data:: Raises: + + - See `ESPNow.recv()`. + + **Note:** On the ESP32: + + - It is unnecessary to provide a bytearray in the first element of the + ``data`` list because it will be replaced by a reference to a unique + ``peer`` address in the **peer device table** (see `ESPNow.peers_table`). + - If the list is at least 4 elements long, the rssi and timestamp values + will be saved as the 3rd and 4th elements. + +.. method:: ESPNow.any() + + Check if data is available to be read with `ESPNow.recv()`. + + For more sophisticated querying of available characters use `select.poll()`:: + + import select + import espnow + + e = espnow.ESPNow() + poll = select.poll() + poll.register(e, select.POLLIN) + poll.poll(timeout) + + .. data:: Returns: + + ``True`` if data is available to be read, else ``False``. + +.. method:: ESPNow.stats() (ESP32 only) + + .. data:: Returns: + + A 5-tuple containing the number of packets sent/received/lost: + + ``(tx_pkts, tx_responses, tx_failures, rx_packets, rx_dropped_packets)`` + + Incoming packets are *dropped* when the recv buffers are full. To reduce + packet loss, increase the ``rxbuf`` config parameters and ensure you are + reading messages as quickly as possible. + + **Note**: Dropped packets will still be acknowledged to the sender as + received. + +Peer Management +--------------- + +On ESP32 devices, the Espressif ESP-NOW software requires that other devices +(peers) must be *registered* using `add_peer()` before we can +`send()` them messages (this is *not* enforced on ESP8266 +devices). It is **not** necessary to register a peer to receive an +un-encrypted message from that peer. + +**Encrypted messages**: To receive an *encrypted* message, the receiving device +must first register the sender and use the same encryption keys as the sender +(PMK and LMK) (see `set_pmk()` and `add_peer()`. + +.. method:: ESPNow.set_pmk(pmk) + + Set the Primary Master Key (PMK) which is used to encrypt the Local Master + Keys (LMK) for encrypting messages. If this is not set, a default PMK is + used by the underlying Espressif ESP-NOW software stack. + + **Note:** messages will only be encrypted if *lmk* is also set in + `ESPNow.add_peer()` (see `Security + `_ in the Espressif API + docs). + + .. data:: Arguments: + + *pmk*: Must be a byte string, bytearray or string of length + `espnow.KEY_LEN` (16 bytes). + + .. data:: Returns: + + ``None`` + + .. data:: Raises: + + ``ValueError()`` on invalid *pmk* values. + +.. method:: ESPNow.add_peer(mac, [lmk], [channel], [ifidx], [encrypt]) + ESPNow.add_peer(mac, param=value, ...) (ESP32 only) + + Add/register the provided *mac* address as a peer. Additional parameters may + also be specified as positional or keyword arguments (any parameter set to + ``None`` will be set to it's default value): + + .. data:: Arguments: + + - *mac*: The MAC address of the peer (as a 6-byte byte-string). + + - *lmk*: The Local Master Key (LMK) key used to encrypt data + transfers with this peer (unless the *encrypt* parameter is set to + ``False``). Must be: + + - a byte-string or bytearray or string of length ``espnow.KEY_LEN`` + (16 bytes), or + + - any non ``True`` python value (default= ``b''``), signifying an + *empty* key which will disable encryption. + + - *channel*: The wifi channel (2.4GHz) to communicate with this peer. + Must be an integer from 0 to 14. If channel is set to 0 the current + channel of the wifi device will be used. (default=0) + + - *ifidx*: (ESP32 only) Index of the wifi interface which will be + used to send data to this peer. Must be an integer set to + ``network.STA_IF`` (=0) or ``network.AP_IF`` (=1). + (default=0/``network.STA_IF``). See `ESPNow and Wifi Operation`_ + below for more information. + + - *encrypt*: (ESP32 only) If set to ``True`` data exchanged with + this peer will be encrypted with the PMK and LMK. (default = + ``True`` if *lmk* is set to a valid key, else ``False``) + + **ESP8266**: Keyword args may not be used on the ESP8266. + + **Note:** The maximum number of peers which may be registered is 20 + (`espnow.MAX_TOTAL_PEER_NUM`), with a maximum of 6 + (`espnow.MAX_ENCRYPT_PEER_NUM`) of those peers with encryption enabled + (see `ESP_NOW_MAX_ENCRYPT_PEER_NUM `_ in the Espressif API + docs). + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_EXIST")`` if *mac* is already + registered. + - ``OSError(num, "ESP_ERR_ESPNOW_FULL")`` if too many peers are + already registered. + - ``ValueError()`` on invalid keyword args or values. + +.. method:: ESPNow.del_peer(mac) + + Deregister the peer associated with the provided *mac* address. + + .. data:: Returns: + + ``None`` + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not + registered. + - ``ValueError()`` on invalid *mac* values. + +.. method:: ESPNow.get_peer(mac) (ESP32 only) + + Return information on a registered peer. + + .. data:: Returns: + + ``(mac, lmk, channel, ifidx, encrypt)``: a tuple of the "peer + info" associated with the given *mac* address. + + .. data:: Raises: + + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_INIT")`` if not initialised. + - ``OSError(num, "ESP_ERR_ESPNOW_NOT_FOUND")`` if *mac* is not + registered. + - ``ValueError()`` on invalid *mac* values. + +.. method:: ESPNow.peer_count() (ESP32 only) + + Return the number of registered peers: + + - ``(peer_num, encrypt_num)``: where + + - ``peer_num`` is the number of peers which are registered, and + - ``encrypt_num`` is the number of encrypted peers. + +.. method:: ESPNow.get_peers() (ESP32 only) + + Return the "peer info" parameters for all the registered peers (as a tuple + of tuples). + +.. method:: ESPNow.mod_peer(mac, lmk, [channel], [ifidx], [encrypt]) (ESP32 only) + ESPNow.mod_peer(mac, 'param'=value, ...) (ESP32 only) + + Modify the parameters of the peer associated with the provided *mac* + address. Parameters may be provided as positional or keyword arguments + (see `ESPNow.add_peer()`). Any parameter that is not set (or set to + ``None``) will retain the existing value for that parameter. + +Callback Methods +---------------- + +.. method:: ESPNow.irq(callback) (ESP32 only) + + Set a callback function to be called *as soon as possible* after a message has + been received from another ESPNow device. The callback function will be called + with the `ESPNow` instance object as an argument. For more reliable operation, + it is recommended to read out as many messages as are available when the + callback is invoked and to set the read timeout to zero, eg: :: + + def recv_cb(e): + while True: # Read out all messages waiting in the buffer + mac, msg = e.irecv(0) # Don't wait if no messages left + if mac is None: + return + print(mac, msg) + e.irq(recv_cb) + + The `irq()` callback method is an alternative method for + processing incoming messages, especially if the data rate is moderate + and the device is *not too busy* but there are some caveats: + + - The scheduler stack *can* overflow and callbacks will be missed if + packets are arriving at a sufficient rate or if other MicroPython components + (eg, bluetooth, machine.Pin.irq(), machine.timer, i2s, ...) are exercising + the scheduler stack. This method may be less reliable for dealing with + bursts of messages, or high throughput or on a device which is busy dealing + with other hardware operations. + + - For more information on *scheduled* function callbacks see: + `micropython.schedule()`. + +Constants +--------- + +.. data:: espnow.MAX_DATA_LEN(=250) + espnow.KEY_LEN(=16) + espnow.ADDR_LEN(=6) + espnow.MAX_TOTAL_PEER_NUM(=20) + espnow.MAX_ENCRYPT_PEER_NUM(=6) + +Exceptions +---------- + +If the underlying Espressif ESP-NOW software stack returns an error code, +the MicroPython espnow module will raise an ``OSError(errnum, errstring)`` +exception where ``errstring`` is set to the name of one of the error codes +identified in the +`Espressif ESP-NOW docs +`_. For example:: + + try: + e.send(peer, 'Hello') + except OSError as err: + if len(err.args) < 2: + raise err + if err.args[1] == 'ESP_ERR_ESPNOW_NOT_INIT': + e.active(True) + elif err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND': + e.add_peer(peer) + elif err.args[1] == 'ESP_ERR_ESPNOW_IF': + network.WLAN(network.STA_IF).active(True) + else: + raise err + +Wifi Signal Strength (RSSI) - (ESP32 only) +------------------------------------------ + +The ESPNow object maintains a **peer device table** which contains the signal +strength and timestamp of the last received message from all hosts. The **peer +device table** can be accessed using `ESPNow.peers_table` and can be used to +track device proximity and identify *nearest neighbours* in a network of peer +devices. This feature is **not** available on ESP8266 devices. + +.. data:: ESPNow.peers_table + + A reference to the **peer device table**: a dict of known peer devices + and rssi values:: + + {peer: [rssi, time_ms], ...} + + where: + + - ``peer`` is the peer MAC address (as `bytes`); + - ``rssi`` is the wifi signal strength in dBm (-127 to 0) of the last + message received from the peer; and + - ``time_ms`` is the time the message was received (in milliseconds since + system boot - wraps every 12 days). + + Example:: + + >>> e.peers_table + {b'\xaa\xaa\xaa\xaa\xaa\xaa': [-31, 18372], + b'\xbb\xbb\xbb\xbb\xbb\xbb': [-43, 12541]} + + **Note**: the ``mac`` addresses returned by `recv()` are references to + the ``peer`` key values in the **peer device table**. + + **Note**: RSSI and timestamp values in the device table are updated only + when the message is read by the application. + +Supporting asyncio +------------------ + +A supplementary module (`aioespnow`) is available to provide +:doc:`asyncio` support. + +**Note:** Asyncio support is available on all ESP32 targets as well as those +ESP8266 boards which include the asyncio module (ie. ESP8266 devices with at +least 2MB flash memory). + +A small async server example:: + + import network + import aioespnow + import asyncio + + # A WLAN interface must be active to send()/recv() + network.WLAN(network.STA_IF).active(True) + + e = aioespnow.AIOESPNow() # Returns AIOESPNow enhanced with async support + e.active(True) + peer = b'\xbb\xbb\xbb\xbb\xbb\xbb' + e.add_peer(peer) + + # Send a periodic ping to a peer + async def heartbeat(e, peer, period=30): + while True: + if not await e.asend(peer, b'ping'): + print("Heartbeat: peer not responding:", peer) + else: + print("Heartbeat: ping", peer) + await asyncio.sleep(period) + + # Echo any received messages back to the sender + async def echo_server(e): + async for mac, msg in e: + print("Echo:", msg) + try: + await e.asend(mac, msg) + except OSError as err: + if len(err.args) > 1 and err.args[1] == 'ESP_ERR_ESPNOW_NOT_FOUND': + e.add_peer(mac) + await e.asend(mac, msg) + + async def main(e, peer, timeout, period): + asyncio.create_task(heartbeat(e, peer, period)) + asyncio.create_task(echo_server(e)) + await asyncio.sleep(timeout) + + asyncio.run(main(e, peer, 120, 10)) + +.. module:: aioespnow + :synopsis: ESP-NOW :doc:`asyncio` support + +.. class:: AIOESPNow() + + The `AIOESPNow` class inherits all the methods of `ESPNow` + and extends the interface with the following async methods. + +.. method:: async AIOESPNow.arecv() + + Asyncio support for `ESPNow.recv()`. Note that this method does not take a + timeout value as argument. + +.. method:: async AIOESPNow.airecv() + + Asyncio support for `ESPNow.irecv()`. Note that this method does not take a + timeout value as argument. + +.. method:: async AIOESPNow.asend(mac, msg, sync=True) + async AIOESPNow.asend(msg) + + Asyncio support for `ESPNow.send()`. + +.. method:: AIOESPNow._aiter__() / async AIOESPNow.__anext__() + + `AIOESPNow` also supports reading incoming messages by asynchronous + iteration using ``async for``; eg:: + + e = AIOESPNow() + e.active(True) + async def recv_till_halt(e): + async for mac, msg in e: + print(mac, msg) + if msg == b'halt': + break + asyncio.run(recv_till_halt(e)) + +Broadcast and Multicast +----------------------- + +All active ESPNow clients will receive messages sent to their MAC address and +all devices (**except ESP8266 devices**) will also receive messages sent to the +*broadcast* MAC address (``b'\xff\xff\xff\xff\xff\xff'``) or any multicast +MAC address. + +All ESPNow devices (including ESP8266 devices) can also send messages to the +broadcast MAC address or any multicast MAC address. + +To `send()` a broadcast message, the broadcast (or +multicast) MAC address must first be registered using +`add_peer()`. `send()` will always return +``True`` for broadcasts, regardless of whether any devices receive the +message. It is not permitted to encrypt messages sent to the broadcast +address or any multicast address. + +**Note**: `ESPNow.send(None, msg)` will send to all registered +peers *except* the broadcast address. To send a broadcast or multicast +message, you must specify the broadcast (or multicast) MAC address as the +peer. For example:: + + bcast = b'\xff' * 6 + e.add_peer(bcast) + e.send(bcast, "Hello World!") + +ESPNow and Wifi Operation +------------------------- + +ESPNow messages may be sent and received on any `active()` +`WLAN` interface (``network.STA_IF`` or ``network.AP_IF``), even +if that interface is also connected to a wifi network or configured as an access +point. When an ESP32 or ESP8266 device connects to a Wifi Access Point (see +`ESP32 Quickref <../esp32/quickref.html#networking>`__) the following things +happen which affect ESPNow communications: + +1. Wifi Power-saving Mode (`network.WLAN.PM_PERFORMANCE`) + is automatically activated and +2. The radio on the esp device changes wifi ``channel`` to match the channel + used by the Access Point. + +**Wifi Power-saving Mode:** (see `Espressif Docs `_) The power saving mode causes the +device to turn off the radio periodically (typically for hundreds of +milliseconds), making it unreliable in receiving ESPNow messages. This can be +resolved by either of: + +1. Disabling the power-saving mode on the STA_IF interface; + + - Use ``sta.config(pm=sta.PM_NONE)`` + +2. Turning on the AP_IF interface, which will disable the power saving mode. + However, the device will then be advertising an active wifi access point. + + - You **may** also choose to send your messages via the AP_IF interface, but + this is not necessary. + - ESP8266 peers must send messages to this AP_IF interface (see below). + +3. Configuring ESPNow clients to retry sending messages. + +**Receiving messages from an ESP8266 device:** Strangely, an ESP32 device +connected to a wifi network using method 1 or 2 above, will receive ESPNow +messages sent to the STA_IF MAC address from another ESP32 device, but will +**reject** messages from an ESP8266 device!!!. To receive messages from an +ESP8266 device, the AP_IF interface must be set to ``active(True)`` **and** +messages must be sent to the AP_IF MAC address. + +**Managing wifi channels:** Any other ESPNow devices wishing to communicate with +a device which is also connected to a Wifi Access Point MUST use the same +channel. A common scenario is where one ESPNow device is connected to a wifi +router and acts as a proxy for messages from a group of sensors connected via +ESPNow: + +**Proxy:** :: + + import network, time, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.connect('myssid', 'mypassword') + while not sta.isconnected(): # Wait until connected... + time.sleep(0.1) + sta.config(pm=sta.PM_NONE) # ..then disable power saving + + # Print the wifi channel used AFTER finished connecting to access point + print("Proxy running on channel:", sta.config("channel")) + e = espnow.ESPNow(); e.active(True) + for peer, msg in e: + # Receive espnow messages and forward them to MQTT broker over wifi + +**Sensor:** :: + + import network, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.config(channel=6) # Change to the channel used by the proxy above. + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of proxy + e = espnow.ESPNow(); e.active(True); + e.add_peer(peer) + while True: + msg = read_sensor() + e.send(peer, msg) + time.sleep(1) + +Other issues to take care with when using ESPNow with wifi are: + +- **Set WIFI to known state on startup:** MicroPython does not reset the wifi + peripheral after a soft reset. This can lead to unexpected behaviour. To + guarantee the wifi is reset to a known state after a soft reset make sure you + deactivate the STA_IF and AP_IF before setting them to the desired state at + startup, eg.:: + + import network, time + + def wifi_reset(): # Reset wifi to AP_IF off, STA_IF on and disconnected + sta = network.WLAN(network.STA_IF); sta.active(False) + ap = network.WLAN(network.AP_IF); ap.active(False) + sta.active(True) + while not sta.active(): + time.sleep(0.1) + sta.disconnect() # For ESP8266 + while sta.isconnected(): + time.sleep(0.1) + return sta, ap + + sta, ap = wifi_reset() + + Remember that a soft reset occurs every time you connect to the device REPL + and when you type ``ctrl-D``. + +- **STA_IF and AP_IF always operate on the same channel:** the AP_IF will change + channel when you connect to a wifi network; regardless of the channel you set + for the AP_IF (see `Attention Note 3 + `_ + ). After all, there is really only one wifi radio on the device, which is + shared by the STA_IF and AP_IF virtual devices. + +- **Disable automatic channel assignment on your wifi router:** If the wifi + router for your wifi network is configured to automatically assign the wifi + channel, it may change the channel for the network if it detects interference + from other wifi routers. When this occurs, the ESP devices connected to the + wifi network will also change channels to match the router, but other + ESPNow-only devices will remain on the previous channel and communication will + be lost. To mitigate this, either set your wifi router to use a fixed wifi + channel or configure your devices to re-scan the wifi channels if they are + unable to find their expected peers on the current channel. + +- **MicroPython re-scans wifi channels when trying to reconnect:** If the esp + device is connected to a Wifi Access Point that goes down, MicroPython will + automatically start scanning channels in an attempt to reconnect to the + Access Point. This means ESPNow messages will be lost while scanning for the + AP. This can be disabled by ``sta.config(reconnects=0)``, which will also + disable the automatic reconnection after losing connection. + +- Some versions of the ESP IDF only permit sending ESPNow packets from the + STA_IF interface to peers which have been registered on the same wifi + channel as the STA_IF:: + + ESPNOW: Peer channel is not equal to the home channel, send fail! + +ESPNow and Sleep Modes +---------------------- + +The `machine.lightsleep([time_ms])` and +`machine.deepsleep([time_ms])` functions can be used to put +the ESP32 and peripherals (including the WiFi and Bluetooth radios) to sleep. +This is useful in many applications to conserve battery power. However, +applications must disable the WLAN peripheral (using +`active(False)`) before entering light or deep sleep (see +`Sleep Modes `_). +Otherwise the WiFi radio may not be initialised properly after wake from +sleep. If the ``STA_IF`` and ``AP_IF`` interfaces have both been set +`active(True)` then both interfaces should be set +`active(False)` before entering any sleep mode. + +**Example:** deep sleep:: + + import network, machine, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer + e = espnow.ESPNow() + e.active(True) + e.add_peer(peer) # Register peer on STA_IF + + print('Sending ping...') + if not e.send(peer, b'ping'): + print('Ping failed!') + e.active(False) + sta.active(False) # Disable the wifi before sleep + print('Going to sleep...') + machine.deepsleep(10000) # Sleep for 10 seconds then reboot + +**Example:** light sleep:: + + import network, machine, espnow + + sta, ap = wifi_reset() # Reset wifi to AP off, STA on and disconnected + sta.config(channel=6) + peer = b'0\xaa\xaa\xaa\xaa\xaa' # MAC address of peer + e = espnow.ESPNow() + e.active(True) + e.add_peer(peer) # Register peer on STA_IF + + while True: + print('Sending ping...') + if not e.send(peer, b'ping'): + print('Ping failed!') + sta.active(False) # Disable the wifi before sleep + print('Going to sleep...') + machine.lightsleep(10000) # Sleep for 10 seconds + sta.active(True) + sta.config(channel=6) # Wifi loses config after lightsleep() + diff --git a/docs/library/framebuf.rst b/docs/library/framebuf.rst index 78ae0c1c346b..149f4d6609be 100644 --- a/docs/library/framebuf.rst +++ b/docs/library/framebuf.rst @@ -133,7 +133,9 @@ Other methods Draw another FrameBuffer on top of the current one at the given coordinates. If *key* is specified then it should be a color integer and the corresponding color will be considered transparent: all pixels with that - color value will not be drawn. + color value will not be drawn. (If the *palette* is specified then the *key* + is compared to the value from *palette*, not to the value directly from + *fbuf*.) The *palette* argument enables blitting between FrameBuffers with differing formats. Typical usage is to render a monochrome or grayscale glyph/icon to diff --git a/docs/library/gzip.rst b/docs/library/gzip.rst new file mode 100644 index 000000000000..f36f896db3a1 --- /dev/null +++ b/docs/library/gzip.rst @@ -0,0 +1,106 @@ +:mod:`gzip` -- gzip compression & decompression +=============================================== + +.. module:: gzip + :synopsis: gzip compression & decompression + +|see_cpython_module| :mod:`python:gzip`. + +This module allows compression and decompression of binary data with the +`DEFLATE algorithm `_ used by the gzip +file format. + +.. note:: Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* This module is **not present by default** in official MicroPython firmware + releases as it duplicates functionality available in the :mod:`deflate + ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. + +Functions +--------- + +.. function:: open(filename, mode, /) + + Wrapper around built-in :func:`open` returning a GzipFile instance. + +.. function:: decompress(data, /) + + Decompresses *data* into a bytes object. + +.. function:: compress(data, /) + + Compresses *data* into a bytes object. + +Classes +------- + +.. class:: GzipFile(*, fileobj, mode) + + This class can be used to wrap a *fileobj* which is any + :term:`stream-like ` object such as a file, socket, or stream + (including :class:`io.BytesIO`). It is itself a stream and implements the + standard read/readinto/write/close methods. + + When the *mode* argument is ``"rb"``, reads from the GzipFile instance will + decompress the data in the underlying stream and return decompressed data. + + If compression support is enabled then the *mode* argument can be set to + ``"wb"``, and writes to the GzipFile instance will be compressed and written + to the underlying stream. + + By default the GzipFile class will read and write data using the gzip file + format, including a header and footer with checksum and a window size of 512 + bytes. + + The **file**, **compresslevel**, and **mtime** arguments are not + supported. **fileobj** and **mode** must always be specified as keyword + arguments. + +Examples +-------- + +A typical use case for :class:`gzip.GzipFile` is to read or write a compressed +file from storage: + +.. code:: python + + import gzip + + # Reading: + with open("data.gz", "rb") as f: + with gzip.GzipFile(fileobj=f, mode="rb") as g: + # Use g.read(), g.readinto(), etc. + + # Same, but using gzip.open: + with gzip.open("data.gz", "rb") as f: + # Use f.read(), f.readinto(), etc. + + # Writing: + with open("data.gz", "wb") as f: + with gzip.GzipFile(fileobj=f, mode="wb") as g: + # Use g.write(...) etc + + # Same, but using gzip.open: + with gzip.open("data.gz", "wb") as f: + # Use f.write(...) etc + + # Write a dictionary as JSON in gzip format, with a + # small (64 byte) window size. + config = { ... } + with gzip.open("config.gz", "wb") as f: + json.dump(config, f) + +For guidance on working with gzip sources and choosing the window size see the +note at the :ref:`end of the deflate documentation `. diff --git a/docs/library/index.rst b/docs/library/index.rst index 59ed1127a783..ae5d3e7d7117 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -8,15 +8,17 @@ MicroPython libraries Important summary of this section * MicroPython provides built-in modules that mirror the functionality of the - Python standard library (e.g. :mod:`os`, :mod:`time`), as well as - MicroPython-specific modules (e.g. :mod:`bluetooth`, :mod:`machine`). - * Most standard library modules implement a subset of the functionality of - the equivalent Python module, and in a few cases provide some - MicroPython-specific extensions (e.g. :mod:`array`, :mod:`os`) + :ref:`Python standard library ` (e.g. :mod:`os`, + :mod:`time`), as well as :ref:`MicroPython-specific modules ` + (e.g. :mod:`bluetooth`, :mod:`machine`). + * Most Python standard library modules implement a subset of the + functionality of the equivalent Python module, and in a few cases provide + some MicroPython-specific extensions (e.g. :mod:`array`, :mod:`os`) * Due to resource constraints or other limitations, some ports or firmware versions may not include all the functionality documented here. - * To allow for extensibility, the built-in modules can be extended from - Python code loaded onto the device. + * To allow for extensibility, some built-in modules can be + :ref:`extended from Python code ` loaded onto + the device filesystem. This chapter describes modules (function and class libraries) which are built into MicroPython. This documentation in general aspires to describe all modules @@ -41,6 +43,8 @@ Beyond the built-in libraries described in this documentation, many more modules from the Python standard library, as well as further MicroPython extensions to it, can be found in :term:`micropython-lib`. +.. _micropython_lib_python: + Python standard libraries and micro-libraries --------------------------------------------- @@ -53,12 +57,14 @@ library. :maxdepth: 1 array.rst + asyncio.rst binascii.rst builtins.rst cmath.rst collections.rst errno.rst gc.rst + gzip.rst hashlib.rst heapq.rst io.rst @@ -73,10 +79,10 @@ library. struct.rst sys.rst time.rst - uasyncio.rst zlib.rst _thread.rst +.. _micropython_lib_micropython: MicroPython-specific libraries ------------------------------ @@ -90,6 +96,7 @@ the following libraries. bluetooth.rst btree.rst cryptolib.rst + deflate.rst framebuf.rst machine.rst micropython.rst @@ -155,6 +162,11 @@ The following libraries are specific to the ESP8266 and ESP32. esp.rst esp32.rst +.. toctree:: + :maxdepth: 1 + + espnow.rst + Libraries specific to the RP2040 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -176,23 +188,60 @@ The following libraries are specific to the Zephyr port. zephyr.rst +.. _micropython_lib_extending: + Extending built-in libraries from Python ---------------------------------------- -In most cases, the above modules are actually named ``umodule`` rather than -``module``, but MicroPython will alias any module prefixed with a ``u`` to the -non-``u`` version. However a file (or :term:`frozen module`) named -``module.py`` will take precedence over this alias. +A subset of the built-in modules are able to be extended by Python code by +providing a module of the same name in the filesystem. This extensibility +applies to the following Python standard library modules which are built-in to +the firmware: ``array``, ``binascii``, ``collections``, ``errno``, ``gzip``, +``hashlib``, ``heapq``, ``io``, ``json``, ``os``, ``platform``, ``random``, +``re``, ``select``, ``socket``, ``ssl``, ``struct``, ``time`` ``zlib``, as well +as the MicroPython-specific ``machine`` module. All other built-in modules +cannot be extended from the filesystem. This allows the user to provide an extended implementation of a built-in library -(perhaps to provide additional CPython compatibility). The user-provided module -(in ``module.py``) can still use the built-in functionality by importing -``umodule`` directly. This is used extensively in :term:`micropython-lib`. See -:ref:`packages` for more information. - -This applies to both the Python standard libraries (e.g. ``os``, ``time``, etc), -but also the MicroPython libraries too (e.g. ``machine``, ``bluetooth``, etc). -The main exception is the port-specific libraries (``pyb``, ``esp``, etc). - -*Other than when you specifically want to force the use of the built-in module, -we recommend always using* ``import module`` *rather than* ``import umodule``. +(perhaps to provide additional CPython compatibility or missing functionality). +This is used extensively in :term:`micropython-lib`, see :ref:`packages` for +more information. The filesystem module will typically do a wildcard import of +the built-in module in order to inherit all the globals (classes, functions and +variables) from the built-in. + +In MicroPython v1.21.0 and higher, to prevent the filesystem module from +importing itself, it can force an import of the built-in module it by +temporarily clearing ``sys.path`` during the import. For example, to extend the +``time`` module from Python, a file named ``time.py`` on the filesystem would +do the following:: + + _path = sys.path + sys.path = () + try: + from time import * + finally: + sys.path = _path + del _path + + def extra_method(): + pass + +The result is that ``time.py`` contains all the globals of the built-in ``time`` +module, but adds ``extra_method``. + +In earlier versions of MicroPython, you can force an import of a built-in module +by appending a ``u`` to the start of its name. For example, ``import utime`` +instead of ``import time``. For example, ``time.py`` on the filesystem could +look like:: + + from utime import * + + def extra_method(): + pass + +This way is still supported, but the ``sys.path`` method described above is now +preferred as the ``u``-prefix will be removed from the names of built-in +modules in a future version of MicroPython. + +*Other than when it specifically needs to force the use of the built-in module, +code should always use* ``import module`` *rather than* ``import umodule``. diff --git a/docs/library/machine.ADC.rst b/docs/library/machine.ADC.rst index eb538a4424f6..65225ea8788d 100644 --- a/docs/library/machine.ADC.rst +++ b/docs/library/machine.ADC.rst @@ -4,7 +4,7 @@ class ADC -- analog to digital conversion ========================================= -The ADC class provides an interface to analog-to-digital convertors, and +The ADC class provides an interface to analog-to-digital converters, and represents a single endpoint that can sample a continuous voltage and convert it to a discretised value. diff --git a/docs/library/machine.I2C.rst b/docs/library/machine.I2C.rst index 2a33b1da47a3..635d5873444b 100644 --- a/docs/library/machine.I2C.rst +++ b/docs/library/machine.I2C.rst @@ -52,7 +52,7 @@ Example usage:: Constructors ------------ -.. class:: I2C(id, *, scl, sda, freq=400000) +.. class:: I2C(id, *, scl, sda, freq=400000, timeout=50000) Construct and return a new I2C object using the following parameters: @@ -62,6 +62,8 @@ Constructors - *sda* should be a pin object specifying the pin to use for SDA. - *freq* should be an integer which sets the maximum frequency for SCL. + - *timeout* is the maximum time in microseconds to allow for I2C + transactions. This parameter is not allowed on some ports. Note that some ports/boards will have default values of *scl* and *sda* that can be changed in this constructor. Others will have fixed values @@ -91,6 +93,10 @@ General Methods - *sda* is a pin object for the SDA line - *freq* is the SCL clock rate + In the case of hardware I2C the actual clock frequency may be lower than the + requested frequency. This is dependent on the platform hardware. The actual + rate may be determined by printing the I2C object. + .. method:: I2C.deinit() Turn off the I2C bus. diff --git a/docs/library/machine.I2S.rst b/docs/library/machine.I2S.rst index b602ac6504d3..84edb94e78db 100644 --- a/docs/library/machine.I2S.rst +++ b/docs/library/machine.I2S.rst @@ -47,7 +47,7 @@ I2S objects can be created and initialized using:: 3 modes of operation are supported: - blocking - non-blocking - - uasyncio + - asyncio blocking:: @@ -63,13 +63,13 @@ non-blocking:: audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled num_read = audio_in.readinto(buf) # returns immediately -uasyncio:: +asyncio:: - swriter = uasyncio.StreamWriter(audio_out) + swriter = asyncio.StreamWriter(audio_out) swriter.write(buf) await swriter.drain() - sreader = uasyncio.StreamReader(audio_in) + sreader = asyncio.StreamReader(audio_in) num_read = await sreader.readinto(buf) Some codec devices like the WM8960 or SGTL5000 require separate initialization @@ -103,7 +103,7 @@ Constructor - ``ibuf`` specifies internal buffer length (bytes) For all ports, DMA runs continuously in the background and allows user applications to perform other operations while - sample data is transfered between the internal buffer and the I2S peripheral unit. + sample data is transferred between the internal buffer and the I2S peripheral unit. Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method). diff --git a/docs/library/machine.PWM.rst b/docs/library/machine.PWM.rst index 4b7435577560..b9cf00240314 100644 --- a/docs/library/machine.PWM.rst +++ b/docs/library/machine.PWM.rst @@ -10,7 +10,8 @@ Example usage:: from machine import PWM - pwm = PWM(pin) # create a PWM object on a pin + pwm = PWM(pin, freq=50, duty_u16=8192) # create a PWM object on a pin + # and set freq and duty pwm.duty_u16(32768) # set duty to 50% # reinitialise with a period of 200us, duty of 5us @@ -23,7 +24,7 @@ Example usage:: Constructors ------------ -.. class:: PWM(dest, *, freq, duty_u16, duty_ns) +.. class:: PWM(dest, *, freq, duty_u16, duty_ns, invert) Construct and return a new PWM object using the following parameters: @@ -34,10 +35,12 @@ Constructors PWM cycle. - *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``. - *duty_ns* sets the pulse width in nanoseconds. + - *invert* inverts the respective output if the value is True Setting *freq* may affect other PWM objects if the objects share the same underlying PWM generator (this is hardware specific). Only one of *duty_u16* and *duty_ns* should be specified at a time. + *invert* is not available at all ports. Methods ------- diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 7b0e8cf40689..7c3c4b583265 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -98,7 +98,7 @@ Methods specify them as a tuple of ``pins`` parameter. In the case of hardware SPI the actual clock frequency may be lower than the - requested baudrate. This is dependant on the platform hardware. The actual + requested baudrate. This is dependent on the platform hardware. The actual rate may be determined by printing the SPI object. .. method:: SPI.deinit() diff --git a/docs/library/machine.Timer.rst b/docs/library/machine.Timer.rst index 424a49bcba48..44e659408055 100644 --- a/docs/library/machine.Timer.rst +++ b/docs/library/machine.Timer.rst @@ -38,13 +38,16 @@ Constructors Methods ------- -.. method:: Timer.init(*, mode=Timer.PERIODIC, period=-1, callback=None) +.. method:: Timer.init(*, mode=Timer.PERIODIC, freq=-1, period=-1, callback=None) Initialise the timer. Example:: def mycallback(t): pass + # periodic at 1kHz + tim.init(mode=Timer.PERIODIC, freq=1000, callback=mycallback) + # periodic with 100ms period tim.init(period=100, callback=mycallback) @@ -60,12 +63,17 @@ Methods - ``Timer.PERIODIC`` - The timer runs periodically at the configured frequency of the channel. + - ``freq`` - The timer frequency, in units of Hz. The upper bound of + the frequency is dependent on the port. When both the ``freq`` and + ``period`` arguments are given, ``freq`` has a higher priority and + ``period`` is ignored. + - ``period`` - The timer period, in milliseconds. - ``callback`` - The callable to call upon expiration of the timer period. The callback must take one argument, which is passed the Timer object. The ``callback`` argument shall be specified. Otherwise an exception - will occurr upon timer expiration: + will occur upon timer expiration: ``TypeError: 'NoneType' object isn't callable`` .. method:: Timer.deinit() diff --git a/docs/library/machine.UART.rst b/docs/library/machine.UART.rst index c3eca8f55a69..072bdb7188a3 100644 --- a/docs/library/machine.UART.rst +++ b/docs/library/machine.UART.rst @@ -188,7 +188,7 @@ Methods For the rp2, esp8266 and nrf ports the call returns while the last byte is sent. If required, a one character wait time has to be added in the calling script. - Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra .. method:: UART.txdone() @@ -201,7 +201,7 @@ Methods of a transfer is still being sent. If required, a one character wait time has to be added in the calling script. - Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports + Availability: rp2, esp32, esp8266, mimxrt, cc3200, stm32, nrf ports, renesas-ra Constants --------- diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index 95893cec36be..cf77df963208 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -25,9 +25,8 @@ Constructors Create a WDT object and start it. The timeout must be given in milliseconds. Once it is running the timeout cannot be changed and the WDT cannot be stopped either. - Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout - cannot be specified, it is determined by the underlying system. On rp2040 devices, - the maximum timeout is 8388 ms. + Notes: On the esp8266 a timeout cannot be specified, it is determined by the underlying system. + On rp2040 devices, the maximum timeout is 8388 ms. Methods ------- diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 58430b8e2e08..877def9784f8 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -19,6 +19,44 @@ This is true for both physical devices with IDs >= 0 and "virtual" devices with negative IDs like -1 (these "virtual" devices are still thin shims on top of real hardware and real hardware interrupts). See :ref:`isr_rules`. +Memory access +------------- + +The module exposes three objects used for raw memory access. + +.. data:: mem8 + + Read/write 8 bits of memory. + +.. data:: mem16 + + Read/write 16 bits of memory. + +.. data:: mem32 + + Read/write 32 bits of memory. + +Use subscript notation ``[...]`` to index these objects with the address of +interest. Note that the address is the byte address, regardless of the size of +memory being accessed. + +Example use (registers are specific to an stm32 microcontroller): + +.. code-block:: python3 + + import machine + from micropython import const + + GPIOA = const(0x48000000) + GPIO_BSRR = const(0x18) + GPIO_IDR = const(0x10) + + # set PA2 high + machine.mem32[GPIOA + GPIO_BSRR] = 1 << 2 + + # read PA3 + value = (machine.mem32[GPIOA + GPIO_IDR] >> 3) & 1 + Reset related functions ----------------------- diff --git a/docs/library/neopixel.rst b/docs/library/neopixel.rst index bc3b4e68a40e..543f2588125e 100644 --- a/docs/library/neopixel.rst +++ b/docs/library/neopixel.rst @@ -7,8 +7,10 @@ This module provides a driver for WS2818 / NeoPixel LEDs. .. note:: This module is only included by default on the ESP8266, ESP32 and RP2 - ports. On STM32 / Pyboard, you can `download the module - `_ + ports. On STM32 / Pyboard and others, you can either install the + ``neopixel`` package using :term:`mip`, or you can download the module + directly from + `_ and copy it to the filesystem. class NeoPixel diff --git a/docs/library/network.LAN.rst b/docs/library/network.LAN.rst index 58bd61ebbd87..375e02cefecd 100644 --- a/docs/library/network.LAN.rst +++ b/docs/library/network.LAN.rst @@ -19,7 +19,7 @@ Example usage:: Constructors ------------ -.. class:: LAN(id, *, phy_type=, phy_addr=, phy_clock=) +.. class:: LAN(id, *, phy_type=, phy_addr=, ref_clk_mode=) Create a LAN driver object, initialise the LAN module using the given PHY driver name, and return the LAN object. @@ -31,13 +31,15 @@ Constructors is the default. Suitable values are port specific. - *phy_addr* specifies the address of the PHY interface. As with *phy_type*, the hardwired value has to be used for most boards and that value is the default. - - *phy_clock* specifies, whether the data clock is provided by the Ethernet controller or the PYH interface. - The default value is the one that matches the board. If set to ``True``, the clock is driven by the - Ethernet controller, otherwise by the PHY interface. + - *ref_clk_mode* specifies, whether the data clock is provided by the Ethernet controller or + the PYH interface. + The default value is the one that matches the board. If set to ``LAN.OUT`` or ``Pin.OUT`` + or ``True``, the clock is driven by the Ethernet controller, if set to ``LAN.IN`` + or ``Pin.IN`` or ``False``, the clock is driven by the PHY interface. For example, with the Seeed Arch Mix board you can use:: - nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=2, phy_clock=False) + nic = LAN(0, phy_type=LAN.PHY_LAN8720, phy_addr=1, ref_clk_mode=Pin.IN) Methods ------- diff --git a/docs/library/network.WLAN.rst b/docs/library/network.WLAN.rst index c673194700e5..68cd49769aff 100644 --- a/docs/library/network.WLAN.rst +++ b/docs/library/network.WLAN.rst @@ -130,7 +130,23 @@ Methods hidden Whether SSID is hidden (boolean) security Security protocol supported (enumeration, see module constants) key Access key (string) - hostname The hostname that will be sent to DHCP (STA interfaces) and mDNS (if supported, both STA and AP) + hostname The hostname that will be sent to DHCP (STA interfaces) and mDNS (if supported, both STA and AP). (Deprecated, use :func:`network.hostname` instead) reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited) txpower Maximum transmit power in dBm (integer or float) + pm WiFi Power Management setting (see below for allowed values) ============= =========== + +Constants +--------- + +.. data:: WLAN.PM_PERFORMANCE + WLAN.PM_POWERSAVE + WLAN.PM_NONE + + Allowed values for the ``WLAN.config(pm=...)`` network interface parameter: + + * ``PM_PERFORMANCE``: enable WiFi power management to balance power + savings and WiFi performance + * ``PM_POWERSAVE``: enable WiFi power management with additional power + savings and reduced WiFi performance + * ``PM_NONE``: disable wifi power management diff --git a/docs/library/network.rst b/docs/library/network.rst index 0a6f5506ea41..b13c84123ce7 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -158,12 +158,39 @@ Network functions The following are functions available in the network module. +.. function:: country([code]) + + Get or set the two-letter ISO 3166-1 Alpha-2 country code to be used for + radio compliance. + + If the *code* parameter is provided, the country will be set to this value. + If the function is called without parameters, it returns the current + country. + + The default code ``"XX"`` represents the "worldwide" region. + +.. function:: hostname([name]) + + Get or set the hostname that will identify this device on the network. It is + applied to all interfaces. + + This hostname is used for: + * Sending to the DHCP server in the client request. (If using DHCP) + * Broadcasting via mDNS. (If enabled) + + If the *name* parameter is provided, the hostname will be set to this value. + If the function is called without parameters, it returns the current + hostname. + + The default hostname is typically the name of the board. + .. function:: phy_mode([mode]) Get or set the PHY mode. - If the *mode* parameter is provided, sets the mode to its value. If - the function is called without parameters, returns the current mode. + If the *mode* parameter is provided, the PHY mode will be set to this value. + If the function is called without parameters, it returns the current PHY + mode. The possible modes are defined as constants: * ``MODE_11B`` -- IEEE 802.11b, diff --git a/docs/library/os.rst b/docs/library/os.rst index 19652ee2bc5e..27a7d2d44a05 100644 --- a/docs/library/os.rst +++ b/docs/library/os.rst @@ -86,7 +86,7 @@ Filesystem access .. function:: statvfs(path) - Get the status of a fileystem. + Get the status of a filesystem. Returns a tuple with the filesystem information in the following order: diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 54377091db2b..57a85d54b771 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -252,7 +252,7 @@ Methods For example:: buf = bytearray(8) - lst = [0, 0, 0, memoryview(buf)] + lst = [0, 0, 0, 0, memoryview(buf)] # No heap memory is allocated in the following call can.recv(0, lst) @@ -272,7 +272,7 @@ Methods - *fdf* for CAN FD controllers, if set to True, the frame will have an FD frame format, which supports data payloads up to 64 bytes. - *brs* for CAN FD controllers, if set to True, the bitrate switching mode - is enabled, in which the data phase is transmitted at a differet bitrate. + is enabled, in which the data phase is transmitted at a different bitrate. See :meth:`CAN.init` for the data bit timing configuration parameters. If timeout is 0 the message is placed in a buffer in one of three hardware diff --git a/docs/library/pyb.I2C.rst b/docs/library/pyb.I2C.rst index 24b9cb8c3aaf..71d043aa6d4f 100644 --- a/docs/library/pyb.I2C.rst +++ b/docs/library/pyb.I2C.rst @@ -96,6 +96,10 @@ Methods that DMA transfers have more precise timing but currently do not handle bus errors properly) + The actual clock frequency may be lower than the requested frequency. + This is dependent on the platform hardware. The actual rate may be determined + by printing the I2C object. + .. method:: I2C.is_ready(addr) Check if an I2C device responds to the given address. Only valid when in controller mode. diff --git a/docs/library/random.rst b/docs/library/random.rst index dd8b47c80f08..be56eb088eae 100644 --- a/docs/library/random.rst +++ b/docs/library/random.rst @@ -24,7 +24,7 @@ This module implements a pseudo-random number generator (PRNG). .. note:: The :func:`randrange`, :func:`randint` and :func:`choice` functions are only - available if the ``MICROPY_PY_URANDOM_EXTRA_FUNCS`` configuration option is + available if the ``MICROPY_PY_RANDOM_EXTRA_FUNCS`` configuration option is enabled. @@ -73,7 +73,7 @@ Other Functions supported by the port) initialise the PRNG with a true random number (usually a hardware generated random number). - The ``None`` case only works if ``MICROPY_PY_URANDOM_SEED_INIT_FUNC`` is + The ``None`` case only works if ``MICROPY_PY_RANDOM_SEED_INIT_FUNC`` is enabled by the port, otherwise it raises ``ValueError``. .. function:: choice(sequence) diff --git a/docs/library/rp2.StateMachine.rst b/docs/library/rp2.StateMachine.rst index 7e38ba8b1a75..ee16ce3c513d 100644 --- a/docs/library/rp2.StateMachine.rst +++ b/docs/library/rp2.StateMachine.rst @@ -82,11 +82,18 @@ Methods .. method:: StateMachine.exec(instr) - Execute a single PIO instruction. Uses `asm_pio_encode` to encode the - instruction from the given string *instr*. + Execute a single PIO instruction. + + If *instr* is a string then uses `asm_pio_encode` to encode the instruction + from the given string. >>> sm.exec("set(0, 1)") + If *instr* is an integer then it is treated as an already encoded PIO + machine code instruction to be executed. + + >>> sm.exec(rp2.asm_pio_encode("out(y, 8)", 0)) + .. method:: StateMachine.get(buf=None, shift=0) Pull a word from the state machine's RX FIFO. @@ -99,13 +106,17 @@ Methods .. method:: StateMachine.put(value, shift=0) - Push a word onto the state machine's TX FIFO. + Push words onto the state machine's TX FIFO. + + *value* can be an integer, an array of type ``B``, ``H`` or ``I``, or a + `bytearray`. - If the FIFO is full, it blocks until there is space (i.e. the state machine - pulls a word). + This method will block until all words have been written to the FIFO. If + the FIFO is, or becomes, full, the method will block until the state machine + pulls enough words to complete the write. - The value is first shifted left by *shift* bits, i.e. the state machine - receives ``value << shift``. + Each word is first shifted left by *shift* bits, i.e. the state machine + receives ``word << shift``. .. method:: StateMachine.rx_fifo() diff --git a/docs/library/rp2.rst b/docs/library/rp2.rst index ec7666d7cef4..7a473387b4a8 100644 --- a/docs/library/rp2.rst +++ b/docs/library/rp2.rst @@ -66,6 +66,17 @@ For running PIO programs, see :class:`rp2.StateMachine`. >>> rp2.asm_pio_encode("set(0, 1)", 0) 57345 +.. function:: bootsel_button() + + Temporarily turns the QSPI_SS pin into an input and reads its value, + returning 1 for low and 0 for high. + On a typical RP2040 board with a BOOTSEL button, a return value of 1 + indicates that the button is pressed. + + Since this function temporarily disables access to the external flash + memory, it also temporarily disables interrupts and the other core to + prevent them from trying to execute code from flash. + .. class:: PIOASMError This exception is raised from `asm_pio()` or `asm_pio_encode()` if there is diff --git a/docs/library/socket.rst b/docs/library/socket.rst index 1d1c23abd197..944e7e631ac7 100644 --- a/docs/library/socket.rst +++ b/docs/library/socket.rst @@ -29,7 +29,7 @@ returned by `getaddrinfo` function, which must be used to resolve textual addres # You must use getaddrinfo() even for numeric addresses sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1] # Now you can use that address - sock.connect(addr) + sock.connect(sockaddr) Using `getaddrinfo` is the most efficient (both in terms of memory and processing power) and portable way to work with addresses. diff --git a/docs/library/ssl.rst b/docs/library/ssl.rst index 924b03b3541b..e3dfa9d99366 100644 --- a/docs/library/ssl.rst +++ b/docs/library/ssl.rst @@ -15,36 +15,53 @@ Functions .. function:: ssl.wrap_socket(sock, server_side=False, keyfile=None, certfile=None, cert_reqs=CERT_NONE, cadata=None, server_hostname=None, do_handshake=True) + Wrap the given *sock* and return a new wrapped-socket object. The implementation + of this function is to first create an `SSLContext` and then call the `SSLContext.wrap_socket` + method on that context object. The arguments *sock*, *server_side* and *server_hostname* are + passed through unchanged to the method call. The argument *do_handshake* is passed through as + *do_handshake_on_connect*. The remaining arguments have the following behaviour: + + - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. + Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not + validate any certificate, only ``ssl.CERT_REQUIRED`` will. + + - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will + validate the peer's certificate. Currently only a single DER-encoded certificate is supported. + + Depending on the underlying module implementation in a particular + :term:`MicroPython port`, some or all keyword arguments above may be not supported. + +class SSLContext +---------------- + +.. class:: SSLContext(protocol, /) + + Create a new SSLContext instance. The *protocol* argument must be one of the ``PROTOCOL_*`` + constants. + +.. method:: SSLContext.wrap_socket(sock, *, server_side=False, do_handshake_on_connect=True, server_hostname=None) + Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type), - and returns an instance of ssl.SSLSocket, which wraps the underlying stream in - an SSL context. Returned object has the usual `stream` interface methods like + and returns an instance of ssl.SSLSocket, wrapping the underlying stream. + The returned object has the usual `stream` interface methods like ``read()``, ``write()``, etc. - A server-side SSL socket should be created from a normal socket returned from - :meth:`~socket.socket.accept()` on a non-SSL listening server socket. - - *do_handshake* determines whether the handshake is done as part of the ``wrap_socket`` + - *server_side* selects whether the wrapped socket is on the server or client side. + A server-side SSL socket should be created from a normal socket returned from + :meth:`~socket.socket.accept()` on a non-SSL listening server socket. + + - *do_handshake_on_connect* determines whether the handshake is done as part of the ``wrap_socket`` or whether it is deferred to be done as part of the initial reads or writes - (there is no ``do_handshake`` method as in CPython). For blocking sockets doing the handshake immediately is standard. For non-blocking sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode) the handshake should generally be deferred because otherwise ``wrap_socket`` blocks until it completes. Note that in AXTLS the handshake can be deferred until the first read or write but it then blocks until completion. - - *cert_reqs* determines whether the peer (server or client) must present a valid certificate. - Note that for mbedtls based ports, ``ssl.CERT_NONE`` and ``ssl.CERT_OPTIONAL`` will not - validate any certificate, only ``ssl.CERT_REQUIRED`` will. - - - *cadata* is a bytes object containing the CA certificate chain (in DER format) that will - validate the peer's certificate. Currently only a single DER-encoded certificate is supported. - - *server_hostname* is for use as a client, and sets the hostname to check against the received server certificate. It also sets the name for Server Name Indication (SNI), allowing the server to present the proper certificate. - Depending on the underlying module implementation in a particular - :term:`MicroPython port`, some or all keyword arguments above may be not supported. - .. warning:: Some implementations of ``ssl`` module do NOT validate server certificates, @@ -55,6 +72,11 @@ Functions returns an object more similar to CPython's ``SSLObject`` which does not have these socket methods. +.. attribute:: SSLContext.verify_mode + + Set or get the behaviour for verification of peer certificates. Must be one of the + ``CERT_*`` constants. + Exceptions ---------- @@ -65,8 +87,14 @@ Exceptions Constants --------- +.. data:: ssl.PROTOCOL_TLS_CLIENT + ssl.PROTOCOL_TLS_SERVER + + Supported values for the *protocol* parameter. + .. data:: ssl.CERT_NONE ssl.CERT_OPTIONAL ssl.CERT_REQUIRED - Supported values for *cert_reqs* parameter. + Supported values for *cert_reqs* parameter, and the :attr:`SSLContext.verify_mode` + attribute. diff --git a/docs/library/struct.rst b/docs/library/struct.rst index 92757aba8d50..026cb5e8ac3b 100644 --- a/docs/library/struct.rst +++ b/docs/library/struct.rst @@ -6,11 +6,58 @@ |see_cpython_module| :mod:`python:struct`. -Supported size/byte order prefixes: ``@``, ``<``, ``>``, ``!``. - -Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``, -``L``, ``q``, ``Q``, ``s``, ``P``, ``f``, ``d`` (the latter 2 depending -on the floating-point support). +The following byte orders are supported: + ++-----------+------------------------+----------+-----------+ +| Character | Byte order | Size | Alignment | ++===========+========================+==========+===========+ +| @ | native | native | native | ++-----------+------------------------+----------+-----------+ +| < | little-endian | standard | none | ++-----------+------------------------+----------+-----------+ +| > | big-endian | standard | none | ++-----------+------------------------+----------+-----------+ +| ! | network (= big-endian) | standard | none | ++-----------+------------------------+----------+-----------+ + +The following data types are supported: + ++--------+--------------------+-------------------+---------------+ +| Format | C Type | Python type | Standard size | ++========+====================+===================+===============+ +| b | signed char | integer | 1 | ++--------+--------------------+-------------------+---------------+ +| B | unsigned char | integer | 1 | ++--------+--------------------+-------------------+---------------+ +| h | short | integer | 2 | ++--------+--------------------+-------------------+---------------+ +| H | unsigned short | integer | 2 | ++--------+--------------------+-------------------+---------------+ +| i | int | integer (`1`) | 4 | ++--------+--------------------+-------------------+---------------+ +| I | unsigned int | integer (`1`) | 4 | ++--------+--------------------+-------------------+---------------+ +| l | long | integer (`1`) | 4 | ++--------+--------------------+-------------------+---------------+ +| L | unsigned long | integer (`1`) | 4 | ++--------+--------------------+-------------------+---------------+ +| q | long long | integer (`1`) | 8 | ++--------+--------------------+-------------------+---------------+ +| Q | unsigned long long | integer (`1`) | 8 | ++--------+--------------------+-------------------+---------------+ +| f | float | float (`2`) | 4 | ++--------+--------------------+-------------------+---------------+ +| d | double | float (`2`) | 8 | ++--------+--------------------+-------------------+---------------+ +| s | char[] | bytes | | ++--------+--------------------+-------------------+---------------+ +| P | void * | integer | | ++--------+--------------------+-------------------+---------------+ + +.. _fn: + +(1) Requires long support when used with values larger than 30 bits. +(2) Requires floating point support. .. admonition:: Difference to CPython :class: attention @@ -43,5 +90,5 @@ Functions .. function:: unpack_from(fmt, data, offset=0, /) Unpack from the *data* starting at *offset* according to the format string - *fmt*. *offset* may be negative to count from the end of *buffer*. The return + *fmt*. *offset* may be negative to count from the end of *data*. The return value is a tuple of the unpacked values. diff --git a/docs/library/sys.rst b/docs/library/sys.rst index 3efdce964ce0..c8eb4b5c502b 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -46,7 +46,7 @@ Functions .. function:: settrace(tracefunc) Enable tracing of bytecode execution. For details see the `CPython - documentaion `_. + documentation `_. This function requires a custom MicroPython build as it is typically not present in pre-built firmware (due to it affecting performance). The relevant diff --git a/docs/library/time.rst b/docs/library/time.rst index 3ab5caf248c6..8c1c1d4d6fb2 100644 --- a/docs/library/time.rst +++ b/docs/library/time.rst @@ -163,8 +163,8 @@ Functions However, values returned by `ticks_ms()`, etc. functions may wrap around, so directly using subtraction on them will produce incorrect result. That is why `ticks_diff()` is needed, it implements modular (or more specifically, ring) - arithmetics to produce correct result even for wrap-around values (as long as they not - too distant inbetween, see below). The function returns **signed** value in the range + arithmetic to produce correct result even for wrap-around values (as long as they not + too distant in between, see below). The function returns **signed** value in the range [*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for two's-complement signed binary integers). If the result is negative, it means that *ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that @@ -183,7 +183,7 @@ Functions has passed. To avoid this mistake, just look at the clock regularly. Your application should do the same. "Too long sleep" metaphor also maps directly to application behaviour: don't let your application run any single task for too long. Run tasks - in steps, and do time-keeping inbetween. + in steps, and do time-keeping in between. `ticks_diff()` is designed to accommodate various usage patterns, among them: diff --git a/docs/library/uasyncio.rst b/docs/library/uasyncio.rst deleted file mode 100644 index 859d505d79a9..000000000000 --- a/docs/library/uasyncio.rst +++ /dev/null @@ -1,359 +0,0 @@ -:mod:`uasyncio` --- asynchronous I/O scheduler -============================================== - -.. module:: uasyncio - :synopsis: asynchronous I/O scheduler for writing concurrent code - -|see_cpython_module| -`asyncio `_ - -Example:: - - import uasyncio - - async def blink(led, period_ms): - while True: - led.on() - await uasyncio.sleep_ms(5) - led.off() - await uasyncio.sleep_ms(period_ms) - - async def main(led1, led2): - uasyncio.create_task(blink(led1, 700)) - uasyncio.create_task(blink(led2, 400)) - await uasyncio.sleep_ms(10_000) - - # Running on a pyboard - from pyb import LED - uasyncio.run(main(LED(1), LED(2))) - - # Running on a generic board - from machine import Pin - uasyncio.run(main(Pin(1), Pin(2))) - -Core functions --------------- - -.. function:: create_task(coro) - - Create a new task from the given coroutine and schedule it to run. - - Returns the corresponding `Task` object. - -.. function:: current_task() - - Return the `Task` object associated with the currently running task. - -.. function:: run(coro) - - Create a new task from the given coroutine and run it until it completes. - - Returns the value returned by *coro*. - -.. function:: sleep(t) - - Sleep for *t* seconds (can be a float). - - This is a coroutine. - -.. function:: sleep_ms(t) - - Sleep for *t* milliseconds. - - This is a coroutine, and a MicroPython extension. - -Additional functions --------------------- - -.. function:: wait_for(awaitable, timeout) - - Wait for the *awaitable* to complete, but cancel it if it takes longer - than *timeout* seconds. If *awaitable* is not a task then a task will be - created from it. - - If a timeout occurs, it cancels the task and raises ``uasyncio.TimeoutError``: - this should be trapped by the caller. The task receives - ``uasyncio.CancelledError`` which may be ignored or trapped using ``try...except`` - or ``try...finally`` to run cleanup code. - - Returns the return value of *awaitable*. - - This is a coroutine. - -.. function:: wait_for_ms(awaitable, timeout) - - Similar to `wait_for` but *timeout* is an integer in milliseconds. - - This is a coroutine, and a MicroPython extension. - -.. function:: gather(*awaitables, return_exceptions=False) - - Run all *awaitables* concurrently. Any *awaitables* that are not tasks are - promoted to tasks. - - Returns a list of return values of all *awaitables*. - - This is a coroutine. - -class Task ----------- - -.. class:: Task() - - This object wraps a coroutine into a running task. Tasks can be waited on - using ``await task``, which will wait for the task to complete and return - the return value of the task. - - Tasks should not be created directly, rather use `create_task` to create them. - -.. method:: Task.cancel() - - Cancel the task by injecting ``uasyncio.CancelledError`` into it. The task may - ignore this exception. Cleanup code may be run by trapping it, or via - ``try ... finally``. - -class Event ------------ - -.. class:: Event() - - Create a new event which can be used to synchronise tasks. Events start - in the cleared state. - -.. method:: Event.is_set() - - Returns ``True`` if the event is set, ``False`` otherwise. - -.. method:: Event.set() - - Set the event. Any tasks waiting on the event will be scheduled to run. - - Note: This must be called from within a task. It is not safe to call this - from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`. - -.. method:: Event.clear() - - Clear the event. - -.. method:: Event.wait() - - Wait for the event to be set. If the event is already set then it returns - immediately. - - This is a coroutine. - -class ThreadSafeFlag --------------------- - -.. class:: ThreadSafeFlag() - - Create a new flag which can be used to synchronise a task with code running - outside the uasyncio loop, such as other threads, IRQs, or scheduler - callbacks. Flags start in the cleared state. - -.. method:: ThreadSafeFlag.set() - - Set the flag. If there is a task waiting on the flag, it will be scheduled - to run. - -.. method:: ThreadSafeFlag.clear() - - Clear the flag. This may be used to ensure that a possibly previously-set - flag is clear before waiting for it. - -.. method:: ThreadSafeFlag.wait() - - Wait for the flag to be set. If the flag is already set then it returns - immediately. The flag is automatically reset upon return from ``wait``. - - A flag may only be waited on by a single task at a time. - - This is a coroutine. - -class Lock ----------- - -.. class:: Lock() - - Create a new lock which can be used to coordinate tasks. Locks start in - the unlocked state. - - In addition to the methods below, locks can be used in an ``async with`` statement. - -.. method:: Lock.locked() - - Returns ``True`` if the lock is locked, otherwise ``False``. - -.. method:: Lock.acquire() - - Wait for the lock to be in the unlocked state and then lock it in an atomic - way. Only one task can acquire the lock at any one time. - - This is a coroutine. - -.. method:: Lock.release() - - Release the lock. If any tasks are waiting on the lock then the next one in the - queue is scheduled to run and the lock remains locked. Otherwise, no tasks are - waiting an the lock becomes unlocked. - -TCP stream connections ----------------------- - -.. function:: open_connection(host, port) - - Open a TCP connection to the given *host* and *port*. The *host* address will be - resolved using `socket.getaddrinfo`, which is currently a blocking call. - - Returns a pair of streams: a reader and a writer stream. - Will raise a socket-specific ``OSError`` if the host could not be resolved or if - the connection could not be made. - - This is a coroutine. - -.. function:: start_server(callback, host, port, backlog=5) - - Start a TCP server on the given *host* and *port*. The *callback* will be - called with incoming, accepted connections, and be passed 2 arguments: reader - and writer streams for the connection. - - Returns a `Server` object. - - This is a coroutine. - -.. class:: Stream() - - This represents a TCP stream connection. To minimise code this class implements - both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to - this class. - -.. method:: Stream.get_extra_info(v) - - Get extra information about the stream, given by *v*. The valid values for *v* are: - ``peername``. - -.. method:: Stream.close() - - Close the stream. - -.. method:: Stream.wait_closed() - - Wait for the stream to close. - - This is a coroutine. - -.. method:: Stream.read(n=-1) - - Read up to *n* bytes and return them. If *n* is not provided or -1 then read all - bytes until EOF. The returned value will be an empty bytes object if EOF is - encountered before any bytes are read. - - This is a coroutine. - -.. method:: Stream.readinto(buf) - - Read up to n bytes into *buf* with n being equal to the length of *buf*. - - Return the number of bytes read into *buf*. - - This is a coroutine, and a MicroPython extension. - -.. method:: Stream.readexactly(n) - - Read exactly *n* bytes and return them as a bytes object. - - Raises an ``EOFError`` exception if the stream ends before reading *n* bytes. - - This is a coroutine. - -.. method:: Stream.readline() - - Read a line and return it. - - This is a coroutine. - -.. method:: Stream.write(buf) - - Accumulated *buf* to the output buffer. The data is only flushed when - `Stream.drain` is called. It is recommended to call `Stream.drain` immediately - after calling this function. - -.. method:: Stream.drain() - - Drain (write) all buffered output data out to the stream. - - This is a coroutine. - -.. class:: Server() - - This represents the server class returned from `start_server`. It can be used - in an ``async with`` statement to close the server upon exit. - -.. method:: Server.close() - - Close the server. - -.. method:: Server.wait_closed() - - Wait for the server to close. - - This is a coroutine. - -Event Loop ----------- - -.. function:: get_event_loop() - - Return the event loop used to schedule and run tasks. See `Loop`. - -.. function:: new_event_loop() - - Reset the event loop and return it. - - Note: since MicroPython only has a single event loop this function just - resets the loop's state, it does not create a new one. - -.. class:: Loop() - - This represents the object which schedules and runs tasks. It cannot be - created, use `get_event_loop` instead. - -.. method:: Loop.create_task(coro) - - Create a task from the given *coro* and return the new `Task` object. - -.. method:: Loop.run_forever() - - Run the event loop until `stop()` is called. - -.. method:: Loop.run_until_complete(awaitable) - - Run the given *awaitable* until it completes. If *awaitable* is not a task - then it will be promoted to one. - -.. method:: Loop.stop() - - Stop the event loop. - -.. method:: Loop.close() - - Close the event loop. - -.. method:: Loop.set_exception_handler(handler) - - Set the exception handler to call when a Task raises an exception that is not - caught. The *handler* should accept two arguments: ``(loop, context)``. - -.. method:: Loop.get_exception_handler() - - Get the current exception handler. Returns the handler, or ``None`` if no - custom handler is set. - -.. method:: Loop.default_exception_handler(context) - - The default exception handler that is called. - -.. method:: Loop.call_exception_handler(context) - - Call the current exception handler. The argument *context* is passed through and - is a dictionary containing keys: ``'message'``, ``'exception'``, ``'future'``. diff --git a/docs/library/zephyr.DiskAccess.rst b/docs/library/zephyr.DiskAccess.rst index d19d81a962e2..3e5fa9a3575a 100644 --- a/docs/library/zephyr.DiskAccess.rst +++ b/docs/library/zephyr.DiskAccess.rst @@ -34,5 +34,5 @@ Methods These methods implement the simple and extended :ref:`block protocol ` defined by - :class:`uos.AbstractBlockDev`. + :class:`os.AbstractBlockDev`. diff --git a/docs/library/zephyr.FlashArea.rst b/docs/library/zephyr.FlashArea.rst index 306347d449ea..9cd4dd59d685 100644 --- a/docs/library/zephyr.FlashArea.rst +++ b/docs/library/zephyr.FlashArea.rst @@ -37,4 +37,4 @@ Methods These methods implement the simple and extended :ref:`block protocol ` defined by - :class:`uos.AbstractBlockDev`. + :class:`os.AbstractBlockDev`. diff --git a/docs/library/zephyr.rst b/docs/library/zephyr.rst index da3d14a093ec..10676d908528 100644 --- a/docs/library/zephyr.rst +++ b/docs/library/zephyr.rst @@ -32,7 +32,7 @@ Functions * *CPU utilization is only printed if runtime statistics are configured via the ``CONFIG_THREAD_RUNTIME_STATS`` kconfig* This function can only be accessed if ``CONFIG_THREAD_ANALYZER`` is configured for the port in ``zephyr/prj.conf``. - For more infomation, see documentation for Zephyr `thread analyzer + For more information, see documentation for Zephyr `thread analyzer `_. .. function:: shell_exec(cmd_in) diff --git a/docs/library/zlib.rst b/docs/library/zlib.rst index 96d6c245232b..54310b72f2a3 100644 --- a/docs/library/zlib.rst +++ b/docs/library/zlib.rst @@ -1,38 +1,82 @@ -:mod:`zlib` -- zlib decompression -================================= +:mod:`zlib` -- zlib compression & decompression +=============================================== .. module:: zlib - :synopsis: zlib decompression + :synopsis: zlib compression & decompression |see_cpython_module| :mod:`python:zlib`. -This module allows to decompress binary data compressed with +This module allows compression and decompression of binary data with the `DEFLATE algorithm `_ -(commonly used in zlib library and gzip archiver). Compression -is not yet implemented. +(commonly used in the zlib library and gzip archiver). + +.. note:: Prefer to use :class:`deflate.DeflateIO` instead of the functions in this + module as it provides a streaming interface to compression and decompression + which is convenient and more memory efficient when working with reading or + writing compressed data to a file, socket, or stream. + +**Availability:** + +* From MicroPython v1.21 onwards, this module may not be present by default on + all MicroPython firmware as it duplicates functionality available in + the :mod:`deflate ` module. + +* A copy of this module can be installed (or frozen) + from :term:`micropython-lib` (`source `_). + See :ref:`packages` for more information. This documentation describes that module. + +* Requires the built-in :mod:`deflate ` module (available since MicroPython v1.21) + +* Compression support will only be available if compression support is enabled + in the built-in :mod:`deflate ` module. Functions --------- -.. function:: decompress(data, wbits=0, bufsize=0, /) +.. function:: decompress(data, wbits=15, /) + + Decompresses *data* into a bytes object. + + The *wbits* parameter works the same way as for :meth:`zlib.compress` + with the following additional valid values: + + * ``0``: Automatically determine the window size from the zlib header + (*data* must be in zlib format). + * ``35`` to ``47``: Auto-detect either the zlib or gzip format. + + As for :meth:`zlib.compress`, see the :mod:`CPython documentation for zlib ` + for more information about the *wbits* parameter. As for :meth:`zlib.compress`, + MicroPython also supports smaller window sizes than CPython. See more + :ref:`MicroPython-specific details ` in the + :mod:`deflate ` module documentation. + + If the data to be decompressed requires a larger window size, it will + fail during decompression. + +.. function:: compress(data, wbits=15, /) - Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window - size used during compression (8-15, the dictionary size is power of 2 of - that value). Additionally, if value is positive, *data* is assumed to be - zlib stream (with zlib header). Otherwise, if it's negative, it's assumed - to be raw DEFLATE stream. *bufsize* parameter is for compatibility with - CPython and is ignored. + Compresses *data* into a bytes object. -.. class:: DecompIO(stream, wbits=0, /) + *wbits* allows you to configure the DEFLATE dictionary window size and the + output format. The window size allows you to trade-off memory usage for + compression level. A larger window size will allow the compressor to + reference fragments further back in the input. The output formats are "raw" + DEFLATE (no header/footer), zlib, and gzip, where the latter two + include a header and checksum. - Create a `stream` wrapper which allows transparent decompression of - compressed data in another *stream*. This allows to process compressed - streams with data larger than available heap size. In addition to - values described in :func:`decompress`, *wbits* may take values - 24..31 (16 + 8..15), meaning that input stream has gzip header. + The low four bits of the absolute value of *wbits* set the base-2 logarithm of + the DEFLATE dictionary window size. So for example, ``wbits=10``, + ``wbits=-10``, and ``wbits=26`` all set the window size to 1024 bytes. Valid + window sizes are ``5`` to ``15`` inclusive (corresponding to 32 to 32k bytes). - .. admonition:: Difference to CPython - :class: attention + Negative values of *wbits* between ``-5`` and ``-15`` correspond to "raw" + output mode, positive values between ``5`` and ``15`` correspond to zlib + output mode, and positive values between ``21`` and ``31`` correspond to + gzip output mode. - This class is MicroPython extension. It's included on provisional - basis and may be changed considerably or removed in later versions. + See the :mod:`CPython documentation for zlib ` for more + information about the *wbits* parameter. Note that MicroPython allows + for smaller window sizes, which is useful when memory is constrained while + still achieving a reasonable level of compression. It also speeds up + the compressor. See more :ref:`MicroPython-specific details ` + in the :mod:`deflate ` module documentation. diff --git a/docs/mimxrt/pinout.rst b/docs/mimxrt/pinout.rst index ef53fa63bff2..b5a7fbbfe08c 100644 --- a/docs/mimxrt/pinout.rst +++ b/docs/mimxrt/pinout.rst @@ -14,9 +14,9 @@ The pin assignment of UARTs to pins is fixed. The UARTs are numbered 0..8. The rx/tx pins are assigned according to the tables below: -================ =========== =========== =========== =========== +================= =========== =========== =========== =========== Board / Pin UART0 UART1 UART2 UART3 -================ =========== =========== =========== =========== +================= =========== =========== =========== =========== Teensy 4.0 - 0/1 7/8 14/15 Teensy 4.1 - 0/1 7/8 14/15 MIMXRT1010-EVK Debug USB D0/D1 D7/D6 - @@ -27,9 +27,10 @@ MIMXRT1050-EVKB Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1060-EVK Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1064-EVK Debug USB D0/D1 D7/D6 D8/D9 MIMXRT1170-EVK Debug USB D0/D1 D12/D11 D10/D13 +Adafruit Metro M7 - D0/D1 D7/D3 A1/A0 Olimex RT1010Py - RxD/TxD D5/D6 - -Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07 -================ =========== =========== =========== =========== +Seeed ARCH MIX - J3_19/J3_20 J4_16/J4_17 J4_06/J4_07 +================= =========== =========== =========== =========== | @@ -61,38 +62,38 @@ PWM pin assignment Pins are specified in the same way as for the Pin class. The following tables show the assignment of the board Pins to PWM modules: -=========== ========== ========== ====== ============== ====== -Pin/ MIMXRT 1010 1015 1020 1050/1060/1064 1170 -=========== ========== ========== ====== ============== ====== -D0 - Q1/1 F1/1/B - - -D1 - Q1/0 F1/1/A - - -D2 F1/3/B F1/3/A - F1/3/B - -D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A -D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A Q4/2 -D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B -D6 - F1/2/B F2/0/A Q3/2 F1/0/A -D7 - - F1/0/A Q3/3 - -D8 F1/0/A F1/1/B F1/0/B F1/1/X Q4/3 -D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B -D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B -D11 F1/2/A - F2/1/A F1/1/A (*) - -D12 F1/2/B - F2/1/B F1/1/B (*) - -D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A -D14 F1/0/B - - F2/3/B - -D15 F1/0/A - - F2/3/A - -A0 - - F1/2/A - - -A1 F1/3/X F1/3/B F1/2/B - - -A2 F1/2/X F1/3/A F1/3/A - - -A3 - F1/2/A F1/3/B - - -A4 - - - Q3/1 - -A5 - - - Q3/0 - -D31 - - - - F1/2/B -D32 - - - - F1/2/A -D33 - - - - F1/1/B -D34 - - - - F1/1/A -D35 - - - - F1/0/B -D36 - - - - F1/0/A -=========== ========== ========== ====== ============== ====== +=========== ========== ========== ====== ========== ====== ======== +Pin/ MIMXRT 1010 1015 1020 1050/60/64 1170 Metro M7 +=========== ========== ========== ====== ========== ====== ======== +D0 - Q1/1 F1/1/B - - - +D1 - Q1/0 F1/1/A - - - +D2 F1/3/B F1/3/A - F1/3/B - - +D3 F1/3/A F1/0/A F2/3/B F4/0/A F1/2/A - +D4 F1/3/A (*) Q1/2 Q2/1 F2/3/A Q4/2 F1/0/B +D5 F1/0/B (*) F1/0/B F2/3/A F1/3/A F1/2/B F1/0/A +D6 - F1/2/B F2/0/A Q3/2 F1/0/A - +D7 - - F1/0/A Q3/3 - - +D8 F1/0/A F1/1/B F1/0/B F1/1/X Q4/3 F1/3/A +D9 F1/1/B (*) F1/2/A F2/0/B F1/0/X F1/0/B F1/3/B +D10 F1/3/B - F2/2/B F1/0/B (*) F2/2/B F1/2/A +D11 F1/2/A - F2/1/A F1/1/A (*) - F1/2/B +D12 F1/2/B - F2/1/B F1/1/B (*) - F1/1/A +D13 F1/3/A - F2/2/A F1/0/A (*) F2/2/A F1/1/B +D14 F1/0/B - - F2/3/B - F1/0/B +D15 F1/0/A - - F2/3/A - F1/0/A +A0 - - F1/2/A - - - +A1 F1/3/X F1/3/B F1/2/B - - - +A2 F1/2/X F1/3/A F1/3/A - - - +A3 - F1/2/A F1/3/B - - F1/3/B +A4 - - - Q3/1 - F1/2/X +A5 - - - Q3/0 - - +D31 - - - - F1/2/B - +D32 - - - - F1/2/A - +D33 - - - - F1/1/B - +D34 - - - - F1/1/A - +D35 - - - - F1/0/B - +D36 - - - - F1/0/A - +=========== ========== ========== ====== ========== ====== ======== Pins denoted with (*) are by default not wired at the board. @@ -318,6 +319,7 @@ MIXMXRT1050-EVKB D10/-/D11/D12/D13 (*) - - MIXMXRT1060-EVK D10/-/D11/D12/D13 (*) - - MIXMXRT1064-EVK D10/-/D11/D12/D13 (*) - - MIXMXRT1170-EVK D10/-/D11/D12/D13 D28/-/D25/D24/D26 -/-/D14/D15/D24 +Adafruit Metro M7 -/-/MOSI/MISO/SCK - - Olimex RT1010Py - CS0/-/SDO/SDI/SCK SDCARD with CS1 Seeed ARCH MIX J4_12/-/J4_14/J4_13/J4_15 J3_09/J3_05/J3_08_J3_11 ================= ========================= ======================= =============== @@ -350,6 +352,7 @@ MIXMXRT1050-EVKB A4/A5 D1/D0 - - - MIXMXRT1060-EVK A4/A5 D1/D0 - - - MIXMXRT1064-EVK A4/A5 D1/D0 - - - MIXMXRT1170-EVK D14/D15 D1/D0 A4/A5 D26/D25 D19/D18 +Adafruit Metro M7 D14/D15 D0/D1 Olimex RT1010Py - SDA1/SCL1 SDA2/SCL2 - - Seeed ARCH MIX J3_17/J3_16 J4_06/J4_07 J5_05/J5_04 - - ================= =========== =========== =========== ======= ======= @@ -364,18 +367,19 @@ Hardware I2S pin assignment Pin assignments for a few MIMXRT boards: -=============== == ===== ======== ======= ======= ======== ======= ======= -Board ID MCK SCK_TX WS_TX SD_TX SCK_RX WS_RX SD_RX -=============== == ===== ======== ======= ======= ======== ======= ======= -Teensy 4.0 1 23 26 27 7 21 20 8 -Teensy 4.0 2 33 4 3 2 - - 5 -Teensy 4.1 1 23 26 27 7 21 20 8 -Teensy 4.1 2 33 4 3 2 - - 5 -Seeed Arch MIX 1 J4_09 J4_14 J4_15 J14_13 J4_11 J4_10 J4_10 -Olimex RT1010Py 1 D8 D6 D7 D4 D1 D2 D3 -Olimex RT1010Py 3 - D10 D9 D11 - - - -MIMXRT_DEV 1 "MCK" "SCK_TX" "WS_TX" "SD_TX" "SCK_RX" "WS_RX" "SD_RX" -=============== == ===== ======== ======= ======= ======== ======= ======= +================= == ===== ======== ======= ======= ======== ======= ======= +Board ID MCK SCK_TX WS_TX SD_TX SCK_RX WS_RX SD_RX +================= == ===== ======== ======= ======= ======== ======= ======= +Teensy 4.0 1 23 26 27 7 21 20 8 +Teensy 4.0 2 33 4 3 2 - - 5 +Teensy 4.1 1 23 26 27 7 21 20 8 +Teensy 4.1 2 33 4 3 2 - - 5 +Seeed Arch MIX 1 J4_09 J4_14 J4_15 J14_13 J4_11 J4_10 J4_10 +Adafruit Metro M7 1 D8 D10 D9 D12 D14 D15 D13 +Olimex RT1010Py 1 D8 D6 D7 D4 D1 D2 D3 +Olimex RT1010Py 3 - D10 D9 D11 - - - +MIMXRT_DEV 1 "MCK" "SCK_TX" "WS_TX" "SD_TX" "SCK_RX" "WS_RX" "SD_RX" +================= == ===== ======== ======= ======= ======== ======= ======= Symbolic pin names are provided for the MIMXRT_10xx_DEV boards. -These are provided for the other boards as well. \ No newline at end of file +These are provided for the other boards as well. diff --git a/docs/mimxrt/quickref.rst b/docs/mimxrt/quickref.rst index c75fe60c8d66..ab8bf8831bbb 100644 --- a/docs/mimxrt/quickref.rst +++ b/docs/mimxrt/quickref.rst @@ -56,21 +56,18 @@ Use the :mod:`time