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
+
+ Quick reference for the SAMD21/SAMD51
+ general information for SAMD21/SAMD51 based boards, snippets of useful code, and a tutorial
+
diff --git a/docs/zephyr/quickref.rst b/docs/zephyr/quickref.rst
index 783621316c70..57262ffb5c63 100644
--- a/docs/zephyr/quickref.rst
+++ b/docs/zephyr/quickref.rst
@@ -19,7 +19,7 @@ See the corresponding section of the tutorial: :ref:`intro`.
Delay and timing
----------------
-Use the :mod:`time ` module::
+Use the :mod:`time ` module::
import time
@@ -151,7 +151,7 @@ Use the :ref:`zsensor.Sensor ` class to access sensor data::
accel.measure() # obtain a measurement reading from the accelerometer
# each of these prints the value taken by measure()
- accel.float(zsensor.ACCEL_X) # print measurement value for accelerometer X-axis sensor channel as float
- accel.millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths
- accel.micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths
- accel.int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel
+ accel.get_float(zsensor.ACCEL_X) # print measurement value for accelerometer X-axis sensor channel as float
+ accel.get_millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths
+ accel.get_micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths
+ accel.get_int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel
diff --git a/docs/zephyr/tutorial/repl.rst b/docs/zephyr/tutorial/repl.rst
index 8cd57c9435bf..2c091f7ee94f 100644
--- a/docs/zephyr/tutorial/repl.rst
+++ b/docs/zephyr/tutorial/repl.rst
@@ -10,7 +10,7 @@ REPL over the serial port
The REPL is available on a UART serial peripheral specified for the board by
the ``zephyr,console`` devicetree node. 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.
To access the prompt over USB-serial you will need to use a terminal emulator
diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h
index 7dfaaf3d40c6..009f55b159d4 100644
--- a/drivers/bus/qspi.h
+++ b/drivers/bus/qspi.h
@@ -41,10 +41,10 @@ enum {
typedef struct _mp_qspi_proto_t {
int (*ioctl)(void *self, uint32_t cmd);
- void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
- void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
- uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len);
- void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);
+ int (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data);
+ int (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src);
+ int (*read_cmd)(void *self, uint8_t cmd, size_t len, uint32_t *dest);
+ int (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest);
} mp_qspi_proto_t;
typedef struct _mp_soft_qspi_obj_t {
diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c
index 71ab559768b1..dc205da3a7c4 100644
--- a/drivers/bus/softqspi.c
+++ b/drivers/bus/softqspi.c
@@ -158,15 +158,16 @@ STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint
//mp_hal_pin_input(self->io1);
}
-STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
+STATIC int mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd | data << 8;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL);
CS_HIGH(self);
+ return 0;
}
-STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
+STATIC int mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[5] = {cmd};
uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr);
@@ -174,18 +175,20 @@ STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_
mp_soft_qspi_transfer(self, addr_len + 1, cmd_buf, NULL);
mp_soft_qspi_transfer(self, len, src, NULL);
CS_HIGH(self);
+ return 0;
}
-STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) {
+STATIC int mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len, uint32_t *dest) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint32_t cmd_buf = cmd;
CS_LOW(self);
mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf);
CS_HIGH(self);
- return cmd_buf >> 8;
+ *dest = cmd_buf >> 8;
+ return 0;
}
-STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
+STATIC int mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) {
mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in;
uint8_t cmd_buf[7] = {cmd};
uint8_t addr_len = mp_spi_set_addr_buff(&cmd_buf[1], addr);
@@ -194,6 +197,7 @@ STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32
mp_soft_qspi_qwrite(self, addr_len + 3, &cmd_buf[1]); // 3/4 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles)
mp_soft_qspi_qread(self, len, dest);
CS_HIGH(self);
+ return 0;
}
const mp_qspi_proto_t mp_soft_qspi_proto = {
diff --git a/drivers/cyw43/cyw43.h b/drivers/cyw43/cyw43.h
deleted file mode 100644
index 5ca4898318a3..000000000000
--- a/drivers/cyw43/cyw43.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_STM32_CYW43_H
-#define MICROPY_INCLUDED_STM32_CYW43_H
-
-#include "lwip/netif.h"
-#include "lwip/dhcp.h"
-#include "shared/netutils/dhcpserver.h"
-#include "drivers/cyw43/cyw43_ll.h"
-
-// For trace_flags
-#define CYW43_TRACE_ASYNC_EV (0x0001)
-#define CYW43_TRACE_ETH_TX (0x0002)
-#define CYW43_TRACE_ETH_RX (0x0004)
-#define CYW43_TRACE_ETH_FULL (0x0008)
-#define CYW43_TRACE_MAC (0x0010)
-
-// Return value of cyw43_wifi_link_status
-#define CYW43_LINK_DOWN (0)
-#define CYW43_LINK_JOIN (1)
-#define CYW43_LINK_NOIP (2)
-#define CYW43_LINK_UP (3)
-#define CYW43_LINK_FAIL (-1)
-#define CYW43_LINK_NONET (-2)
-#define CYW43_LINK_BADAUTH (-3)
-
-#ifndef MICROPY_BOARD_HOSTNAME
-#define MICROPY_BOARD_HOSTNAME "PYBD"
-#endif
-
-#ifndef MICROPY_BOARD_HOSTNAME_LENGTH
-#define MICROPY_BOARD_HOSTNAME_LENGTH 16
-#endif
-
-typedef struct _cyw43_t {
- cyw43_ll_t cyw43_ll;
-
- uint8_t itf_state;
- uint32_t trace_flags;
-
- // State for async events
- volatile uint32_t wifi_scan_state;
- uint32_t wifi_join_state;
- void *wifi_scan_env;
- int (*wifi_scan_cb)(void*, const cyw43_ev_scan_result_t*);
-
- // Pending things to do
- bool pend_disassoc;
- bool pend_rejoin;
- bool pend_rejoin_wpa;
-
- // AP settings
- uint8_t ap_channel;
- uint8_t ap_auth;
- uint8_t ap_ssid_len;
- uint8_t ap_key_len;
- uint8_t ap_ssid[32];
- uint8_t ap_key[64];
-
- // lwIP data
- struct netif netif[2];
- struct dhcp dhcp_client;
- dhcp_server_t dhcp_server;
- char hostname[MICROPY_BOARD_HOSTNAME_LENGTH];
-} cyw43_t;
-
-extern cyw43_t cyw43_state;
-extern void (*cyw43_poll)(void);
-extern uint32_t cyw43_sleep;
-
-void cyw43_init(cyw43_t *self);
-void cyw43_deinit(cyw43_t *self);
-
-int cyw43_ioctl(cyw43_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface);
-int cyw43_send_ethernet(cyw43_t *self, int itf, size_t len, const void *buf, bool is_pbuf);
-
-int cyw43_wifi_pm(cyw43_t *self, uint32_t pm);
-int cyw43_wifi_link_status(cyw43_t *self, int itf);
-void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up);
-int cyw43_wifi_get_mac(cyw43_t *self, int itf, uint8_t mac[6]);
-int cyw43_wifi_scan(cyw43_t *self, cyw43_wifi_scan_options_t *opts, void *env, int (*result_cb)(void*, const cyw43_ev_scan_result_t*));
-
-static inline bool cyw43_wifi_scan_active(cyw43_t *self) {
- return self->wifi_scan_state == 1;
-}
-
-int cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel);
-int cyw43_wifi_leave(cyw43_t *self, int itf);
-
-static inline void cyw43_wifi_ap_get_ssid(cyw43_t *self, size_t *len, const uint8_t **buf) {
- *len = self->ap_ssid_len;
- *buf = self->ap_ssid;
-}
-
-static inline void cyw43_wifi_ap_set_channel(cyw43_t *self, uint32_t channel) {
- self->ap_channel = channel;
-}
-
-static inline void cyw43_wifi_ap_set_ssid(cyw43_t *self, size_t len, const uint8_t *buf) {
- self->ap_ssid_len = MIN(len, sizeof(self->ap_ssid));
- memcpy(self->ap_ssid, buf, self->ap_ssid_len);
-}
-
-static inline void cyw43_wifi_ap_set_password(cyw43_t *self, size_t len, const uint8_t *buf) {
- self->ap_key_len = MIN(len, sizeof(self->ap_key));
- memcpy(self->ap_key, buf, self->ap_key_len);
-}
-
-static inline void cyw43_wifi_ap_set_auth(cyw43_t *self, uint32_t auth) {
- self->ap_auth = auth;
-}
-
-void cyw43_wifi_ap_get_stas(cyw43_t *self, int *num_stas, uint8_t *macs);
-
-void cyw43_tcpip_init(cyw43_t *self, int itf);
-void cyw43_tcpip_deinit(cyw43_t *self, int itf);
-void cyw43_tcpip_set_link_up(cyw43_t *self, int itf);
-void cyw43_tcpip_set_link_down(cyw43_t *self, int itf);
-int cyw43_tcpip_link_status(cyw43_t *self, int itf);
-
-#endif // MICROPY_INCLUDED_STM32_CYW43_H
diff --git a/drivers/cyw43/cyw43_ctrl.c b/drivers/cyw43/cyw43_ctrl.c
deleted file mode 100644
index 73e6e5895779..000000000000
--- a/drivers/cyw43/cyw43_ctrl.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/mperrno.h"
-#include "py/mphal.h"
-#include "drivers/cyw43/cyw43.h"
-#include "pendsv.h"
-#include "sdio.h"
-
-#define CYW_ENTER MICROPY_PY_LWIP_ENTER
-#define CYW_EXIT MICROPY_PY_LWIP_EXIT
-
-#ifdef pyb_pin_WL_HOST_WAKE
-#define USE_SDIOIT (0)
-#else
-#define USE_SDIOIT (1)
-#endif
-
-#define CYW43_SLEEP_MAX (50)
-
-#define WIFI_JOIN_STATE_ACTIVE (0x0001)
-#define WIFI_JOIN_STATE_FAIL (0x0002)
-#define WIFI_JOIN_STATE_NONET (0x0003)
-#define WIFI_JOIN_STATE_BADAUTH (0x0004)
-#define WIFI_JOIN_STATE_AUTH (0x0200)
-#define WIFI_JOIN_STATE_LINK (0x0400)
-#define WIFI_JOIN_STATE_KEYED (0x0800)
-#define WIFI_JOIN_STATE_ALL (0x0e01)
-
-#define CYW43_STA_IS_ACTIVE(self) (((self)->itf_state >> CYW43_ITF_STA) & 1)
-#define CYW43_AP_IS_ACTIVE(self) (((self)->itf_state >> CYW43_ITF_AP) & 1)
-
-cyw43_t cyw43_state;
-void (*cyw43_poll)(void);
-uint32_t cyw43_sleep;
-
-STATIC void cyw43_poll_func(void);
-STATIC void cyw43_wifi_ap_init(cyw43_t *self);
-STATIC void cyw43_wifi_ap_set_up(cyw43_t *self, bool up);
-
-static inline uint32_t cyw43_get_be16(const uint8_t *buf) {
- return buf[0] << 8 | buf[1];
-}
-
-static inline uint32_t cyw43_get_be32(const uint8_t *buf) {
- return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
-}
-
-static inline void cyw43_delay_ms(uint32_t ms) {
- mp_hal_delay_ms(ms);
-}
-
-/*******************************************************************************/
-// Initialisation and polling
-
-void cyw43_init(cyw43_t *self) {
- #ifdef pyb_pin_WL_HOST_WAKE
- mp_hal_pin_config(pyb_pin_WL_HOST_WAKE, MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0);
- #endif
- mp_hal_pin_config(pyb_pin_WL_REG_ON, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0);
- mp_hal_pin_low(pyb_pin_WL_REG_ON);
- #ifdef pyb_pin_WL_RFSW_VDD
- mp_hal_pin_config(pyb_pin_WL_RFSW_VDD, MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0); // RF-switch power
- mp_hal_pin_low(pyb_pin_WL_RFSW_VDD);
- #endif
-
- cyw43_ll_init(&self->cyw43_ll, self);
-
- self->itf_state = 0;
- self->wifi_scan_state = 0;
- self->wifi_join_state = 0;
- self->pend_disassoc = false;
- self->pend_rejoin= false;
- self->pend_rejoin_wpa = false;
- self->ap_channel = 3;
- self->ap_ssid_len = 0;
- self->ap_key_len = 0;
- strncpy(self->hostname, MICROPY_BOARD_HOSTNAME, MICROPY_BOARD_HOSTNAME_LENGTH);
- self->hostname[MICROPY_BOARD_HOSTNAME_LENGTH - 1] = 0;
-
- cyw43_poll = NULL;
-}
-
-void cyw43_deinit(cyw43_t *self) {
- if (cyw43_poll == NULL) {
- return;
- }
-
- CYW_ENTER
-
- // Stop the TCP/IP network interfaces.
- cyw43_tcpip_deinit(self, 0);
- cyw43_tcpip_deinit(self, 1);
-
- // Turn off the SDIO bus.
- #if USE_SDIOIT
- sdio_enable_irq(false);
- #endif
- sdio_deinit();
-
- // Power off the WLAN chip and make sure all state is reset.
- cyw43_init(self);
-
- CYW_EXIT
-}
-
-STATIC int cyw43_ensure_up(cyw43_t *self) {
- if (cyw43_poll != NULL) {
- cyw43_ll_bus_sleep(&self->cyw43_ll, false);
- return 0;
- }
-
- CYW_ENTER
-
- // Disable the netif if it was previously up
- cyw43_tcpip_deinit(self, CYW43_ITF_STA);
- cyw43_tcpip_deinit(self, CYW43_ITF_AP);
- self->itf_state = 0;
-
- // Reset and power up the WL chip
- mp_hal_pin_low(pyb_pin_WL_REG_ON);
- cyw43_delay_ms(20);
- mp_hal_pin_high(pyb_pin_WL_REG_ON);
- cyw43_delay_ms(50);
-
- // Initialise SDIO bus
- // IRQ priority only needs to be higher than CYW_ENTER/EXIT protection (PENDSV)
- sdio_init(NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 14, 0));
-
- // Initialise the low-level driver
- uint8_t mac[6];
- mp_hal_get_mac(MP_HAL_MAC_WLAN0, mac);
- int ret = cyw43_ll_bus_init(&self->cyw43_ll, mac);
-
- if (ret != 0) {
- CYW_EXIT
- return ret;
- }
-
- // Enable async events from low-level driver
- cyw43_sleep = CYW43_SLEEP_MAX;
- cyw43_poll = cyw43_poll_func;
- #if USE_SDIOIT
- sdio_enable_irq(true);
- #else
- extern void extint_set(const pin_obj_t *pin, uint32_t mode);
- extint_set(pyb_pin_WL_HOST_WAKE, GPIO_MODE_IT_FALLING);
- #endif
-
- CYW_EXIT
-
- return ret;
-}
-
-// This function must always be executed at the level where CYW_ENTER is effectively active
-STATIC void cyw43_poll_func(void) {
- if (cyw43_poll == NULL) {
- // Poll scheduled during deinit, just ignore it
- return;
- }
-
- cyw43_t *self = &cyw43_state;
- cyw43_ll_process_packets(&self->cyw43_ll);
-
- if (self->pend_disassoc) {
- self->pend_disassoc = false;
- cyw43_ll_ioctl(&self->cyw43_ll, CYW43_IOCTL_SET_DISASSOC, 0, NULL, CYW43_ITF_STA);
- }
-
- if (self->pend_rejoin_wpa) {
- self->pend_rejoin_wpa = false;
- cyw43_ll_wifi_set_wpa_auth(&self->cyw43_ll);
- }
-
- if (self->pend_rejoin) {
- self->pend_rejoin = false;
- cyw43_ll_wifi_rejoin(&self->cyw43_ll);
- self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE;
- }
-
- if (cyw43_sleep == 0) {
- cyw43_ll_bus_sleep(&self->cyw43_ll, true);
- #if !USE_SDIOIT
- sdio_deinit(); // save power while WLAN bus sleeps
- #endif
- }
-
- #if USE_SDIOIT
- sdio_enable_irq(true);
- #endif
-}
-
-/*******************************************************************************/
-// Callback interface to low-level driver
-
-int cyw43_cb_read_host_interrupt_pin(void *cb_data) {
- #ifdef pyb_pin_WL_HOST_WAKE
- return mp_hal_pin_read(pyb_pin_WL_HOST_WAKE);
- #else
- return mp_hal_pin_read(pyb_pin_WL_SDIO_1);
- #endif
-}
-
-void cyw43_cb_ensure_awake(void *cb_data) {
- cyw43_sleep = CYW43_SLEEP_MAX;
- #if !USE_SDIOIT
- sdio_reenable();
- #endif
-}
-
-STATIC const char *cyw43_async_event_name_table[89] = {
- [0 ... 88] = NULL,
- [CYW43_EV_SET_SSID] = "SET_SSID",
- [CYW43_EV_JOIN] = "JOIN",
- [CYW43_EV_AUTH] = "AUTH",
- [CYW43_EV_DEAUTH_IND] = "DEAUTH_IND",
- [CYW43_EV_ASSOC] = "ASSOC",
- [CYW43_EV_DISASSOC] = "DISASSOC",
- [CYW43_EV_DISASSOC_IND] = "DISASSOC_IND",
- [CYW43_EV_LINK] = "LINK",
- [CYW43_EV_PSK_SUP] = "PSK_SUP",
- [CYW43_EV_ESCAN_RESULT] = "ESCAN_RESULT",
- [CYW43_EV_CSA_COMPLETE_IND] = "CSA_COMPLETE_IND",
- [CYW43_EV_ASSOC_REQ_IE] = "ASSOC_REQ_IE",
- [CYW43_EV_ASSOC_RESP_IE] = "ASSOC_RESP_IE",
-};
-
-STATIC void cyw43_dump_async_event(const cyw43_async_event_t *ev) {
- printf("[% 8d] ASYNC(%04x,",
- (int)mp_hal_ticks_ms(),
- (unsigned int)ev->flags
- );
- if (ev->event_type < MP_ARRAY_SIZE(cyw43_async_event_name_table)
- && cyw43_async_event_name_table[ev->event_type] != NULL) {
- printf("%s", cyw43_async_event_name_table[ev->event_type]);
- } else {
- printf("%u", (unsigned int)ev->event_type);
- }
- printf(",%u,%u,%u)\n",
- (unsigned int)ev->status,
- (unsigned int)ev->reason,
- (unsigned int)ev->interface
- );
-}
-
-void cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev) {
- cyw43_t *self = cb_data;
-
- if (self->trace_flags & CYW43_TRACE_ASYNC_EV) {
- cyw43_dump_async_event(ev);
- }
-
- if (ev->event_type == CYW43_EV_ESCAN_RESULT && self->wifi_scan_state == 1) {
- // Escan result event
- if (ev->status == 8) {
- // Partial result
- int ret = self->wifi_scan_cb(self->wifi_scan_env, &ev->u.scan_result);
- if (ret != 0) {
- // TODO need to abort scan, or just ignore any more results
- }
- } else if (ev->status == 0) {
- // Scan complete
- self->wifi_scan_state = 2;
- }
-
- } else if (ev->event_type == CYW43_EV_DISASSOC) {
- cyw43_tcpip_set_link_down(self, CYW43_ITF_STA);
- self->wifi_join_state = 0x0000;
-
- /*
- } else if (ev->event_type == CYW43_EV_DISASSOC_IND) {
- if (ev->interface == CYW43_ITF_AP) {
- // Station disassociated with our AP, let DHCP server know so it can free the IP address
- dhcp_server_disassoc(&self->dhcp_server, buf + 24);
- }
- */
-
- // WiFi join events
- } else if (ev->event_type == CYW43_EV_PRUNE) {
- if (ev->status == 0 && ev->reason == 8) {
- // RSN mismatch, retry join with WPA auth
- self->pend_rejoin = true;
- self->pend_rejoin_wpa = true;
- pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func);
- }
- } else if (ev->event_type == CYW43_EV_SET_SSID) {
- if (ev->status == 0) {
- // Success setting SSID
- } else if (ev->status == 3 && ev->reason == 0) {
- self->wifi_join_state = WIFI_JOIN_STATE_NONET;
- // No matching SSID found (could be out of range, or down)
- } else {
- // Other failure setting SSID
- self->wifi_join_state = WIFI_JOIN_STATE_FAIL;
- }
- } else if (ev->event_type == CYW43_EV_AUTH) {
- if (ev->status == 0) {
- self->wifi_join_state |= WIFI_JOIN_STATE_AUTH;
- } else if (ev->status == 6) {
- // Unsolicited auth packet, ignore it
- } else {
- // Cannot authenticate
- self->wifi_join_state = WIFI_JOIN_STATE_BADAUTH;
- }
- } else if (ev->event_type == CYW43_EV_DEAUTH_IND) {
- if (ev->status == 0 && ev->reason == 2) {
- // Deauth, probably because password was wrong; disassociate
- self->pend_disassoc = true;
- pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func);
- }
- } else if (ev->event_type == CYW43_EV_LINK) {
- if (ev->status == 0) {
- if (ev->flags & 1) {
- // Link is up
- if (ev->interface == CYW43_ITF_STA) {
- self->wifi_join_state |= WIFI_JOIN_STATE_LINK;
- } else {
- cyw43_tcpip_set_link_up(self, ev->interface);
- }
- } else {
- // Link is down
- cyw43_tcpip_set_link_down(self, ev->interface);
- }
- }
- } else if (ev->event_type == CYW43_EV_PSK_SUP) {
- if (ev->status == 6) { // WLC_SUP_KEYED
- self->wifi_join_state |= WIFI_JOIN_STATE_KEYED;
- } else if ((ev->status == 4 || ev->status == 8 || ev->status == 11) && ev->reason == 15) {
- // Timeout waiting for key exchange M1/M3/G1
- // Probably at edge of the cell, retry
- self->pend_rejoin = true;
- pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, cyw43_poll_func);
- } else {
- // PSK_SUP failure
- self->wifi_join_state = WIFI_JOIN_STATE_BADAUTH;
- }
- }
-
- if (self->wifi_join_state == WIFI_JOIN_STATE_ALL) {
- // STA connected
- self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE;
- cyw43_tcpip_set_link_up(self, CYW43_ITF_STA);
- }
-}
-
-/*******************************************************************************/
-// Ioctl and Ethernet interface
-
-int cyw43_ioctl(cyw43_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return ret;
- }
-
- CYW_ENTER
- ret = cyw43_ll_ioctl(&self->cyw43_ll, cmd, len, buf, iface);
- CYW_EXIT
-
- return ret;
-}
-
-int cyw43_send_ethernet(cyw43_t *self, int itf, size_t len, const void *buf, bool is_pbuf) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return ret;
- }
-
- CYW_ENTER
- ret = cyw43_ll_send_ethernet(&self->cyw43_ll, itf, len, buf, is_pbuf);
- CYW_EXIT
-
- return ret;
-}
-
-/*******************************************************************************/
-// WiFi control
-
-STATIC int cyw43_wifi_on(cyw43_t *self, uint32_t country) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return ret;
- }
-
- #ifdef pyb_pin_WL_RFSW_VDD
- // Turn the RF-switch on
- mp_hal_pin_high(pyb_pin_WL_RFSW_VDD);
- #endif
-
- CYW_ENTER
- ret = cyw43_ll_wifi_on(&self->cyw43_ll, country);
- CYW_EXIT
-
- return ret;
-}
-
-int cyw43_wifi_pm(cyw43_t *self, uint32_t pm_in) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return ret;
- }
-
- // pm_in: 0x00adbrrm
- uint32_t pm = pm_in & 0xf;
- uint32_t pm_sleep_ret = (pm_in >> 4) & 0xff;
- uint32_t li_bcn = (pm_in >> 12) & 0xf;
- uint32_t li_dtim = (pm_in >> 16) & 0xf;
- uint32_t li_assoc = (pm_in >> 20) & 0xf;
-
- CYW_ENTER
- ret = cyw43_ll_wifi_pm(&self->cyw43_ll, pm, pm_sleep_ret, li_bcn, li_dtim, li_assoc);
- CYW_EXIT
-
- return ret;
-}
-
-int cyw43_wifi_get_mac(cyw43_t *self, int itf, uint8_t mac[6]) {
- mp_hal_get_mac(MP_HAL_MAC_WLAN0, &mac[0]);
- return 0;
-}
-
-#define MAKE_COUNTRY(a, b, rev) ((a) | (b) << 8 | (rev) << 16)
-
-void cyw43_wifi_set_up(cyw43_t *self, int itf, bool up) {
- if (up) {
- if (self->itf_state == 0) {
- uint32_t country;
- extern char pyb_country_code[2];
- if (pyb_country_code[0] == '\0' || pyb_country_code[1] == '\0') {
- country = MAKE_COUNTRY('X', 'X', 17); // default to world-wide (passive ch 12-14)
- } else {
- country = MAKE_COUNTRY(pyb_country_code[0], pyb_country_code[1], 0);
- }
- if (cyw43_wifi_on(self, country) != 0) {
- return;
- }
- cyw43_wifi_pm(self, 10 << 20 | 1 << 16 | 1 << 12 | 20 << 4 | 2);
- }
- if (itf == CYW43_ITF_AP) {
- cyw43_wifi_ap_init(self);
- cyw43_wifi_ap_set_up(self, true);
- }
- if ((self->itf_state & (1 << itf)) == 0) {
- CYW_ENTER
- cyw43_tcpip_deinit(self, itf);
- cyw43_tcpip_init(self, itf);
- self->itf_state |= 1 << itf;
- CYW_EXIT
- }
- } else {
- if (itf == CYW43_ITF_AP) {
- cyw43_wifi_ap_set_up(self, false);
- }
- }
-}
-
-int cyw43_wifi_scan(cyw43_t *self, cyw43_wifi_scan_options_t *opts, void *env, int (*result_cb)(void*, const cyw43_ev_scan_result_t*)) {
- if (self->itf_state == 0) {
- return -MP_EPERM;
- }
-
- cyw43_ensure_up(self);
-
- CYW_ENTER
-
- // Set state and callback data
- self->wifi_scan_state = 1;
- self->wifi_scan_env = env;
- self->wifi_scan_cb = result_cb;
-
- // Start the scan
- int ret = cyw43_ll_wifi_scan(&self->cyw43_ll, opts);
-
- CYW_EXIT
-
- return ret;
-}
-
-int cyw43_wifi_link_status(cyw43_t *self, int itf) {
- if (itf == CYW43_ITF_STA) {
- int s = self->wifi_join_state & 0xf;
- if (s == WIFI_JOIN_STATE_ACTIVE) {
- return CYW43_LINK_JOIN;
- } else if (s == WIFI_JOIN_STATE_FAIL) {
- return CYW43_LINK_FAIL;
- } else if (s == WIFI_JOIN_STATE_NONET) {
- return CYW43_LINK_NONET;
- } else if (s == WIFI_JOIN_STATE_BADAUTH) {
- return CYW43_LINK_BADAUTH;
- } else {
- return CYW43_LINK_DOWN;
- }
- } else {
- return CYW43_LINK_DOWN;
- }
-}
-
-/*******************************************************************************/
-// WiFi STA
-
-int cyw43_wifi_join(cyw43_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel) {
- if (!CYW43_STA_IS_ACTIVE(self)) {
- return -MP_EPERM;
- }
-
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return ret;
- }
-
- CYW_ENTER
-
- ret = cyw43_ll_wifi_join(&self->cyw43_ll, ssid_len, ssid, key_len, key, auth_type, bssid, channel);
-
- if (ret == 0) {
- // Wait for responses: EV_AUTH, EV_LINK, EV_SET_SSID, EV_PSK_SUP
- // Will get EV_DEAUTH_IND if password is invalid
- self->wifi_join_state = WIFI_JOIN_STATE_ACTIVE;
-
- if (auth_type == 0) {
- // For open security we don't need EV_PSK_SUP, so set that flag indicator now
- self->wifi_join_state |= WIFI_JOIN_STATE_KEYED;
- }
- }
-
- CYW_EXIT
-
- return ret;
-}
-
-int cyw43_wifi_leave(cyw43_t *self, int itf) {
- // Disassociate with SSID
- return cyw43_ioctl(self, CYW43_IOCTL_SET_DISASSOC, 0, NULL, itf);
-}
-
-/*******************************************************************************/
-// WiFi AP
-
-STATIC void cyw43_wifi_ap_init(cyw43_t *self) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return;
- }
-
- CYW_ENTER
- cyw43_ll_wifi_ap_init(&self->cyw43_ll, self->ap_ssid_len, self->ap_ssid, self->ap_auth, self->ap_key_len, self->ap_key, self->ap_channel);
- CYW_EXIT
-}
-
-STATIC void cyw43_wifi_ap_set_up(cyw43_t *self, bool up) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return;
- }
-
- CYW_ENTER
- cyw43_ll_wifi_ap_set_up(&self->cyw43_ll, up);
- CYW_EXIT
-}
-
-void cyw43_wifi_ap_get_stas(cyw43_t *self, int *num_stas, uint8_t *macs) {
- int ret = cyw43_ensure_up(self);
- if (ret) {
- return;
- }
-
- CYW_ENTER
- cyw43_ll_wifi_ap_get_stas(&self->cyw43_ll, num_stas, macs);
- CYW_EXIT
-}
diff --git a/drivers/cyw43/cyw43_ll.h b/drivers/cyw43/cyw43_ll.h
deleted file mode 100644
index 879367a2edd9..000000000000
--- a/drivers/cyw43/cyw43_ll.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_STM32_CYW43_LL_H
-#define MICROPY_INCLUDED_STM32_CYW43_LL_H
-
-// IOCTL commands
-#define CYW43_IOCTL_GET_SSID (0x32)
-#define CYW43_IOCTL_GET_CHANNEL (0x3a)
-#define CYW43_IOCTL_SET_DISASSOC (0x69)
-#define CYW43_IOCTL_GET_ANTDIV (0x7e)
-#define CYW43_IOCTL_SET_ANTDIV (0x81)
-#define CYW43_IOCTL_SET_MONITOR (0xd9)
-#define CYW43_IOCTL_GET_VAR (0x20c)
-#define CYW43_IOCTL_SET_VAR (0x20f)
-
-// Async events, event_type field
-#define CYW43_EV_SET_SSID (0)
-#define CYW43_EV_JOIN (1)
-#define CYW43_EV_AUTH (3)
-#define CYW43_EV_DEAUTH_IND (6)
-#define CYW43_EV_ASSOC (7)
-#define CYW43_EV_DISASSOC (11)
-#define CYW43_EV_DISASSOC_IND (12)
-#define CYW43_EV_LINK (16)
-#define CYW43_EV_PRUNE (23)
-#define CYW43_EV_PSK_SUP (46)
-#define CYW43_EV_ESCAN_RESULT (69)
-#define CYW43_EV_CSA_COMPLETE_IND (80)
-#define CYW43_EV_ASSOC_REQ_IE (87)
-#define CYW43_EV_ASSOC_RESP_IE (88)
-
-enum {
- CYW43_ITF_STA,
- CYW43_ITF_AP,
-};
-
-typedef struct _cyw43_ev_scan_result_t {
- uint32_t _0[5];
- uint8_t bssid[6];
- uint16_t _1[2];
- uint8_t ssid_len;
- uint8_t ssid[32];
- uint32_t _2[5];
- uint16_t channel;
- uint16_t _3;
- uint8_t auth_mode;
- int16_t rssi;
-} cyw43_ev_scan_result_t;
-
-typedef struct _cyw43_async_event_t {
- uint16_t _0;
- uint16_t flags;
- uint32_t event_type;
- uint32_t status;
- uint32_t reason;
- uint8_t _1[30];
- uint8_t interface;
- uint8_t _2;
- union {
- cyw43_ev_scan_result_t scan_result;
- } u;
-} cyw43_async_event_t;
-
-typedef struct _cyw43_wifi_scan_options_t {
- uint32_t version;
- uint16_t action;
- uint16_t _;
- uint32_t ssid_len; // 0 to select all
- uint8_t ssid[32];
- uint8_t bssid[6];
- int8_t bss_type; // fill with 0xff to select all
- int8_t scan_type; // 0=active, 1=passive
- int32_t nprobes;
- int32_t active_time;
- int32_t passive_time;
- int32_t home_time;
- int32_t channel_num;
- uint16_t channel_list[1];
-} cyw43_wifi_scan_options_t;
-
-typedef struct _cyw43_ll_t {
- uint32_t opaque[528];
-} cyw43_ll_t;
-
-void cyw43_ll_init(cyw43_ll_t *self, void *cb_data);
-void cyw43_ll_deinit(cyw43_ll_t *self);
-
-int cyw43_ll_bus_init(cyw43_ll_t *self, const uint8_t *mac);
-void cyw43_ll_bus_sleep(cyw43_ll_t *self, bool can_sleep);
-void cyw43_ll_process_packets(cyw43_ll_t *self);
-int cyw43_ll_ioctl(cyw43_ll_t *self, uint32_t cmd, size_t len, uint8_t *buf, uint32_t iface);
-int cyw43_ll_send_ethernet(cyw43_ll_t *self, int itf, size_t len, const void *buf, bool is_pbuf);
-
-int cyw43_ll_wifi_on(cyw43_ll_t *self, uint32_t country);
-int cyw43_ll_wifi_pm(cyw43_ll_t *self, uint32_t pm, uint32_t pm_sleep_ret, uint32_t li_bcn, uint32_t li_dtim, uint32_t li_assoc);
-int cyw43_ll_wifi_scan(cyw43_ll_t *self, cyw43_wifi_scan_options_t *opts);
-
-int cyw43_ll_wifi_join(cyw43_ll_t *self, size_t ssid_len, const uint8_t *ssid, size_t key_len, const uint8_t *key, uint32_t auth_type, const uint8_t *bssid, uint32_t channel);
-void cyw43_ll_wifi_set_wpa_auth(cyw43_ll_t *self);
-void cyw43_ll_wifi_rejoin(cyw43_ll_t *self);
-
-int cyw43_ll_wifi_ap_init(cyw43_ll_t *self, size_t ssid_len, const uint8_t *ssid, uint32_t auth, size_t key_len, const uint8_t *key, uint32_t channel);
-int cyw43_ll_wifi_ap_set_up(cyw43_ll_t *self, bool up);
-int cyw43_ll_wifi_ap_get_stas(cyw43_ll_t *self, int *num_stas, uint8_t *macs);
-
-// Callbacks to be provided by mid-level interface
-int cyw43_cb_read_host_interrupt_pin(void *cb_data);
-void cyw43_cb_ensure_awake(void *cb_data);
-void cyw43_cb_process_async_event(void *cb_data, const cyw43_async_event_t *ev);
-void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf);
-
-#endif // MICROPY_INCLUDED_STM32_CYW43_LL_H
diff --git a/drivers/cyw43/cyw43_lwip.c b/drivers/cyw43/cyw43_lwip.c
deleted file mode 100644
index f12a378c5da6..000000000000
--- a/drivers/cyw43/cyw43_lwip.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2018-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/mphal.h"
-#include "shared/netutils/netutils.h"
-#include "lwip/etharp.h"
-#include "lwip/dns.h"
-#include "lwip/apps/mdns.h"
-#include "drivers/cyw43/cyw43.h"
-
-STATIC void cyw43_ethernet_trace(cyw43_t *self, struct netif *netif, size_t len, const void *data, unsigned int flags) {
- bool is_tx = flags & NETUTILS_TRACE_IS_TX;
- if ((is_tx && (self->trace_flags & CYW43_TRACE_ETH_TX))
- || (!is_tx && (self->trace_flags & CYW43_TRACE_ETH_RX))) {
- const uint8_t *buf;
- if (len == (size_t)-1) {
- // data is a pbuf
- const struct pbuf *pbuf = data;
- buf = pbuf->payload;
- len = pbuf->len; // restricted to print only the first chunk of the pbuf
- } else {
- // data is actual data buffer
- buf = data;
- }
-
- if (self->trace_flags & CYW43_TRACE_MAC) {
- printf("[% 8d] ETH%cX itf=%c%c len=%u", (int)mp_hal_ticks_ms(), is_tx ? 'T' : 'R', netif->name[0], netif->name[1], len);
- printf(" MAC type=%d subtype=%d data=", buf[0] >> 2 & 3, buf[0] >> 4);
- for (size_t i = 0; i < len; ++i) {
- printf(" %02x", buf[i]);
- }
- printf("\n");
- return;
- }
-
- if (self->trace_flags & CYW43_TRACE_ETH_FULL) {
- flags |= NETUTILS_TRACE_PAYLOAD;
- }
- netutils_ethernet_trace(MP_PYTHON_PRINTER, len, buf, flags);
- }
-}
-
-STATIC err_t cyw43_netif_output(struct netif *netif, struct pbuf *p) {
- cyw43_t *self = netif->state;
- if (self->trace_flags != 0) {
- cyw43_ethernet_trace(self, netif, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
- }
- int itf = netif->name[1] - '0';
- int ret = cyw43_send_ethernet(self, itf, p->tot_len, (void*)p, true);
- if (ret) {
- printf("[CYW43] send_ethernet failed: %d\n", ret);
- return ERR_IF;
- }
- return ERR_OK;
-}
-
-STATIC err_t cyw43_netif_init(struct netif *netif) {
- netif->linkoutput = cyw43_netif_output;
- netif->output = etharp_output;
- netif->mtu = 1500;
- netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP;
- cyw43_wifi_get_mac(netif->state, netif->name[1] - '0', netif->hwaddr);
- netif->hwaddr_len = sizeof(netif->hwaddr);
- return ERR_OK;
-}
-
-void cyw43_tcpip_init(cyw43_t *self, int itf) {
- ip_addr_t ipconfig[4];
- #if LWIP_IPV6
- #define IP(x) ((x).u_addr.ip4)
- #else
- #define IP(x) (x)
- #endif
- if (itf == 0) {
- // need to zero out to get isconnected() working
- IP4_ADDR(&IP(ipconfig[0]), 0, 0, 0, 0);
- IP4_ADDR(&IP(ipconfig[2]), 192, 168, 0, 1);
- } else {
- IP4_ADDR(&IP(ipconfig[0]), 192, 168, 4, 1);
- IP4_ADDR(&IP(ipconfig[2]), 192, 168, 4, 1);
- }
- IP4_ADDR(&IP(ipconfig[1]), 255, 255, 255, 0);
- IP4_ADDR(&IP(ipconfig[3]), 8, 8, 8, 8);
- #undef IP
-
- struct netif *n = &self->netif[itf];
- n->name[0] = 'w';
- n->name[1] = '0' + itf;
- #if LWIP_IPV6
- netif_add(n, &ipconfig[0].u_addr.ip4, &ipconfig[1].u_addr.ip4, &ipconfig[2].u_addr.ip4, self, cyw43_netif_init, ethernet_input);
- #else
- netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, cyw43_netif_init, netif_input);
- #endif
- netif_set_hostname(n, self->hostname);
- netif_set_default(n);
- netif_set_up(n);
-
- if (itf == CYW43_ITF_STA) {
- dns_setserver(0, &ipconfig[3]);
- dhcp_set_struct(n, &self->dhcp_client);
- dhcp_start(n);
- } else {
- dhcp_server_init(&self->dhcp_server, &ipconfig[0], &ipconfig[1]);
- }
-
- #if LWIP_MDNS_RESPONDER
- // TODO better to call after IP address is set
- char mdns_hostname[9];
- int len = MIN(strlen(self->hostname), 4);
- memcpy(&mdns_hostname[0], self->hostname, len);
- mp_hal_get_mac_ascii(MP_HAL_MAC_WLAN0, 4 + len, 8 - len, &mdns_hostname[len]);
- mdns_hostname[8] = '\0';
- mdns_resp_add_netif(n, mdns_hostname, 60);
- #endif
-}
-
-void cyw43_tcpip_deinit(cyw43_t *self, int itf) {
- struct netif *n = &self->netif[itf];
- if (itf == CYW43_ITF_STA) {
- dhcp_stop(n);
- } else {
- dhcp_server_deinit(&self->dhcp_server);
- }
- #if LWIP_MDNS_RESPONDER
- mdns_resp_remove_netif(n);
- #endif
- for (struct netif *netif = netif_list; netif != NULL; netif = netif->next) {
- if (netif == n) {
- netif_remove(netif);
- netif->ip_addr.addr = 0;
- netif->flags = 0;
- }
- }
-}
-
-void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
- cyw43_t *self = cb_data;
- struct netif *netif = &self->netif[itf];
- if (self->trace_flags) {
- cyw43_ethernet_trace(self, netif, len, buf, NETUTILS_TRACE_NEWLINE);
- }
- if (netif->flags & NETIF_FLAG_LINK_UP) {
- struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
- if (p != NULL) {
- pbuf_take(p, buf, len);
- if (netif->input(p, netif) != ERR_OK) {
- pbuf_free(p);
- }
- }
- }
-}
-
-void cyw43_tcpip_set_link_up(cyw43_t *self, int itf) {
- netif_set_link_up(&self->netif[itf]);
-}
-
-void cyw43_tcpip_set_link_down(cyw43_t *self, int itf) {
- netif_set_link_down(&self->netif[itf]);
-}
-
-int cyw43_tcpip_link_status(cyw43_t *self, int itf) {
- struct netif *netif = &self->netif[itf];
- if ((netif->flags & (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP))
- == (NETIF_FLAG_UP | NETIF_FLAG_LINK_UP)) {
- if (netif->ip_addr.addr != 0) {
- return CYW43_LINK_UP;
- } else {
- return CYW43_LINK_NOIP;
- }
- } else {
- return cyw43_wifi_link_status(self, itf);
- }
-}
diff --git a/drivers/cyw43/cywbt.c b/drivers/cyw43/cywbt.c
index 64aeb871c38b..006fd28e901d 100644
--- a/drivers/cyw43/cywbt.c
+++ b/drivers/cyw43/cywbt.c
@@ -35,8 +35,8 @@
#if MICROPY_PY_NETWORK_CYW43
-extern const char fw_4343WA1_7_45_98_50_start;
-#define CYWBT_FW_ADDR (&fw_4343WA1_7_45_98_50_start + 749 * 512 + 29 * 256)
+#include "lib/cyw43-driver/src/cyw43_config.h"
+#include "lib/cyw43-driver/firmware/cyw43_btfw_4343A1.h"
// Provided by the port.
extern pyb_uart_obj_t mp_bluetooth_hci_uart_obj;
@@ -67,7 +67,7 @@ STATIC int cywbt_hci_cmd_raw(size_t len, uint8_t *buf) {
buf[i] = uart_rx_char(&mp_bluetooth_hci_uart_obj);
}
- // expect a comand complete event (event 0x0e)
+ // expect a command complete event (event 0x0e)
if (buf[0] != 0x04 || buf[1] != 0x0e) {
printf("unknown response: %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
return -1;
@@ -159,8 +159,8 @@ STATIC int cywbt_download_firmware(const uint8_t *firmware) {
#endif
mp_bluetooth_hci_uart_set_baudrate(115200);
- cywbt_set_baudrate(3000000);
- mp_bluetooth_hci_uart_set_baudrate(3000000);
+ cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
+ mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_SECONDARY);
return 0;
}
@@ -191,11 +191,13 @@ int mp_bluetooth_hci_controller_init(void) {
// Reset
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
+ #ifdef MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE
// Change baudrate
- cywbt_set_baudrate(3000000);
- mp_bluetooth_hci_uart_set_baudrate(3000000);
+ cywbt_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
+ mp_bluetooth_hci_uart_set_baudrate(MICROPY_HW_BLE_UART_BAUDRATE_DOWNLOAD_FIRMWARE);
+ #endif
- cywbt_download_firmware((const uint8_t*)CYWBT_FW_ADDR);
+ cywbt_download_firmware((const uint8_t*)&cyw43_btfw_4343A1[0]);
// Reset
cywbt_hci_cmd(0x03, 0x0003, 0, NULL);
diff --git a/drivers/cyw43/libcyw43.a b/drivers/cyw43/libcyw43.a
deleted file mode 100644
index 7d0ff93dcbe6..000000000000
Binary files a/drivers/cyw43/libcyw43.a and /dev/null differ
diff --git a/drivers/memory/external_flash_device.h b/drivers/memory/external_flash_device.h
new file mode 100644
index 000000000000..03798446036a
--- /dev/null
+++ b/drivers/memory/external_flash_device.h
@@ -0,0 +1,461 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
+#define MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
+
+#include
+#include
+
+typedef struct {
+ uint32_t total_size;
+ uint16_t start_up_time_us;
+
+ // Three response bytes to 0x9f JEDEC ID command.
+ uint8_t manufacturer_id;
+ uint8_t memory_type;
+ uint8_t capacity;
+
+ // Max clock speed for all operations and the fastest read mode.
+ uint8_t max_clock_speed_mhz;
+
+ // Bitmask for Quad Enable bit if present. 0x00 otherwise. This is for the highest byte in the
+ // status register.
+ uint8_t quad_enable_bit_mask;
+
+ bool has_sector_protection : 1;
+
+ // Supports the 0x0b fast read command with 8 dummy cycles.
+ bool supports_fast_read : 1;
+
+ // Supports the fast read, quad output command 0x6b with 8 dummy cycles.
+ bool supports_qspi : 1;
+
+ // Supports the quad input page program command 0x32. This is known as 1-1-4 because it only
+ // uses all four lines for data.
+ bool supports_qspi_writes : 1;
+
+ // Requires a separate command 0x31 to write to the second byte of the status register.
+ // Otherwise two byte are written via 0x01.
+ bool write_status_register_split : 1;
+
+ // True when the status register is a single byte. This implies the Quad Enable bit is in the
+ // first byte and the Read Status Register 2 command (0x35) is unsupported.
+ bool single_status_byte : 1;
+} external_flash_device;
+
+// Settings for the Adesto Tech AT25DF081A 1MiB SPI flash. Its on the SAMD21
+// Xplained board.
+// Datasheet: https://www.adestotech.com/wp-content/uploads/doc8715.pdf
+#define AT25DF081A { \
+ .total_size = (1 << 20), /* 1 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x1f, \
+ .memory_type = 0x45, \
+ .capacity = 0x01, \
+ .max_clock_speed_mhz = 85, \
+ .quad_enable_bit_mask = 0x00, \
+ .has_sector_protection = true, \
+ .supports_fast_read = true, \
+ .supports_qspi = false, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Gigadevice GD25Q16C 2MiB SPI flash.
+// Datasheet: http://www.gigadevice.com/datasheet/gd25q16c/
+#define GD25Q16C { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc8, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 104, /* if we need 120 then we can turn on high performance mode */ \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Gigadevice GD25Q64C 8MiB SPI flash.
+// Datasheet: http://www.elm-tech.com/en/products/spi-flash-memory/gd25q64/gd25q64.pdf
+#define GD25Q64C { \
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc8, \
+ .memory_type = 0x40, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 104, /* if we need 120 then we can turn on high performance mode */ \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = true, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL064L 8MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/316661/download
+#define S25FL064L { \
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 300, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x60, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 108, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL116K 2MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/196886/download
+#define S25FL116K { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 108, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Cypress (was Spansion) S25FL216K 2MiB SPI flash.
+// Datasheet: http://www.cypress.com/file/197346/download
+#define S25FL216K { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0x01, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 65, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = false, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16FW 2MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q16fw%20revj%2005182017%20sfdp.pdf
+#define W25Q16FW { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16JV-IQ 2MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q16jv%20spi%20revf%2005092017.pdf
+#define W25Q16JV_IQ { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q16JV-IM 2MiB SPI flash. Note that JV-IQ has a different .memory_type (0x40)
+// Datasheet: https://www.winbond.com/resource-files/w25q16jv%20spi%20revf%2005092017.pdf
+#define W25Q16JV_IM { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q32BV 4MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q32bv_revi_100413_wo_automotive.pdf
+#define W25Q32BV { \
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 10000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 104, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+// Settings for the Winbond W25Q32JV-IM 4MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q32jv%20revg%2003272018%20plus.pdf
+#define W25Q32JV_IM { \
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q32JV-IM 4MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q32jv%20revg%2003272018%20plus.pdf
+#define W25Q32JV_IQ { \
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q64JV-IM 8MiB SPI flash. Note that JV-IQ has a different .memory_type (0x40)
+// Datasheet: http://www.winbond.com/resource-files/w25q64jv%20revj%2003272018%20plus.pdf
+#define W25Q64JV_IM { \
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q64JV-IQ 8MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: http://www.winbond.com/resource-files/w25q64jv%20revj%2003272018%20plus.pdf
+#define W25Q64JV_IQ { \
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Winbond W25Q80DL 1MiB SPI flash.
+// Datasheet: https://www.winbond.com/resource-files/w25q80dv%20dl_revh_10022015.pdf
+#define W25Q80DL { \
+ .total_size = (1 << 20), /* 1 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x60, \
+ .capacity = 0x14, \
+ .max_clock_speed_mhz = 104, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+
+// Settings for the Winbond W25Q128JV-SQ 16MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
+#define W25Q128JV_SQ { \
+ .total_size = (1 << 24), /* 16 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x18, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for the Macronix MX25L1606 2MiB SPI flash.
+// Datasheet:
+#define MX25L1606 { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc2, \
+ .memory_type = 0x20, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 8, \
+ .quad_enable_bit_mask = 0x40, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+}
+
+// Settings for the Macronix MX25L3233F 4MiB SPI flash.
+// Datasheet: http://www.macronix.com/Lists/Datasheet/Attachments/7426/MX25L3233F,%203V,%2032Mb,%20v1.6.pdf
+#define MX25L3233F { \
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc2, \
+ .memory_type = 0x20, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x40, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+}
+
+// Settings for the Macronix MX25R6435F 8MiB SPI flash.
+// Datasheet: http://www.macronix.com/Lists/Datasheet/Attachments/7428/MX25R6435F,%20Wide%20Range,%2064Mb,%20v1.4.pdf
+// By default its in lower power mode which can only do 8mhz. In high power mode it can do 80mhz.
+#define MX25R6435F { \
+ .total_size = (1 << 23), /* 8 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xc2, \
+ .memory_type = 0x28, \
+ .capacity = 0x17, \
+ .max_clock_speed_mhz = 8, \
+ .quad_enable_bit_mask = 0x40, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = true, \
+}
+
+// Settings for the Winbond W25Q128JV-PM 16MiB SPI flash. Note that JV-IM has a different .memory_type (0x70)
+// Datasheet: https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf
+#define W25Q128JV_PM { \
+ .total_size = (1 << 24), /* 16 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x70, \
+ .capacity = 0x18, \
+ .max_clock_speed_mhz = 133, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+}
+
+// Settings for the Winbond W25Q32FV 4MiB SPI flash.
+// Datasheet:http://www.winbond.com/resource-files/w25q32fv%20revj%2006032016.pdf?__locale=en
+#define W25Q32FV { \
+ .total_size = (1 << 22), /* 4 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0xef, \
+ .memory_type = 0x40, \
+ .capacity = 0x16, \
+ .max_clock_speed_mhz = 104, \
+ .quad_enable_bit_mask = 0x00, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = false, \
+ .supports_qspi_writes = false, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+
+// Settings for a GENERIC device with the most common setting
+#define GENERIC { \
+ .total_size = (1 << 21), /* 2 MiB */ \
+ .start_up_time_us = 5000, \
+ .manufacturer_id = 0x00, \
+ .memory_type = 0x40, \
+ .capacity = 0x15, \
+ .max_clock_speed_mhz = 48, \
+ .quad_enable_bit_mask = 0x02, \
+ .has_sector_protection = false, \
+ .supports_fast_read = true, \
+ .supports_qspi = true, \
+ .supports_qspi_writes = true, \
+ .write_status_register_split = false, \
+ .single_status_byte = false, \
+}
+#endif // MICROPY_INCLUDED_ATMEL_SAMD_EXTERNAL_FLASH_DEVICES_H
diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c
index 9f8dc29a734d..52739b1d8bdf 100644
--- a/drivers/memory/spiflash.c
+++ b/drivers/memory/spiflash.c
@@ -70,7 +70,8 @@ STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) {
}
}
-STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) {
+STATIC int mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) {
+ int ret = 0;
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
// Note: len/data are unused for standard SPI
@@ -78,11 +79,13 @@ STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
mp_hal_pin_write(c->bus.u_spi.cs, 1);
} else {
- c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data);
+ ret = c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data);
}
+ return ret;
}
-STATIC void mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) {
+STATIC int mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src, uint8_t *dest) {
+ int ret = 0;
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
uint8_t buf[5] = {cmd, 0};
@@ -98,28 +101,28 @@ STATIC void mp_spiflash_transfer_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd,
mp_hal_pin_write(c->bus.u_spi.cs, 1);
} else {
if (dest != NULL) {
- c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, cmd, addr, len, dest);
+ ret = c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, cmd, addr, len, dest);
} else {
- c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src);
+ ret = c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src);
}
}
+ return ret;
}
-STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) {
+STATIC int mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t *dest) {
const mp_spiflash_config_t *c = self->config;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
- uint32_t buf;
mp_hal_pin_write(c->bus.u_spi.cs, 0);
c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL);
- c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf);
+ c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)dest, (void*)dest);
mp_hal_pin_write(c->bus.u_spi.cs, 1);
- return buf;
+ return 0;
} else {
- return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len);
+ return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len, dest);
}
}
-STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
+STATIC int mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
const mp_spiflash_config_t *c = self->config;
uint8_t cmd;
if (c->bus_kind == MP_SPIFLASH_BUS_SPI) {
@@ -127,17 +130,20 @@ STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len
} else {
cmd = MICROPY_HW_SPI_ADDR_IS_32BIT(addr) ? CMD_C4READ_32 : CMD_C4READ;
}
- mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, NULL, dest);
+ return mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, NULL, dest);
}
-STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
- mp_spiflash_write_cmd_data(self, cmd, 0, 0);
+STATIC int mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) {
+ return mp_spiflash_write_cmd_data(self, cmd, 0, 0);
}
STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) {
- uint8_t sr;
do {
- sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1);
+ uint32_t sr;
+ int ret = mp_spiflash_read_cmd(self, CMD_RDSR, 1, &sr);
+ if (ret != 0) {
+ return ret;
+ }
if ((sr & mask) == val) {
return 0; // success
}
@@ -176,17 +182,23 @@ void mp_spiflash_init(mp_spiflash_t *self) {
#if defined(CHECK_DEVID)
// Validate device id
- uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3);
- if (devid != CHECK_DEVID) {
- return 0;
+ uint32_t devid;
+ int ret = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3, &devid);
+ if (ret != 0 || devid != CHECK_DEVID) {
+ mp_spiflash_release_bus(self);
+ return;
}
#endif
if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) {
// Set QE bit
- uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff)
- | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8;
- if (!(data & (QSPI_QE_MASK << 8))) {
+ uint32_t sr = 0, cr = 0;
+ int ret = mp_spiflash_read_cmd(self, CMD_RDSR, 1, &sr);
+ if (ret == 0) {
+ ret = mp_spiflash_read_cmd(self, CMD_RDCR, 1, &cr);
+ }
+ uint32_t data = (sr & 0xff) | (cr & 0xff) << 8;
+ if (ret == 0 && !(data & (QSPI_QE_MASK << 8))) {
data |= QSPI_QE_MASK << 8;
mp_spiflash_write_cmd(self, CMD_WREN);
mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data);
@@ -208,36 +220,50 @@ void mp_spiflash_deepsleep(mp_spiflash_t *self, int value) {
}
STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) {
+ int ret = 0;
// enable writes
- mp_spiflash_write_cmd(self, CMD_WREN);
+ ret = mp_spiflash_write_cmd(self, CMD_WREN);
+ if (ret != 0) {
+ return ret;
+ }
// wait WEL=1
- int ret = mp_spiflash_wait_wel1(self);
+ ret = mp_spiflash_wait_wel1(self);
if (ret != 0) {
return ret;
}
// erase the sector
uint8_t cmd = MICROPY_HW_SPI_ADDR_IS_32BIT(addr) ? CMD_SEC_ERASE_32 : CMD_SEC_ERASE;
- mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, 0, NULL, NULL);
+ ret = mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, 0, NULL, NULL);
+ if (ret != 0) {
+ return ret;
+ }
// wait WIP=0
return mp_spiflash_wait_wip0(self);
}
STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
+ int ret = 0;
// enable writes
- mp_spiflash_write_cmd(self, CMD_WREN);
+ ret = mp_spiflash_write_cmd(self, CMD_WREN);
+ if (ret != 0) {
+ return ret;
+ }
// wait WEL=1
- int ret = mp_spiflash_wait_wel1(self);
+ ret = mp_spiflash_wait_wel1(self);
if (ret != 0) {
return ret;
}
// write the page
uint8_t cmd = MICROPY_HW_SPI_ADDR_IS_32BIT(addr) ? CMD_WRITE_32 : CMD_WRITE;
- mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, src, NULL);
+ ret = mp_spiflash_transfer_cmd_addr_data(self, cmd, addr, len, src, NULL);
+ if (ret != 0) {
+ return ret;
+ }
// wait WIP=0
return mp_spiflash_wait_wip0(self);
@@ -253,13 +279,14 @@ int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr) {
return ret;
}
-void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
+int mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
if (len == 0) {
- return;
+ return 0;
}
mp_spiflash_acquire_bus(self);
- mp_spiflash_read_data(self, addr, len, dest);
+ int ret = mp_spiflash_read_data(self, addr, len, dest);
mp_spiflash_release_bus(self);
+ return ret;
}
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
@@ -289,9 +316,9 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
-void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
+int mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
if (len == 0) {
- return;
+ return 0;
}
mp_spiflash_acquire_bus(self);
mp_spiflash_cache_t *cache = self->config->cache;
@@ -304,7 +331,11 @@ void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uin
if (bis < cache->block) {
// Read direct from flash for first part
rest = cache->block * SECTOR_SIZE - addr;
- mp_spiflash_read_data(self, addr, rest, dest);
+ int ret = mp_spiflash_read_data(self, addr, rest, dest);
+ if (ret != 0) {
+ mp_spiflash_release_bus(self);
+ return ret;
+ }
len -= rest;
dest += rest;
addr += rest;
@@ -318,21 +349,22 @@ void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uin
len -= rest;
if (len == 0) {
mp_spiflash_release_bus(self);
- return;
+ return 0;
}
dest += rest;
addr += rest;
}
}
// Read rest direct from flash
- mp_spiflash_read_data(self, addr, len, dest);
+ int ret = mp_spiflash_read_data(self, addr, len, dest);
mp_spiflash_release_bus(self);
+ return ret;
}
-STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
+STATIC int mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
#if USE_WR_DELAY
if (!(self->flags & 1)) {
- return;
+ return 0;
}
self->flags &= ~1;
@@ -342,7 +374,7 @@ STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
// Erase sector
int ret = mp_spiflash_erase_block_internal(self, cache->block * SECTOR_SIZE);
if (ret != 0) {
- return;
+ return ret;
}
// Write
@@ -350,16 +382,18 @@ STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) {
uint32_t addr = cache->block * SECTOR_SIZE + i * PAGE_SIZE;
int ret = mp_spiflash_write_page(self, addr, PAGE_SIZE, cache->buf + i * PAGE_SIZE);
if (ret != 0) {
- return;
+ return ret;
}
}
#endif
+ return 0;
}
-void mp_spiflash_cache_flush(mp_spiflash_t *self) {
+int mp_spiflash_cache_flush(mp_spiflash_t *self) {
mp_spiflash_acquire_bus(self);
- mp_spiflash_cache_flush_internal(self);
+ int ret = mp_spiflash_cache_flush_internal(self);
mp_spiflash_release_bus(self);
+ return ret;
}
STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) {
@@ -389,10 +423,16 @@ STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, siz
// Read sector
#if USE_WR_DELAY
if (cache->block != 0xffffffff) {
- mp_spiflash_cache_flush_internal(self);
+ int ret = mp_spiflash_cache_flush_internal(self);
+ if (ret != 0) {
+ return ret;
+ }
}
#endif
- mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf);
+ int ret = mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf);
+ if (ret != 0) {
+ return ret;
+ }
}
#if USE_WR_DELAY
diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h
index c4162ff21cdc..5ccf7d44c97d 100644
--- a/drivers/memory/spiflash.h
+++ b/drivers/memory/spiflash.h
@@ -76,13 +76,13 @@ void mp_spiflash_deepsleep(mp_spiflash_t *self, int value);
// These functions go direct to the SPI flash device
int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr);
-void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
+int mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
// These functions use the cache (which must already be configured)
-void mp_spiflash_cache_flush(mp_spiflash_t *self);
-void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
+int mp_spiflash_cache_flush(mp_spiflash_t *self);
+int mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);
#endif
diff --git a/drivers/ninaw10/machine_pin_nina.c b/drivers/ninaw10/machine_pin_nina.c
new file mode 100644
index 000000000000..025ecb66af0d
--- /dev/null
+++ b/drivers/ninaw10/machine_pin_nina.c
@@ -0,0 +1,101 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Ibrahim Abdelkader
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#if defined(MICROPY_PY_NETWORK_NINAW10) && defined(MICROPY_HW_PIN_EXT_COUNT)
+
+#include "modmachine.h"
+#include "machine_pin.h"
+#include "nina_wifi_drv.h"
+
+#define NINA_GPIO_INPUT (0x00)
+#define NINA_GPIO_OUTPUT (0x01)
+#define NINA_GPIO_INPUT_PULLUP (0x02)
+
+#define NINA_GPIO_MODE (0x50)
+#define NINA_GPIO_READ (0x53)
+#define NINA_GPIO_WRITE (0x51)
+#define NINA_GPIO_IS_INPUT_ONLY(p) ((p >= 34 && p <= 36) || (p == 39))
+
+static uint8_t pin_map[MICROPY_HW_PIN_EXT_COUNT] = {
+ 27, // LEDR
+ 25, // LEDG
+ 26, // LEDB
+ 34, // A4
+ 39, // A5
+ 36, // A6
+ 35, // A7
+};
+
+void machine_pin_ext_init(void) {
+ nina_init();
+}
+
+void machine_pin_ext_set(machine_pin_obj_t *self, bool value) {
+ if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
+ uint8_t buf[] = {pin_map[self->id], value};
+ nina_ioctl(NINA_GPIO_WRITE, sizeof(buf), buf, 0);
+ }
+}
+
+bool machine_pin_ext_get(machine_pin_obj_t *self) {
+ bool value = false;
+ if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
+ uint8_t buf[] = {pin_map[self->id]};
+ nina_ioctl(NINA_GPIO_READ, sizeof(buf), buf, 0);
+ value = buf[0];
+ }
+ return value;
+}
+
+void machine_pin_ext_config(machine_pin_obj_t *self, int mode, int value) {
+ if (mode == MACHINE_PIN_MODE_IN) {
+ mode = NINA_GPIO_INPUT;
+ self->is_output = false;
+ } else if (mode == MACHINE_PIN_MODE_OUT) {
+ mode = NINA_GPIO_OUTPUT;
+ self->is_output = true;
+ } else {
+ mp_raise_ValueError("only Pin.OUT and Pin.IN are supported for this pin");
+ }
+ if (self->id >= 0 && self->id < MICROPY_HW_PIN_EXT_COUNT) {
+ uint8_t buf[] = {pin_map[self->id], mode};
+ if (mode == NINA_GPIO_OUTPUT) {
+ if (NINA_GPIO_IS_INPUT_ONLY(buf[0])) {
+ mp_raise_ValueError("only Pin.IN is supported for this pin");
+ }
+ machine_pin_ext_set(self, value);
+ }
+ nina_ioctl(NINA_GPIO_MODE, sizeof(buf), buf, 0);
+ }
+}
+
+#endif // defined(MICROPY_PY_NETWORK_NINAW10) && defined(MICROPY_HW_PIN_EXT_COUNT)
diff --git a/drivers/ninaw10/nina_wifi_drv.c b/drivers/ninaw10/nina_wifi_drv.c
index 7a1167b2c94c..111ead003dee 100644
--- a/drivers/ninaw10/nina_wifi_drv.c
+++ b/drivers/ninaw10/nina_wifi_drv.c
@@ -105,9 +105,10 @@ typedef enum {
NINA_CMD_AP_GET_BSSID = 0x3C,
NINA_CMD_AP_GET_CHANNEL = 0x3D,
- // Disonnect/status commands.
+ // Disconnect/status commands.
NINA_CMD_DISCONNECT = 0x30,
NINA_CMD_CONN_STATUS = 0x20,
+ NINA_CMD_CONN_REASON = 0x1F,
// Interface config commands.
NINA_CMD_SET_IF_CONFIG = 0x14,
@@ -173,19 +174,6 @@ typedef enum {
NINA_CMD_CMD_DOWNLOAD_OTA = 0x67,
} nina_cmd_t;
-typedef enum {
- NINA_STATUS_IDLE = 0,
- NINA_STATUS_NO_SSID_AVAIL,
- NINA_STATUS_SCAN_COMPLETED,
- NINA_STATUS_CONNECTED,
- NINA_STATUS_CONNECT_FAILED,
- NINA_STATUS_CONNECTION_LOST,
- NINA_STATUS_DISCONNECTED,
- NINA_STATUS_AP_LISTENING,
- NINA_STATUS_AP_CONNECTED,
- NINA_STATUS_AP_FAILED
-} nina_status_t;
-
typedef enum {
SOCKET_STATE_CLOSED = 0,
SOCKET_STATE_LISTEN,
@@ -364,13 +352,15 @@ int nina_deinit(void) {
return nina_bsp_deinit();
}
-static int nina_connection_status() {
+int nina_connection_status(void) {
return nina_send_command_read_ack(NINA_CMD_CONN_STATUS, 0, ARG_8BITS, NULL);
}
-int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
- uint8_t status = NINA_STATUS_CONNECT_FAILED;
+int nina_connection_reason(void) {
+ return nina_send_command_read_ack(NINA_CMD_CONN_REASON, 0, ARG_8BITS, NULL);
+}
+int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
if (key == NULL && security != NINA_SEC_OPEN) {
return -1;
}
@@ -398,18 +388,7 @@ int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t c
return -1;
}
- for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
- status = nina_connection_status();
- if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
- break;
- }
-
- if ((mp_hal_ticks_ms() - start) >= NINA_CONNECT_TIMEOUT) {
- break;
- }
- }
-
- return (status == NINA_STATUS_CONNECTED) ? 0 : -1;
+ return 0;
}
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel) {
@@ -439,7 +418,7 @@ int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t
for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_hal_delay_ms(10)) {
status = nina_connection_status();
- if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL) && (status != NINA_STATUS_SCAN_COMPLETED)) {
+ if ((status != NINA_STATUS_IDLE) && (status != NINA_STATUS_NO_SSID_AVAIL)) {
break;
}
diff --git a/drivers/ninaw10/nina_wifi_drv.h b/drivers/ninaw10/nina_wifi_drv.h
index 22163c7286e9..4b09ac8bd24a 100644
--- a/drivers/ninaw10/nina_wifi_drv.h
+++ b/drivers/ninaw10/nina_wifi_drv.h
@@ -46,6 +46,17 @@
#define NINA_FW_VER_MINOR_OFFS (2)
#define NINA_FW_VER_PATCH_OFFS (4)
+#define NINA_ESP_REASON_AUTH_EXPIRE (2)
+#define NINA_ESP_REASON_ASSOC_EXPIRE (4)
+#define NINA_ESP_REASON_NOT_AUTHED (6)
+#define NINA_ESP_REASON_4WAY_HANDSHAKE_TIMEOUT (15)
+#define NINA_ESP_REASON_BEACON_TIMEOUT (200)
+#define NINA_ESP_REASON_NO_AP_FOUND (201)
+#define NINA_ESP_REASON_AUTH_FAIL (202)
+#define NINA_ESP_REASON_ASSOC_FAIL (203)
+#define NINA_ESP_REASON_HANDSHAKE_TIMEOUT (204)
+#define NINA_ESP_REASON_CONNECTION_FAIL (205)
+
typedef enum {
NINA_SEC_INVALID = 0,
NINA_SEC_OPEN,
@@ -59,6 +70,19 @@ typedef enum {
NINA_SOCKET_TYPE_RAW = 3,
} nina_socket_type_t;
+typedef enum {
+ NINA_STATUS_IDLE = 0,
+ NINA_STATUS_NO_SSID_AVAIL = 1,
+ NINA_STATUS_SCAN_COMPLETED = 2,
+ NINA_STATUS_CONNECTED = 3,
+ NINA_STATUS_CONNECT_FAILED = 4,
+ NINA_STATUS_CONNECTION_LOST = 5,
+ NINA_STATUS_DISCONNECTED = 6,
+ NINA_STATUS_AP_LISTENING = 7,
+ NINA_STATUS_AP_CONNECTED = 8,
+ NINA_STATUS_AP_FAILED = 9
+} nina_status_t;
+
typedef struct {
uint8_t ip_addr[NINA_IPV4_ADDR_LEN];
uint8_t subnet_addr[NINA_IPV4_ADDR_LEN];
@@ -85,6 +109,8 @@ typedef int (*nina_scan_callback_t)(nina_scan_result_t *, void *);
int nina_init(void);
int nina_deinit(void);
+int nina_connection_status(void);
+int nina_connection_reason(void);
int nina_connect(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_start_ap(const char *ssid, uint8_t security, const char *key, uint16_t channel);
int nina_disconnect(void);
diff --git a/examples/SDdatalogger/datalogger.py b/examples/SDdatalogger/datalogger.py
index 3d6f98b38927..1d1195700cbb 100644
--- a/examples/SDdatalogger/datalogger.py
+++ b/examples/SDdatalogger/datalogger.py
@@ -10,7 +10,6 @@
# loop
while True:
-
# wait for interrupt
# this reduces power consumption while waiting for switch press
pyb.wfi()
diff --git a/examples/asmsum.py b/examples/asmsum.py
index f465b25afda7..f2c7f285badc 100644
--- a/examples/asmsum.py
+++ b/examples/asmsum.py
@@ -1,6 +1,5 @@
@micropython.asm_thumb
def asm_sum_words(r0, r1):
-
# r0 = len
# r1 = ptr
# r2 = sum
@@ -25,7 +24,6 @@ def asm_sum_words(r0, r1):
@micropython.asm_thumb
def asm_sum_bytes(r0, r1):
-
# r0 = len
# r1 = ptr
# r2 = sum
diff --git a/examples/bluetooth/ble_simple_central.py b/examples/bluetooth/ble_simple_central.py
index a6bbdc6ee079..3c0cf2a0d49e 100644
--- a/examples/bluetooth/ble_simple_central.py
+++ b/examples/bluetooth/ble_simple_central.py
@@ -179,7 +179,7 @@ def connect(self, addr_type=None, addr=None, callback=None):
# Disconnect from current device.
def disconnect(self):
- if not self._conn_handle:
+ if self._conn_handle is None:
return
self._ble.gap_disconnect(self._conn_handle)
self._reset()
diff --git a/examples/bluetooth/ble_temperature_central.py b/examples/bluetooth/ble_temperature_central.py
index 96c4aad1445a..afa914672ce4 100644
--- a/examples/bluetooth/ble_temperature_central.py
+++ b/examples/bluetooth/ble_temperature_central.py
@@ -39,14 +39,7 @@
_ENV_SENSE_UUID = bluetooth.UUID(0x181A)
# org.bluetooth.characteristic.temperature
_TEMP_UUID = bluetooth.UUID(0x2A6E)
-_TEMP_CHAR = (
- _TEMP_UUID,
- bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
-)
-_ENV_SENSE_SERVICE = (
- _ENV_SENSE_UUID,
- (_TEMP_CHAR,),
-)
+
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_THERMOMETER = const(768)
@@ -196,7 +189,7 @@ def connect(self, addr_type=None, addr=None, callback=None):
# Disconnect from current device.
def disconnect(self):
- if not self._conn_handle:
+ if self._conn_handle is None:
return
self._ble.gap_disconnect(self._conn_handle)
self._reset()
diff --git a/examples/bluetooth/ble_uart_repl.py b/examples/bluetooth/ble_uart_repl.py
index 9e8a38ff4b5e..7d92c1f31829 100644
--- a/examples/bluetooth/ble_uart_repl.py
+++ b/examples/bluetooth/ble_uart_repl.py
@@ -20,6 +20,7 @@
else:
_timer = None
+
# Batch writes into 50ms intervals.
def schedule_in(handler, delay_ms):
def _wrap(_arg):
diff --git a/examples/conwaylife.py b/examples/conwaylife.py
index 44c1a507be8a..00cbd9cfccaa 100644
--- a/examples/conwaylife.py
+++ b/examples/conwaylife.py
@@ -4,6 +4,7 @@
lcd = pyb.LCD("x")
lcd.light(1)
+
# do 1 iteration of Conway's Game of Life
def conway_step():
for x in range(128): # loop over x coordinates
diff --git a/examples/embedding/Makefile b/examples/embedding/Makefile
index edaa577f5734..13bfdf12395d 100644
--- a/examples/embedding/Makefile
+++ b/examples/embedding/Makefile
@@ -1,8 +1,25 @@
-MPTOP = ../..
-CFLAGS += -std=c99 -I. -I$(MPTOP) -DNO_QSTR
-LDFLAGS += -L./build
+# This file is part of the MicroPython project, http://micropython.org/
+# The MIT License (MIT)
+# Copyright (c) 2022-2023 Damien P. George
+#
+# This is a very simple makefile that demonstrates how to build the embed port.
+# All it needs to do is build all *.c files in the micropython_embed directory.
+# This makefile would be replaced with your custom build system.
-hello-embed: hello-embed.o -lmicropython
+EMBED_DIR = micropython_embed
+PROG = embed
--lmicropython:
- $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP)
+CFLAGS += -I.
+CFLAGS += -I$(EMBED_DIR)
+CFLAGS += -I$(EMBED_DIR)/port
+CFLAGS += -Wall -Og
+
+SRC += main.c
+SRC += $(wildcard $(EMBED_DIR)/*/*.c) $(wildcard $(EMBED_DIR)/*/*/*.c)
+OBJ += $(SRC:.c=.o)
+
+$(PROG): $(OBJ)
+ $(CC) -o $@ $^
+
+clean:
+ /bin/rm -f $(OBJ) $(PROG)
diff --git a/examples/embedding/Makefile.upylib b/examples/embedding/Makefile.upylib
index 99ce94b7add0..e69de29bb2d1 100644
--- a/examples/embedding/Makefile.upylib
+++ b/examples/embedding/Makefile.upylib
@@ -1,184 +0,0 @@
-MPTOP = ../..
--include mpconfigport.mk
-include $(MPTOP)/py/mkenv.mk
-
-all: lib
-
-# OS name, for simple autoconfig
-UNAME_S := $(shell uname -s)
-
-# include py core make definitions
-include $(MPTOP)/py/py.mk
-include $(MPTOP)/extmod/extmod.mk
-
-INC += -I.
-INC += -I..
-INC += -I$(MPTOP)
-INC += -I$(MPTOP)/ports/unix
-INC += -I$(BUILD)
-
-# compiler settings
-CWARN = -Wall -Werror
-CWARN += -Wpointer-arith -Wuninitialized
-CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
-
-# Some systems (eg MacOS) need -fno-common so that mp_state_ctx is placed in the BSS.
-CFLAGS += -fno-common
-
-# Debugging/Optimization
-ifdef DEBUG
-CFLAGS += -g
-COPT = -O0
-else
-COPT = -Os #-DNDEBUG
-# _FORTIFY_SOURCE is a feature in gcc/glibc which is intended to provide extra
-# security for detecting buffer overflows. Some distros (Ubuntu at the very least)
-# have it enabled by default.
-#
-# gcc already optimizes some printf calls to call puts and/or putchar. When
-# _FORTIFY_SOURCE is enabled and compiling with -O1 or greater, then some
-# printf calls will also be optimized to call __printf_chk (in glibc). Any
-# printfs which get redirected to __printf_chk are then no longer synchronized
-# with printfs that go through mp_printf.
-#
-# In MicroPython, we don't want to use the runtime library's printf but rather
-# go through mp_printf, so that stdout is properly tied into streams, etc.
-# This means that we either need to turn off _FORTIFY_SOURCE or provide our
-# own implementation of __printf_chk. We've chosen to turn off _FORTIFY_SOURCE.
-# It should also be noted that the use of printf in MicroPython is typically
-# quite limited anyways (primarily for debug and some error reporting, etc
-# in the unix version).
-#
-# Information about _FORTIFY_SOURCE seems to be rather scarce. The best I could
-# find was this: https://securityblog.redhat.com/2014/03/26/fortify-and-you/
-# Original patchset was introduced by
-# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html .
-#
-# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater
-CFLAGS += -U _FORTIFY_SOURCE
-endif
-
-# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed.
-# The unix port of MicroPython on OSX must be compiled with clang,
-# while cross-compile ports require gcc, so we test here for OSX and
-# if necessary override the value of 'CC' set in py/mkenv.mk
-ifeq ($(UNAME_S),Darwin)
-CC = clang
-# Use clang syntax for map file
-LDFLAGS_ARCH = -Wl,-map,$@.map
-else
-# Use gcc syntax for map file
-LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref
-endif
-LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
-
-ifeq ($(MICROPY_FORCE_32BIT),1)
-# Note: you may need to install i386 versions of dependency packages,
-# starting with linux-libc-dev:i386
-ifeq ($(MICROPY_PY_FFI),1)
-ifeq ($(UNAME_S),Linux)
-CFLAGS_MOD += -I/usr/include/i686-linux-gnu
-endif
-endif
-endif
-
-ifeq ($(MICROPY_USE_READLINE),1)
-INC += -I$(MPTOP)/shared/readline
-CFLAGS_MOD += -DMICROPY_USE_READLINE=1
-SHARED_SRC_C_EXTRA += readline/readline.c
-endif
-ifeq ($(MICROPY_USE_READLINE),2)
-CFLAGS_MOD += -DMICROPY_USE_READLINE=2
-LDFLAGS_MOD += -lreadline
-# the following is needed for BSD
-#LDFLAGS_MOD += -ltermcap
-endif
-ifeq ($(MICROPY_PY_TIME),1)
-CFLAGS_MOD += -DMICROPY_PY_TIME=1
-SRC_MOD += modtime.c
-endif
-ifeq ($(MICROPY_PY_TERMIOS),1)
-CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1
-SRC_MOD += modtermios.c
-endif
-ifeq ($(MICROPY_PY_SOCKET),1)
-CFLAGS_MOD += -DMICROPY_PY_SOCKET=1
-SRC_MOD += modsocket.c
-endif
-
-ifeq ($(MICROPY_PY_FFI),1)
-
-ifeq ($(MICROPY_STANDALONE),1)
-LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(MPTOP)/lib/libffi/build_dir/out/lib/libffi-*/include)
- ifeq ($(MICROPY_FORCE_32BIT),1)
- LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib32/libffi.a
- else
- LIBFFI_LDFLAGS_MOD = $(MPTOP)/lib/libffi/build_dir/out/lib/libffi.a
- endif
-else
-LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi)
-LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi)
-endif
-
-ifeq ($(UNAME_S),Linux)
-LIBFFI_LDFLAGS_MOD += -ldl
-endif
-
-CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1
-LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD)
-SRC_MOD += modffi.c
-endif
-
-MAIN_C = main.c
-
-# source files
-SRC_C = $(addprefix ports/unix/,\
- $(MAIN_C) \
- gccollect.c \
- unix_mphal.c \
- input.c \
- modmachine.c \
- moduselect.c \
- alloc.c \
- coverage.c \
- fatfs_port.c \
- $(SRC_MOD) \
- )
-
-SHARED_SRC_C = $(addprefix shared/,\
- libc/printf.c \
- runtime/gchelper_generic.c \
- timeutils/timeutils.c \
- $(SHARED_SRC_C_EXTRA) \
- )
-
-OBJ = $(PY_O)
-OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
-OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
-
-# List of sources for qstr extraction
-SRC_QSTR += $(SRC_C) $(SHARED_SRC_C)
-# Append any auto-generated sources that are needed by sources listed in
-# SRC_QSTR
-SRC_QSTR_AUTO_DEPS +=
-
-include $(MPTOP)/py/mkrules.mk
-
-# Value of configure's --host= option (required for cross-compilation).
-# Deduce it from CROSS_COMPILE by default, but can be overridden.
-ifneq ($(CROSS_COMPILE),)
-CROSS_COMPILE_HOST = --host=$(patsubst %-,%,$(CROSS_COMPILE))
-else
-CROSS_COMPILE_HOST =
-endif
-
-deplibs: libffi
-
-# install-exec-recursive & install-data-am targets are used to avoid building
-# docs and depending on makeinfo
-libffi:
- cd $(MPTOP)/lib/libffi; git clean -d -x -f
- cd $(MPTOP)/lib/libffi; ./autogen.sh
- mkdir -p $(MPTOP)/lib/libffi/build_dir; cd $(MPTOP)/lib/libffi/build_dir; \
- ../configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out CC="$(CC)" CXX="$(CXX)" LD="$(LD)"; \
- make install-exec-recursive; make -C include install-data-am
diff --git a/examples/embedding/README.md b/examples/embedding/README.md
index 0dfc52e1dcad..3f19aff41f25 100644
--- a/examples/embedding/README.md
+++ b/examples/embedding/README.md
@@ -1,67 +1,37 @@
Example of embedding MicroPython in a standalone C application
==============================================================
-This directory contains a (very simple!) example of how to embed a MicroPython
-in an existing C application.
-
-A C application is represented by the file `hello-embed.c`. It executes a simple
-Python statement which prints to the standard output.
+This directory contains a simple example of how to embed MicroPython in an
+existing C application.
+A C application is represented here by the file `main.c`. It executes two
+simple Python scripts which print things to the standard output.
Building the example
--------------------
-Building the example is as simple as running:
-
- make
-
-It's worth to trace what's happening behind the scenes though:
-
-1. As a first step, a MicroPython library is built. This is handled by a
-separate makefile, `Makefile.upylib`. It is more or less complex, but the
-good news is that you won't need to change anything in it, just use it
-as is, the main `Makefile` shows how. What may require editing though is
-a MicroPython configuration file. MicroPython is highly configurable, so
-you would need to build a library suiting your application well, while
-not bloating its size. Check the options in the file `mpconfigport.h`.
-Included is a copy of the "minimal" Unix port, which should be a good start
-for minimal embedding. For the list of all available options, see
-`py/mpconfig.h`.
+First build the embed port using:
-2. Once the MicroPython library is built, your application is compiled
-and linked it. The main Makefile is very simple and shows that the changes
-you would need to do to your application's `Makefile` (or other build
-configuration) are also simple:
+ $ make -f micropython_embed.mk
-a) You would need to use C99 standard (you're using this 15+ years old
-standard already, not a 25+ years old one, right?).
+This will generate the `micropython_embed` directory which is a self-contained
+copy of MicroPython suitable for embedding. The .c files in this directory need
+to be compiled into your project, in whatever way your project can do that. The
+example here uses make and a provided `Makefile`.
-b) You need to provide a path to MicroPython's top-level dir, for includes.
+To build the example project, based on `main.c`, use:
-c) You need to include `-DNO_QSTR` compile-time flag.
+ $ make
-d) Otherwise, just link with the MicroPython library produced in step 1.
+That will create an executable called `embed` which you can run:
+ $ ./embed
Out of tree build
-----------------
This example is set up to work out of the box, being part of the MicroPython
-tree. Your application of course will be outside of its tree, but the
-only thing you need to do is to pass `MPTOP` variable pointing to
-MicroPython directory to both Makefiles (in this example, the main Makefile
-automatically passes it to `Makefile.upylib`; in your own Makefile, don't forget
-to use a suitable value).
-
-A practical way to embed MicroPython in your application is to include it
-as a git submodule. Suppose you included it as `libs/micropython`. Then in
-your main Makefile you would have something like:
-
-~~~
-MPTOP = libs/micropython
-
-my_app: $(MY_OBJS) -lmicropython
-
--lmicropython:
- $(MAKE) -f $(MPTOP)/examples/embedding/Makefile.upylib MPTOP=$(MPTOP)
-~~~
+tree. Your application will be outside of this tree, but the only thing you
+need to do for that is to change `MICROPYTHON_TOP` (found in `micropython_embed.mk`)
+to point to the location of the MicroPython repository. The MicroPython
+repository may, for example, be a git submodule in your project.
diff --git a/examples/embedding/hello-embed.c b/examples/embedding/hello-embed.c
deleted file mode 100644
index 0b778986b3a5..000000000000
--- a/examples/embedding/hello-embed.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/builtin.h"
-#include "py/compile.h"
-#include "py/runtime.h"
-#include "py/gc.h"
-#include "py/stackctrl.h"
-
-static char heap[16384];
-
-mp_obj_t execute_from_str(const char *str) {
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- qstr src_name = 1/*MP_QSTR_*/;
- mp_lexer_t *lex = mp_lexer_new_from_str_len(src_name, str, strlen(str), false);
- mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT);
- mp_obj_t module_fun = mp_compile(&pt, src_name, false);
- mp_call_function_0(module_fun);
- nlr_pop();
- return 0;
- } else {
- // uncaught exception
- return (mp_obj_t)nlr.ret_val;
- }
-}
-
-int main() {
- // Initialized stack limit
- mp_stack_set_limit(40000 * (sizeof(void *) / 4));
- // Initialize heap
- gc_init(heap, heap + sizeof(heap));
- // Initialize interpreter
- mp_init();
-
- const char str[] = "print('Hello world of easy embedding!')";
- if (execute_from_str(str)) {
- printf("Error\n");
- }
-}
-
-uint mp_import_stat(const char *path) {
- return MP_IMPORT_STAT_NO_EXIST;
-}
-
-void nlr_jump_fail(void *val) {
- printf("FATAL: uncaught NLR %p\n", val);
- exit(1);
-}
diff --git a/examples/embedding/main.c b/examples/embedding/main.c
new file mode 100644
index 000000000000..ee673fc93a68
--- /dev/null
+++ b/examples/embedding/main.c
@@ -0,0 +1,44 @@
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2022-2023 Damien P. George
+ */
+
+#include "port/micropython_embed.h"
+
+// This is example 1 script, which will be compiled and executed.
+static const char *example_1 =
+ "print('hello world!', list(x + 1 for x in range(10)), end='eol\\n')";
+
+// This is example 2 script, which will be compiled and executed.
+static const char *example_2 =
+ "for i in range(10):\n"
+ " print('iter {:08}'.format(i))\n"
+ "\n"
+ "try:\n"
+ " 1//0\n"
+ "except Exception as er:\n"
+ " print('caught exception', repr(er))\n"
+ "\n"
+ "import gc\n"
+ "print('run GC collect')\n"
+ "gc.collect()\n"
+ "\n"
+ "print('finish')\n"
+ ;
+
+// This array is the MicroPython GC heap.
+static char heap[8 * 1024];
+
+int main() {
+ // Initialise MicroPython.
+ mp_embed_init(&heap[0], sizeof(heap));
+
+ // Run the example scripts (they will be compiled first).
+ mp_embed_exec_str(example_1);
+ mp_embed_exec_str(example_2);
+
+ // Deinitialise MicroPython.
+ mp_embed_deinit();
+
+ return 0;
+}
diff --git a/examples/embedding/micropython_embed.mk b/examples/embedding/micropython_embed.mk
new file mode 100644
index 000000000000..5db541592750
--- /dev/null
+++ b/examples/embedding/micropython_embed.mk
@@ -0,0 +1,9 @@
+# This file is part of the MicroPython project, http://micropython.org/
+# The MIT License (MIT)
+# Copyright (c) 2022-2023 Damien P. George
+
+# Set the location of the top of the MicroPython repository.
+MICROPYTHON_TOP = ../..
+
+# Include the main makefile fragment to build the MicroPython component.
+include $(MICROPYTHON_TOP)/ports/embed/embed.mk
diff --git a/examples/embedding/mpconfigport.h b/examples/embedding/mpconfigport.h
index 89c180b2a815..ed34a5d766ae 100644
--- a/examples/embedding/mpconfigport.h
+++ b/examples/embedding/mpconfigport.h
@@ -1 +1,15 @@
-#include "mpconfigport_minimal.h"
+/* This file is part of the MicroPython project, http://micropython.org/
+ * The MIT License (MIT)
+ * Copyright (c) 2022-2023 Damien P. George
+ */
+
+// Include common MicroPython embed configuration.
+#include
+
+// Use the minimal starting configuration (disables all optional features).
+#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_MINIMUM)
+
+// MicroPython configuration.
+#define MICROPY_ENABLE_COMPILER (1)
+#define MICROPY_ENABLE_GC (1)
+#define MICROPY_PY_GC (1)
diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h
deleted file mode 100644
index 02089c1a6213..000000000000
--- a/examples/embedding/mpconfigport_minimal.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-// options to control how MicroPython is built
-
-#define MICROPY_ALLOC_PATH_MAX (PATH_MAX)
-#define MICROPY_ENABLE_GC (1)
-#define MICROPY_ENABLE_FINALISER (0)
-#define MICROPY_STACK_CHECK (0)
-#define MICROPY_COMP_CONST (0)
-#define MICROPY_MEM_STATS (0)
-#define MICROPY_DEBUG_PRINTERS (0)
-#define MICROPY_READER_POSIX (1)
-#define MICROPY_KBD_EXCEPTION (1)
-#define MICROPY_HELPER_REPL (1)
-#define MICROPY_HELPER_LEXER_UNIX (1)
-#define MICROPY_ENABLE_SOURCE_LINE (0)
-#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
-#define MICROPY_WARNINGS (0)
-#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
-#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
-#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
-#define MICROPY_STREAMS_NON_BLOCK (0)
-#define MICROPY_OPT_COMPUTED_GOTO (0)
-#define MICROPY_CAN_OVERRIDE_BUILTINS (0)
-#define MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG (0)
-#define MICROPY_CPYTHON_COMPAT (0)
-#define MICROPY_PY_BUILTINS_BYTEARRAY (0)
-#define MICROPY_PY_BUILTINS_MEMORYVIEW (0)
-#define MICROPY_PY_BUILTINS_COMPILE (0)
-#define MICROPY_PY_BUILTINS_ENUMERATE (0)
-#define MICROPY_PY_BUILTINS_FILTER (0)
-#define MICROPY_PY_BUILTINS_FROZENSET (0)
-#define MICROPY_PY_BUILTINS_REVERSED (0)
-#define MICROPY_PY_BUILTINS_SET (0)
-#define MICROPY_PY_BUILTINS_SLICE (0)
-#define MICROPY_PY_BUILTINS_STR_UNICODE (0)
-#define MICROPY_PY_BUILTINS_PROPERTY (0)
-#define MICROPY_PY_BUILTINS_MIN_MAX (0)
-#define MICROPY_PY___FILE__ (0)
-#define MICROPY_PY_MICROPYTHON_MEM_INFO (0)
-#define MICROPY_PY_GC (0)
-#define MICROPY_PY_GC_COLLECT_RETVAL (0)
-#define MICROPY_PY_ARRAY (0)
-#define MICROPY_PY_COLLECTIONS (0)
-#define MICROPY_PY_MATH (0)
-#define MICROPY_PY_CMATH (0)
-#define MICROPY_PY_IO (0)
-#define MICROPY_PY_STRUCT (0)
-#define MICROPY_PY_SYS (1)
-#define MICROPY_PY_SYS_EXIT (0)
-#define MICROPY_PY_SYS_PLATFORM "linux"
-#define MICROPY_PY_SYS_MAXSIZE (0)
-#define MICROPY_PY_SYS_PATH_DEFAULT ".frozen"
-#define MICROPY_PY_SYS_STDFILES (0)
-#define MICROPY_PY_CMATH (0)
-#define MICROPY_PY_UCTYPES (0)
-#define MICROPY_PY_UZLIB (0)
-#define MICROPY_PY_UJSON (0)
-#define MICROPY_PY_UOS (1)
-#define MICROPY_PY_URE (0)
-#define MICROPY_PY_UHEAPQ (0)
-#define MICROPY_PY_UHASHLIB (0)
-#define MICROPY_PY_UBINASCII (0)
-
-//////////////////////////////////////////
-// Do not change anything beyond this line
-//////////////////////////////////////////
-
-#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
-// Fall back to setjmp() implementation for discovery of GC pointers in registers.
-#define MICROPY_GCREGS_SETJMP (1)
-#endif
-
-// type definitions for the specific machine
-
-#ifdef __LP64__
-typedef long mp_int_t; // must be pointer size
-typedef unsigned long mp_uint_t; // must be pointer size
-#else
-// These are definitions for machines where sizeof(int) == sizeof(void*),
-// regardless for actual size.
-typedef int mp_int_t; // must be pointer size
-typedef unsigned int mp_uint_t; // must be pointer size
-#endif
-
-// Cannot include , as it may lead to symbol name clashes
-#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__)
-typedef long long mp_off_t;
-#else
-typedef long mp_off_t;
-#endif
-
-// We need to provide a declaration/definition of alloca()
-#ifdef __FreeBSD__
-#include
-#else
-#include
-#endif
diff --git a/examples/hwapi/README.md b/examples/hwapi/README.md
index df16b4c86be5..a1b0c5642a2f 100644
--- a/examples/hwapi/README.md
+++ b/examples/hwapi/README.md
@@ -5,7 +5,7 @@ which would work from a board to board, from a system to another systems.
This is inherently a hard problem, because hardware is different from one
board type to another, and even from examplar of board to another. For
example, if your app requires an external LED, one user may connect it
-to one GPIO pin, while another user may find it much more convinient to
+to one GPIO pin, while another user may find it much more convenient to
use another pin. This of course applies to relays, buzzers, sensors, etc.
With complications above in mind, it's still possible to write portable
@@ -40,13 +40,13 @@ application of this idea would look like:
`app.py`:
from hwconfig import *
- import utime
+ import time
while True:
LED.value(1)
- utime.sleep_ms(500)
+ time.sleep_ms(500)
LED.value(0)
- utime.sleep_ms(500)
+ time.sleep_ms(500)
To deploy this application to a particular board, a user will need:
diff --git a/examples/hwapi/button_led.py b/examples/hwapi/button_led.py
index bd6fe0172988..c73bcfc89a29 100644
--- a/examples/hwapi/button_led.py
+++ b/examples/hwapi/button_led.py
@@ -1,4 +1,4 @@
-import utime
+import time
from hwconfig import LED, BUTTON
# Light LED when (and while) a BUTTON is pressed
@@ -6,4 +6,4 @@
while 1:
LED.value(BUTTON.value())
# Don't burn CPU
- utime.sleep_ms(10)
+ time.sleep_ms(10)
diff --git a/examples/hwapi/button_reaction.py b/examples/hwapi/button_reaction.py
index e5a139a575f2..52bdf793849e 100644
--- a/examples/hwapi/button_reaction.py
+++ b/examples/hwapi/button_reaction.py
@@ -1,4 +1,4 @@
-import utime
+import time
import machine
from hwconfig import LED, BUTTON
@@ -18,4 +18,4 @@
print("Well, you're *really* slow")
else:
print("You are as slow as %d microseconds!" % delay)
- utime.sleep_ms(10)
+ time.sleep_ms(10)
diff --git a/examples/hwapi/hwconfig_pyboard.py b/examples/hwapi/hwconfig_pyboard.py
index a74a1ae151bb..cb77e9f2d682 100644
--- a/examples/hwapi/hwconfig_pyboard.py
+++ b/examples/hwapi/hwconfig_pyboard.py
@@ -1,6 +1,6 @@
from machine import Pin, Signal
-# Red LED on pin LED_RED also kown as A13
+# Red LED on pin LED_RED also known as A13
LED = Signal("LED_RED", Pin.OUT)
# Green LED on pin LED_GREEN also known as A14
diff --git a/examples/hwapi/soft_pwm.py b/examples/hwapi/soft_pwm.py
index 72291b0ecde5..466de08f09b6 100644
--- a/examples/hwapi/soft_pwm.py
+++ b/examples/hwapi/soft_pwm.py
@@ -1,4 +1,4 @@
-import utime
+import time
from hwconfig import LED
@@ -15,10 +15,10 @@ def pwm_cycle(led, duty, cycles):
for i in range(cycles):
if duty:
led.on()
- utime.sleep_ms(duty)
+ time.sleep_ms(duty)
if duty_off:
led.off()
- utime.sleep_ms(duty_off)
+ time.sleep_ms(duty_off)
# At the duty setting of 1, an LED is still pretty bright, then
diff --git a/examples/hwapi/soft_pwm2_asyncio.py b/examples/hwapi/soft_pwm2_asyncio.py
new file mode 100644
index 000000000000..689499004327
--- /dev/null
+++ b/examples/hwapi/soft_pwm2_asyncio.py
@@ -0,0 +1,31 @@
+# Like soft_pwm_asyncio.py, but fading 2 LEDs with different phase.
+# Also see original soft_pwm.py.
+import asyncio
+from hwconfig import LED, LED2
+
+
+async def pwm_cycle(led, duty, cycles):
+ duty_off = 20 - duty
+ for i in range(cycles):
+ if duty:
+ led.value(1)
+ await asyncio.sleep_ms(duty)
+ if duty_off:
+ led.value(0)
+ await asyncio.sleep_ms(duty_off)
+
+
+async def fade_in_out(LED):
+ while True:
+ # Fade in
+ for i in range(1, 21):
+ await pwm_cycle(LED, i, 2)
+ # Fade out
+ for i in range(20, 0, -1):
+ await pwm_cycle(LED, i, 2)
+
+
+loop = asyncio.get_event_loop()
+loop.create_task(fade_in_out(LED))
+loop.call_later_ms(800, fade_in_out(LED2))
+loop.run_forever()
diff --git a/examples/hwapi/soft_pwm2_uasyncio.py b/examples/hwapi/soft_pwm2_uasyncio.py
deleted file mode 100644
index 908ef2d8ac20..000000000000
--- a/examples/hwapi/soft_pwm2_uasyncio.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Like soft_pwm_uasyncio.py, but fading 2 LEDs with different phase.
-# Also see original soft_pwm.py.
-import uasyncio
-from hwconfig import LED, LED2
-
-
-async def pwm_cycle(led, duty, cycles):
- duty_off = 20 - duty
- for i in range(cycles):
- if duty:
- led.value(1)
- await uasyncio.sleep_ms(duty)
- if duty_off:
- led.value(0)
- await uasyncio.sleep_ms(duty_off)
-
-
-async def fade_in_out(LED):
- while True:
- # Fade in
- for i in range(1, 21):
- await pwm_cycle(LED, i, 2)
- # Fade out
- for i in range(20, 0, -1):
- await pwm_cycle(LED, i, 2)
-
-
-loop = uasyncio.get_event_loop()
-loop.create_task(fade_in_out(LED))
-loop.call_later_ms(800, fade_in_out(LED2))
-loop.run_forever()
diff --git a/examples/hwapi/soft_pwm_asyncio.py b/examples/hwapi/soft_pwm_asyncio.py
new file mode 100644
index 000000000000..ae6c7340f6fd
--- /dev/null
+++ b/examples/hwapi/soft_pwm_asyncio.py
@@ -0,0 +1,28 @@
+# See original soft_pwm.py for detailed comments.
+import asyncio
+from hwconfig import LED
+
+
+async def pwm_cycle(led, duty, cycles):
+ duty_off = 20 - duty
+ for i in range(cycles):
+ if duty:
+ led.value(1)
+ await asyncio.sleep_ms(duty)
+ if duty_off:
+ led.value(0)
+ await asyncio.sleep_ms(duty_off)
+
+
+async def fade_in_out(LED):
+ while True:
+ # Fade in
+ for i in range(1, 21):
+ await pwm_cycle(LED, i, 2)
+ # Fade out
+ for i in range(20, 0, -1):
+ await pwm_cycle(LED, i, 2)
+
+
+loop = asyncio.get_event_loop()
+loop.run_until_complete(fade_in_out(LED))
diff --git a/examples/hwapi/soft_pwm_uasyncio.py b/examples/hwapi/soft_pwm_uasyncio.py
deleted file mode 100644
index 8d7ad8c9e07b..000000000000
--- a/examples/hwapi/soft_pwm_uasyncio.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# See original soft_pwm.py for detailed comments.
-import uasyncio
-from hwconfig import LED
-
-
-async def pwm_cycle(led, duty, cycles):
- duty_off = 20 - duty
- for i in range(cycles):
- if duty:
- led.value(1)
- await uasyncio.sleep_ms(duty)
- if duty_off:
- led.value(0)
- await uasyncio.sleep_ms(duty_off)
-
-
-async def fade_in_out(LED):
- while True:
- # Fade in
- for i in range(1, 21):
- await pwm_cycle(LED, i, 2)
- # Fade out
- for i in range(20, 0, -1):
- await pwm_cycle(LED, i, 2)
-
-
-loop = uasyncio.get_event_loop()
-loop.run_until_complete(fade_in_out(LED))
diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile
new file mode 100644
index 000000000000..86ef29b6324b
--- /dev/null
+++ b/examples/natmod/deflate/Makefile
@@ -0,0 +1,13 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module (different to built-in uzlib so it can coexist)
+MOD = deflate_$(ARCH)
+
+# Source files (.c or .py)
+SRC = deflate.c
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/deflate/deflate.c b/examples/natmod/deflate/deflate.c
new file mode 100644
index 000000000000..fa475bd06724
--- /dev/null
+++ b/examples/natmod/deflate/deflate.c
@@ -0,0 +1,70 @@
+#define MICROPY_PY_DEFLATE (1)
+#define MICROPY_PY_DEFLATE_COMPRESS (1)
+
+#include "py/dynruntime.h"
+
+#if !defined(__linux__)
+void *memcpy(void *dst, const void *src, size_t n) {
+ return mp_fun_table.memmove_(dst, src, n);
+}
+void *memset(void *s, int c, size_t n) {
+ return mp_fun_table.memset_(s, c, n);
+}
+#endif
+
+mp_obj_full_type_t deflateio_type;
+
+#include "extmod/moddeflate.c"
+
+// Re-implemented from py/stream.c, not yet available in dynruntime.h.
+mp_obj_t mp_stream_close(mp_obj_t stream) {
+ const mp_stream_p_t *stream_p = mp_get_stream(stream);
+ int error;
+ mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
+ if (res == MP_STREAM_ERROR) {
+ mp_raise_OSError(error);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close);
+
+// Re-implemented from py/stream.c, not yet available in dynruntime.h.
+STATIC mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return mp_stream_close(args[0]);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj, 4, 4, mp_stream___exit__);
+
+// Re-implemented from obj.c, not yet available in dynruntime.h.
+mp_obj_t mp_identity(mp_obj_t self) {
+ return self;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
+
+mp_map_elem_t deflateio_locals_dict_table[7];
+STATIC MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
+
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ deflateio_type.base.type = mp_fun_table.type_type;
+ deflateio_type.name = MP_QSTR_DeflateIO;
+ MP_OBJ_TYPE_SET_SLOT(&deflateio_type, make_new, &deflateio_make_new, 0);
+ MP_OBJ_TYPE_SET_SLOT(&deflateio_type, protocol, &deflateio_stream_p, 1);
+ deflateio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) };
+ deflateio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) };
+ deflateio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) };
+ deflateio_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_OBJ_FROM_PTR(&mp_stream_write_obj) };
+ deflateio_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&mp_stream_close_obj) };
+ deflateio_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___enter__), MP_OBJ_FROM_PTR(&mp_identity_obj) };
+ deflateio_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___exit__), MP_OBJ_FROM_PTR(&mp_stream___exit___obj) };
+ MP_OBJ_TYPE_SET_SLOT(&deflateio_type, locals_dict, (void*)&deflateio_locals_dict, 2);
+
+ mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_deflate));
+ mp_store_global(MP_QSTR_DeflateIO, MP_OBJ_FROM_PTR(&deflateio_type));
+ mp_store_global(MP_QSTR_RAW, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_RAW));
+ mp_store_global(MP_QSTR_ZLIB, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_ZLIB));
+ mp_store_global(MP_QSTR_GZIP, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_GZIP));
+
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c
index f865f1887cd0..d2494b213886 100644
--- a/examples/natmod/features1/features1.c
+++ b/examples/natmod/features1/features1.c
@@ -88,7 +88,7 @@ mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *a
// This must be first, it sets up the globals dict and other things
MP_DYNRUNTIME_INIT_ENTRY
- // Messages can be printed as usualy
+ // Messages can be printed as usual
mp_printf(&mp_plat_print, "initialising module self=%p\n", self);
// Make the functions available in the module's namespace
diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile
new file mode 100644
index 000000000000..af45b472da1a
--- /dev/null
+++ b/examples/natmod/heapq/Makefile
@@ -0,0 +1,13 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module (different to built-in heapq so it can coexist)
+MOD = heapq_$(ARCH)
+
+# Source files (.c or .py)
+SRC = heapq.c
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/heapq/heapq.c b/examples/natmod/heapq/heapq.c
new file mode 100644
index 000000000000..ed19652a66b1
--- /dev/null
+++ b/examples/natmod/heapq/heapq.c
@@ -0,0 +1,16 @@
+#define MICROPY_PY_HEAPQ (1)
+
+#include "py/dynruntime.h"
+
+#include "extmod/modheapq.c"
+
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_heapq));
+ mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_heapq_heappush_obj));
+ mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_heapq_heappop_obj));
+ mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_heapq_heapify_obj));
+
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/random/Makefile b/examples/natmod/random/Makefile
new file mode 100644
index 000000000000..5c50227b15f9
--- /dev/null
+++ b/examples/natmod/random/Makefile
@@ -0,0 +1,13 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module (different to built-in random so it can coexist)
+MOD = random_$(ARCH)
+
+# Source files (.c or .py)
+SRC = random.c
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/random/random.c b/examples/natmod/random/random.c
new file mode 100644
index 000000000000..92257b8bc681
--- /dev/null
+++ b/examples/natmod/random/random.c
@@ -0,0 +1,33 @@
+#define MICROPY_PY_RANDOM (1)
+#define MICROPY_PY_RANDOM_EXTRA_FUNCS (1)
+
+#include "py/dynruntime.h"
+
+// Dynamic native modules don't support a data section so these must go in the BSS
+uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
+uint8_t yasmarang_dat;
+
+#include "extmod/modrandom.c"
+
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ yasmarang_pad = 0xeda4baba;
+ yasmarang_n = 69;
+ yasmarang_d = 233;
+
+ mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_random));
+ mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_random_getrandbits_obj));
+ mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_random_seed_obj));
+ #if MICROPY_PY_RANDOM_EXTRA_FUNCS
+ mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_random_randrange_obj));
+ mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_random_randint_obj));
+ mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_random_choice_obj));
+ #if MICROPY_PY_BUILTINS_FLOAT
+ mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_random_random_obj));
+ mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_random_uniform_obj));
+ #endif
+ #endif
+
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/re/Makefile b/examples/natmod/re/Makefile
new file mode 100644
index 000000000000..1ba540110650
--- /dev/null
+++ b/examples/natmod/re/Makefile
@@ -0,0 +1,13 @@
+# Location of top-level MicroPython directory
+MPY_DIR = ../../..
+
+# Name of module (different to built-in re so it can coexist)
+MOD = re_$(ARCH)
+
+# Source files (.c or .py)
+SRC = re.c
+
+# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
+ARCH = x64
+
+include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/re/re.c b/examples/natmod/re/re.c
new file mode 100644
index 000000000000..df89ea83530e
--- /dev/null
+++ b/examples/natmod/re/re.c
@@ -0,0 +1,78 @@
+#define MICROPY_STACK_CHECK (1)
+#define MICROPY_PY_RE (1)
+#define MICROPY_PY_RE_MATCH_GROUPS (1)
+#define MICROPY_PY_RE_MATCH_SPAN_START_END (1)
+#define MICROPY_PY_RE_SUB (0) // requires vstr interface
+
+#include
+#include "py/dynruntime.h"
+
+#define STACK_LIMIT (2048)
+
+const char *stack_top;
+
+void mp_stack_check(void) {
+ // Assumes descending stack on target
+ volatile char dummy;
+ if (stack_top - &dummy >= STACK_LIMIT) {
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("maximum recursion depth exceeded"));
+ }
+}
+
+#if !defined(__linux__)
+void *memcpy(void *dst, const void *src, size_t n) {
+ return mp_fun_table.memmove_(dst, src, n);
+}
+void *memset(void *s, int c, size_t n) {
+ return mp_fun_table.memset_(s, c, n);
+}
+#endif
+
+void *memmove(void *dest, const void *src, size_t n) {
+ return mp_fun_table.memmove_(dest, src, n);
+}
+
+mp_obj_full_type_t match_type;
+mp_obj_full_type_t re_type;
+
+#include "extmod/modre.c"
+
+mp_map_elem_t match_locals_dict_table[5];
+STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
+
+mp_map_elem_t re_locals_dict_table[3];
+STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
+
+mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
+ MP_DYNRUNTIME_INIT_ENTRY
+
+ char dummy;
+ stack_top = &dummy;
+
+ // Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section
+ // to copy in this key/value pair if they are specified as a struct, so assign them separately.
+
+ match_type.base.type = (void*)&mp_fun_table.type_type;
+ match_type.name = MP_QSTR_match;
+ MP_OBJ_TYPE_SET_SLOT(&match_type, print, match_print, 0);
+ match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) };
+ match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) };
+ match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) };
+ match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) };
+ match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) };
+ MP_OBJ_TYPE_SET_SLOT(&match_type, locals_dict, (void*)&match_locals_dict, 1);
+
+ re_type.base.type = (void*)&mp_fun_table.type_type;
+ re_type.name = MP_QSTR_re;
+ MP_OBJ_TYPE_SET_SLOT(&re_type, print, re_print, 0);
+ re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) };
+ re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) };
+ re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) };
+ MP_OBJ_TYPE_SET_SLOT(&re_type, locals_dict, (void*)&re_locals_dict, 1);
+
+ mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj));
+ mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj));
+ mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&re_search_obj));
+
+ MP_DYNRUNTIME_INIT_EXIT
+}
diff --git a/examples/natmod/uheapq/Makefile b/examples/natmod/uheapq/Makefile
deleted file mode 100644
index 55de3cc08185..000000000000
--- a/examples/natmod/uheapq/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Location of top-level MicroPython directory
-MPY_DIR = ../../..
-
-# Name of module (different to built-in uheapq so it can coexist)
-MOD = uheapq_$(ARCH)
-
-# Source files (.c or .py)
-SRC = uheapq.c
-
-# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
-ARCH = x64
-
-include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/uheapq/uheapq.c b/examples/natmod/uheapq/uheapq.c
deleted file mode 100644
index 9da6bb4ada4b..000000000000
--- a/examples/natmod/uheapq/uheapq.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#define MICROPY_PY_UHEAPQ (1)
-
-#include "py/dynruntime.h"
-
-#include "extmod/moduheapq.c"
-
-mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
- MP_DYNRUNTIME_INIT_ENTRY
-
- mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uheapq));
- mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_uheapq_heappush_obj));
- mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_uheapq_heappop_obj));
- mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_uheapq_heapify_obj));
-
- MP_DYNRUNTIME_INIT_EXIT
-}
diff --git a/examples/natmod/urandom/Makefile b/examples/natmod/urandom/Makefile
deleted file mode 100644
index 3f018baaf76b..000000000000
--- a/examples/natmod/urandom/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Location of top-level MicroPython directory
-MPY_DIR = ../../..
-
-# Name of module (different to built-in urandom so it can coexist)
-MOD = urandom_$(ARCH)
-
-# Source files (.c or .py)
-SRC = urandom.c
-
-# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
-ARCH = x64
-
-include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/urandom/urandom.c b/examples/natmod/urandom/urandom.c
deleted file mode 100644
index e1fed6a554fc..000000000000
--- a/examples/natmod/urandom/urandom.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#define MICROPY_PY_URANDOM (1)
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
-
-#include "py/dynruntime.h"
-
-// Dynamic native modules don't support a data section so these must go in the BSS
-uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
-uint8_t yasmarang_dat;
-
-#include "extmod/modurandom.c"
-
-mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
- MP_DYNRUNTIME_INIT_ENTRY
-
- yasmarang_pad = 0xeda4baba;
- yasmarang_n = 69;
- yasmarang_d = 233;
-
- mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_urandom));
- mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_urandom_getrandbits_obj));
- mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_urandom_seed_obj));
- #if MICROPY_PY_URANDOM_EXTRA_FUNCS
- mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_urandom_randrange_obj));
- mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_urandom_randint_obj));
- mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_urandom_choice_obj));
- #if MICROPY_PY_BUILTINS_FLOAT
- mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_urandom_random_obj));
- mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_urandom_uniform_obj));
- #endif
- #endif
-
- MP_DYNRUNTIME_INIT_EXIT
-}
diff --git a/examples/natmod/ure/Makefile b/examples/natmod/ure/Makefile
deleted file mode 100644
index f5254298fdd9..000000000000
--- a/examples/natmod/ure/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Location of top-level MicroPython directory
-MPY_DIR = ../../..
-
-# Name of module (different to built-in ure so it can coexist)
-MOD = ure_$(ARCH)
-
-# Source files (.c or .py)
-SRC = ure.c
-
-# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
-ARCH = x64
-
-include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/ure/ure.c b/examples/natmod/ure/ure.c
deleted file mode 100644
index d4bd680abd42..000000000000
--- a/examples/natmod/ure/ure.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#define MICROPY_STACK_CHECK (1)
-#define MICROPY_PY_URE (1)
-#define MICROPY_PY_URE_MATCH_GROUPS (1)
-#define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
-#define MICROPY_PY_URE_SUB (0) // requires vstr interface
-
-#include
-#include "py/dynruntime.h"
-
-#define STACK_LIMIT (2048)
-
-const char *stack_top;
-
-void mp_stack_check(void) {
- // Assumes descending stack on target
- volatile char dummy;
- if (stack_top - &dummy >= STACK_LIMIT) {
- mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("maximum recursion depth exceeded"));
- }
-}
-
-#if !defined(__linux__)
-void *memcpy(void *dst, const void *src, size_t n) {
- return mp_fun_table.memmove_(dst, src, n);
-}
-void *memset(void *s, int c, size_t n) {
- return mp_fun_table.memset_(s, c, n);
-}
-#endif
-
-void *memmove(void *dest, const void *src, size_t n) {
- return mp_fun_table.memmove_(dest, src, n);
-}
-
-mp_obj_full_type_t match_type;
-mp_obj_full_type_t re_type;
-
-#include "extmod/modure.c"
-
-mp_map_elem_t match_locals_dict_table[5];
-STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
-
-mp_map_elem_t re_locals_dict_table[3];
-STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
-
-mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
- MP_DYNRUNTIME_INIT_ENTRY
-
- char dummy;
- stack_top = &dummy;
-
- // Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section
- // to copy in this key/value pair if they are specified as a struct, so assign them separately.
-
- match_type.base.type = (void*)&mp_fun_table.type_type;
- match_type.name = MP_QSTR_match;
- MP_OBJ_TYPE_SET_SLOT(&match_type, print, match_print, 0);
- match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) };
- match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) };
- match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) };
- match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) };
- match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) };
- MP_OBJ_TYPE_SET_SLOT(&match_type, locals_dict, (void*)&match_locals_dict, 1);
-
- re_type.base.type = (void*)&mp_fun_table.type_type;
- re_type.name = MP_QSTR_ure;
- MP_OBJ_TYPE_SET_SLOT(&re_type, print, re_print, 0);
- re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) };
- re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) };
- re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) };
- MP_OBJ_TYPE_SET_SLOT(&re_type, locals_dict, (void*)&re_locals_dict, 1);
-
- mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj));
- mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj));
- mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&re_search_obj));
-
- MP_DYNRUNTIME_INIT_EXIT
-}
diff --git a/examples/natmod/uzlib/Makefile b/examples/natmod/uzlib/Makefile
deleted file mode 100644
index 8761caf2dd26..000000000000
--- a/examples/natmod/uzlib/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# Location of top-level MicroPython directory
-MPY_DIR = ../../..
-
-# Name of module (different to built-in uzlib so it can coexist)
-MOD = uzlib_$(ARCH)
-
-# Source files (.c or .py)
-SRC = uzlib.c
-
-# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
-ARCH = x64
-
-include $(MPY_DIR)/py/dynruntime.mk
diff --git a/examples/natmod/uzlib/uzlib.c b/examples/natmod/uzlib/uzlib.c
deleted file mode 100644
index 9cf58b10e78e..000000000000
--- a/examples/natmod/uzlib/uzlib.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#define MICROPY_PY_UZLIB (1)
-
-#include "py/dynruntime.h"
-
-#if !defined(__linux__)
-void *memset(void *s, int c, size_t n) {
- return mp_fun_table.memset_(s, c, n);
-}
-#endif
-
-mp_obj_full_type_t decompio_type;
-
-#include "extmod/moduzlib.c"
-
-mp_map_elem_t decompio_locals_dict_table[3];
-STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
-
-mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
- MP_DYNRUNTIME_INIT_ENTRY
-
- decompio_type.base.type = mp_fun_table.type_type;
- decompio_type.name = MP_QSTR_DecompIO;
- MP_OBJ_TYPE_SET_SLOT(&decompio_type, make_new, &decompio_make_new, 0);
- MP_OBJ_TYPE_SET_SLOT(&decompio_type, protocol, &decompio_stream_p, 1);
- decompio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) };
- decompio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) };
- decompio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) };
- MP_OBJ_TYPE_SET_SLOT(&decompio_type, locals_dict, (void*)&decompio_locals_dict, 2);
-
- mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_uzlib));
- mp_store_global(MP_QSTR_decompress, MP_OBJ_FROM_PTR(&mod_uzlib_decompress_obj));
- mp_store_global(MP_QSTR_DecompIO, MP_OBJ_FROM_PTR(&decompio_type));
-
- MP_DYNRUNTIME_INIT_EXIT
-}
diff --git a/examples/network/http_client.py b/examples/network/http_client.py
index 0791c8066b67..661c286b70bc 100644
--- a/examples/network/http_client.py
+++ b/examples/network/http_client.py
@@ -1,7 +1,4 @@
-try:
- import usocket as socket
-except:
- import socket
+import socket
def main(use_stream=False):
diff --git a/examples/network/http_client_ssl.py b/examples/network/http_client_ssl.py
index 83f685fdf35d..323971c0ee24 100644
--- a/examples/network/http_client_ssl.py
+++ b/examples/network/http_client_ssl.py
@@ -1,17 +1,11 @@
-try:
- import usocket as _socket
-except:
- import _socket
-try:
- import ussl as ssl
-except:
- import ssl
+import socket
+import ssl
def main(use_stream=True):
- s = _socket.socket()
+ s = socket.socket()
- ai = _socket.getaddrinfo("google.com", 443)
+ ai = socket.getaddrinfo("google.com", 443)
print("Address infos:", ai)
addr = ai[0][-1]
diff --git a/examples/network/http_server.py b/examples/network/http_server.py
index 76be3ab8173b..a6ed53154a4e 100644
--- a/examples/network/http_server.py
+++ b/examples/network/http_server.py
@@ -1,7 +1,4 @@
-try:
- import usocket as socket
-except:
- import socket
+import socket
CONTENT = b"""\
diff --git a/examples/network/http_server_simplistic.py b/examples/network/http_server_simplistic.py
index 71949419e67b..09936b9d91ea 100644
--- a/examples/network/http_server_simplistic.py
+++ b/examples/network/http_server_simplistic.py
@@ -1,9 +1,6 @@
# Do not use this code in real projects! Read
# http_server_simplistic_commented.py for details.
-try:
- import usocket as socket
-except:
- import socket
+import socket
CONTENT = b"""\
@@ -28,7 +25,6 @@ def main():
while True:
res = s.accept()
client_s = res[0]
- client_addr = res[1]
req = client_s.recv(4096)
print("Request:")
print(req)
diff --git a/examples/network/http_server_simplistic_commented.py b/examples/network/http_server_simplistic_commented.py
index da042c6c8a56..d4710ad61a61 100644
--- a/examples/network/http_server_simplistic_commented.py
+++ b/examples/network/http_server_simplistic_commented.py
@@ -8,10 +8,7 @@
# details, and use this code only for quick hacks, preferring
# http_server.py for "real thing".
#
-try:
- import usocket as socket
-except:
- import socket
+import socket
CONTENT = b"""\
diff --git a/examples/network/http_server_ssl.py b/examples/network/http_server_ssl.py
index 1116c71e996a..7766fa7ea566 100644
--- a/examples/network/http_server_ssl.py
+++ b/examples/network/http_server_ssl.py
@@ -1,10 +1,6 @@
-import ubinascii as binascii
-
-try:
- import usocket as socket
-except:
- import socket
-import ussl as ssl
+import binascii
+import socket
+import ssl
# This self-signed key/cert pair is randomly generated and to be used for
diff --git a/examples/rp2/pio_1hz.py b/examples/rp2/pio_1hz.py
index c18aa22fc0ec..84d761fa1434 100644
--- a/examples/rp2/pio_1hz.py
+++ b/examples/rp2/pio_1hz.py
@@ -1,4 +1,5 @@
# Example using PIO to blink an LED and raise an IRQ at 1Hz.
+# Note: this does not work on Pico W because it uses Pin(25) for LED output.
import time
from machine import Pin
@@ -16,9 +17,10 @@ def blink_1hz():
nop() [29]
jmp(x_dec, "delay_high")
- # Cycles: 1 + 7 + 32 * (30 + 1) = 1000
+ # Cycles: 1 + 1 + 6 + 32 * (30 + 1) = 1000
+ nop()
set(pins, 0)
- set(x, 31) [6]
+ set(x, 31) [5]
label("delay_low")
nop() [29]
jmp(x_dec, "delay_low")
diff --git a/examples/rp2/pio_exec.py b/examples/rp2/pio_exec.py
index d8cbc33ef015..ce39f2df8430 100644
--- a/examples/rp2/pio_exec.py
+++ b/examples/rp2/pio_exec.py
@@ -1,4 +1,5 @@
# Example using PIO to turn on an LED via an explicit exec.
+# Note: this does not work on Pico W because it uses Pin(25) for LED output.
#
# Demonstrates:
# - using set_init and set_base
@@ -8,6 +9,7 @@
from machine import Pin
import rp2
+
# Define an empty program that uses a single set pin.
@rp2.asm_pio(set_init=rp2.PIO.OUT_LOW)
def prog():
diff --git a/examples/rp2/pio_uart_tx.py b/examples/rp2/pio_uart_tx.py
index 0f8c1260bd7d..5e4af8f6ccfd 100644
--- a/examples/rp2/pio_uart_tx.py
+++ b/examples/rp2/pio_uart_tx.py
@@ -33,6 +33,7 @@ def uart_tx():
sm.active(1)
uarts.append(sm)
+
# We can print characters from each UART by pushing them to the TX FIFO
def pio_uart_print(sm, s):
for c in s:
diff --git a/examples/rp2/pwm_fade.py b/examples/rp2/pwm_fade.py
index 7264edaa293a..5b7089c6b1ad 100644
--- a/examples/rp2/pwm_fade.py
+++ b/examples/rp2/pwm_fade.py
@@ -1,4 +1,5 @@
# Example using PWM to fade an LED.
+# Note: this does not work on Pico W because it uses Pin(25) for LED output.
import time
from machine import Pin, PWM
diff --git a/examples/unix/machine_bios.py b/examples/unix/machine_bios.py
index 878f3fd8f3c5..40aae4ccefe6 100644
--- a/examples/unix/machine_bios.py
+++ b/examples/unix/machine_bios.py
@@ -4,6 +4,6 @@
# It is expected to print 0xaa55, which is a signature at the start of
# Video BIOS.
-import umachine as machine
+import machine
print(hex(machine.mem16[0xC0000]))
diff --git a/examples/usercmodule/cexample/examplemodule.c b/examples/usercmodule/cexample/examplemodule.c
index 93a58be2ed28..9416613ba952 100644
--- a/examples/usercmodule/cexample/examplemodule.c
+++ b/examples/usercmodule/cexample/examplemodule.c
@@ -1,6 +1,9 @@
// Include MicroPython API.
#include "py/runtime.h"
+// Used to get the time in the Timer class example.
+#include "py/mphal.h"
+
// This is the function which will be called from Python as cexample.add_ints(a, b).
STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// Extract the ints from the micropython input objects.
@@ -13,7 +16,59 @@ STATIC mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) {
// Define a Python reference to the function above.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
-// Define all properties of the module.
+// This structure represents Timer instance objects.
+typedef struct _example_Timer_obj_t {
+ // All objects start with the base.
+ mp_obj_base_t base;
+ // Everything below can be thought of as instance attributes, but they
+ // cannot be accessed by MicroPython code directly. In this example we
+ // store the time at which the object was created.
+ mp_uint_t start_time;
+} example_Timer_obj_t;
+
+// This is the Timer.time() method. After creating a Timer object, this
+// can be called to get the time elapsed since creating the Timer.
+STATIC mp_obj_t example_Timer_time(mp_obj_t self_in) {
+ // The first argument is self. It is cast to the *example_Timer_obj_t
+ // type so we can read its attributes.
+ example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // Get the elapsed time and return it as a MicroPython integer.
+ mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time;
+ return mp_obj_new_int_from_uint(elapsed);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(example_Timer_time_obj, example_Timer_time);
+
+// This represents Timer.__new__ and Timer.__init__, which is called when
+// the user instantiates a Timer object.
+STATIC mp_obj_t example_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ // Allocates the new object and sets the type.
+ example_Timer_obj_t *self = mp_obj_malloc(example_Timer_obj_t, type);
+
+ // Initializes the time for this Timer instance.
+ self->start_time = mp_hal_ticks_ms();
+
+ // The make_new function always returns self.
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// This collects all methods and other static class attributes of the Timer.
+// The table structure is similar to the module table, as detailed below.
+STATIC const mp_rom_map_elem_t example_Timer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&example_Timer_time_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(example_Timer_locals_dict, example_Timer_locals_dict_table);
+
+// This defines the type(Timer) object.
+MP_DEFINE_CONST_OBJ_TYPE(
+ example_type_Timer,
+ MP_QSTR_Timer,
+ MP_TYPE_FLAG_NONE,
+ make_new, example_Timer_make_new,
+ locals_dict, &example_Timer_locals_dict
+ );
+
+// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
@@ -21,6 +76,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints);
STATIC const mp_rom_map_elem_t example_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) },
{ MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) },
+ { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&example_type_Timer) },
};
STATIC MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table);
diff --git a/examples/usercmodule/cexample/micropython.mk b/examples/usercmodule/cexample/micropython.mk
index dbfe3c5cbdb1..d6801dac0ba5 100644
--- a/examples/usercmodule/cexample/micropython.mk
+++ b/examples/usercmodule/cexample/micropython.mk
@@ -1,9 +1,8 @@
-EXAMPLE_MOD_DIR := $(USERMOD_DIR)
+CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
-SRC_USERMOD += $(EXAMPLE_MOD_DIR)/examplemodule.c
+SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c
# We can add our module folder to include paths if needed
# This is not actually needed in this example.
-CFLAGS_USERMOD += -I$(EXAMPLE_MOD_DIR)
-CEXAMPLE_MOD_DIR := $(USERMOD_DIR)
+CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR)
diff --git a/examples/usercmodule/cppexample/examplemodule.c b/examples/usercmodule/cppexample/examplemodule.c
index 5c84eccd7996..96a1a7443884 100644
--- a/examples/usercmodule/cppexample/examplemodule.c
+++ b/examples/usercmodule/cppexample/examplemodule.c
@@ -4,7 +4,7 @@
// See example.cpp for the definition.
STATIC MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc);
-// Define all properties of the module.
+// Define all attributes of the module.
// Table entries are key/value pairs of the attribute name (a string)
// and the MicroPython object reference.
// All identifiers and strings are written as MP_QSTR_xxx and will be
diff --git a/examples/usercmodule/subpackage/README.md b/examples/usercmodule/subpackage/README.md
new file mode 100644
index 000000000000..c7f2ee53a240
--- /dev/null
+++ b/examples/usercmodule/subpackage/README.md
@@ -0,0 +1 @@
+This is an example of a user C module that includes subpackages.
diff --git a/examples/usercmodule/subpackage/micropython.cmake b/examples/usercmodule/subpackage/micropython.cmake
new file mode 100644
index 000000000000..a51e7a80613d
--- /dev/null
+++ b/examples/usercmodule/subpackage/micropython.cmake
@@ -0,0 +1,19 @@
+# Create an INTERFACE library for our C module.
+add_library(usermod_subpackage_example INTERFACE)
+
+# Add our source files to the lib
+target_sources(usermod_subpackage_example INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c
+)
+
+# Add the current directory as an include directory.
+target_include_directories(usermod_subpackage_example INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}
+)
+
+target_compile_definitions(usermod_subpackage_example INTERFACE
+ MICROPY_MODULE_BUILTIN_SUBPACKAGES=1
+)
+
+# Link our INTERFACE library to the usermod target.
+target_link_libraries(usermod INTERFACE usermod_subpackage_example)
diff --git a/examples/usercmodule/subpackage/micropython.mk b/examples/usercmodule/subpackage/micropython.mk
new file mode 100644
index 000000000000..99ebf13ec19a
--- /dev/null
+++ b/examples/usercmodule/subpackage/micropython.mk
@@ -0,0 +1,10 @@
+SUBPACKAGE_EXAMPLE_MOD_DIR := $(USERMOD_DIR)
+
+# Add all C files to SRC_USERMOD.
+SRC_USERMOD += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/modexamplepackage.c
+
+# We can add our module folder to include paths if needed
+# This is not actually needed in this example.
+CFLAGS_USERMOD += -I$(SUBPACKAGE_EXAMPLE_MOD_DIR) -DMICROPY_MODULE_BUILTIN_SUBPACKAGES=1
+
+QSTR_DEFS += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/qstrdefsexamplepackage.h
diff --git a/examples/usercmodule/subpackage/modexamplepackage.c b/examples/usercmodule/subpackage/modexamplepackage.c
new file mode 100644
index 000000000000..70e1e4005b30
--- /dev/null
+++ b/examples/usercmodule/subpackage/modexamplepackage.c
@@ -0,0 +1,84 @@
+// Include MicroPython API.
+#include "py/runtime.h"
+
+// Define example_package.foo.bar.f()
+STATIC mp_obj_t example_package_foo_bar_f(void) {
+ mp_printf(&mp_plat_print, "example_package.foo.bar.f\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_bar_f_obj, example_package_foo_bar_f);
+
+// Define all attributes of the second-level sub-package (example_package.foo.bar).
+STATIC const mp_rom_map_elem_t example_package_foo_bar_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo_dot_bar) },
+ { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_bar_f_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(example_package_foo_bar_globals, example_package_foo_bar_globals_table);
+
+// Define example_package.foo.bar module object.
+const mp_obj_module_t example_package_foo_bar_user_cmodule = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&example_package_foo_bar_globals,
+};
+
+// Define example_package.foo.f()
+STATIC mp_obj_t example_package_foo_f(void) {
+ mp_printf(&mp_plat_print, "example_package.foo.f\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_f_obj, example_package_foo_f);
+
+// Define all attributes of the first-level sub-package (example_package.foo).
+STATIC const mp_rom_map_elem_t example_package_foo_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo) },
+ { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&example_package_foo_bar_user_cmodule) },
+ { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_f_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(example_package_foo_globals, example_package_foo_globals_table);
+
+// Define example_package.foo module object.
+const mp_obj_module_t example_package_foo_user_cmodule = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&example_package_foo_globals,
+};
+
+// Define example_package.f()
+STATIC mp_obj_t example_package_f(void) {
+ mp_printf(&mp_plat_print, "example_package.f\n");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package_f_obj, example_package_f);
+
+STATIC mp_obj_t example_package___init__(void) {
+ if (!MP_STATE_VM(example_package_initialised)) {
+ // __init__ for builtins is called each time the module is imported,
+ // so ensure that initialisation only happens once.
+ MP_STATE_VM(example_package_initialised) = true;
+ mp_printf(&mp_plat_print, "example_package.__init__\n");
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(example_package___init___obj, example_package___init__);
+
+// The "initialised" state is stored on mp_state so that it is cleared on soft
+// reset.
+MP_REGISTER_ROOT_POINTER(int example_package_initialised);
+
+// Define all attributes of the top-level package (example_package).
+STATIC const mp_rom_map_elem_t example_package_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package) },
+ { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&example_package___init___obj) },
+ { MP_ROM_QSTR(MP_QSTR_foo), MP_ROM_PTR(&example_package_foo_user_cmodule) },
+ { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_f_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(example_package_globals, example_package_globals_table);
+
+// Define module object.
+const mp_obj_module_t example_package_user_cmodule = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&example_package_globals,
+};
+
+// Register the module to make it available in Python.
+// Note: subpackages should not be registered with MP_REGISTER_MODULE.
+MP_REGISTER_MODULE(MP_QSTR_example_package, example_package_user_cmodule);
diff --git a/examples/usercmodule/subpackage/qstrdefsexamplepackage.h b/examples/usercmodule/subpackage/qstrdefsexamplepackage.h
new file mode 100644
index 000000000000..057ec5279d00
--- /dev/null
+++ b/examples/usercmodule/subpackage/qstrdefsexamplepackage.h
@@ -0,0 +1,2 @@
+Q(example_package.foo)
+Q(example_package.foo.bar)
diff --git a/extmod/asyncio/__init__.py b/extmod/asyncio/__init__.py
new file mode 100644
index 000000000000..1f83750c5aaf
--- /dev/null
+++ b/extmod/asyncio/__init__.py
@@ -0,0 +1,31 @@
+# MicroPython asyncio module
+# MIT license; Copyright (c) 2019 Damien P. George
+
+from .core import *
+
+__version__ = (3, 0, 0)
+
+_attrs = {
+ "wait_for": "funcs",
+ "wait_for_ms": "funcs",
+ "gather": "funcs",
+ "Event": "event",
+ "ThreadSafeFlag": "event",
+ "Lock": "lock",
+ "open_connection": "stream",
+ "start_server": "stream",
+ "StreamReader": "stream",
+ "StreamWriter": "stream",
+}
+
+
+# Lazy loader, effectively does:
+# global attr
+# from .mod import attr
+def __getattr__(attr):
+ mod = _attrs.get(attr, None)
+ if mod is None:
+ raise AttributeError(attr)
+ value = getattr(__import__(mod, None, None, True, 1), attr)
+ globals()[attr] = value
+ return value
diff --git a/extmod/uasyncio/core.py b/extmod/asyncio/core.py
similarity index 99%
rename from extmod/uasyncio/core.py
rename to extmod/asyncio/core.py
index 10a310809c0e..be5119ba6118 100644
--- a/extmod/uasyncio/core.py
+++ b/extmod/asyncio/core.py
@@ -1,4 +1,4 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019 Damien P. George
from time import ticks_ms as ticks, ticks_diff, ticks_add
@@ -6,7 +6,7 @@
# Import TaskQueue and Task, preferring built-in C code over Python code
try:
- from _uasyncio import TaskQueue, Task
+ from _asyncio import TaskQueue, Task
except:
from .task import TaskQueue, Task
@@ -30,6 +30,7 @@ class TimeoutError(Exception):
################################################################################
# Sleep functions
+
# "Yield" once, then raise StopIteration
class SingletonGenerator:
def __init__(self):
@@ -132,6 +133,7 @@ def wait_io_event(self, dt):
################################################################################
# Main run loop
+
# Ensure the awaitable is a task
def _promote_to_task(aw):
return aw if isinstance(aw, Task) else create_task(aw)
diff --git a/extmod/uasyncio/event.py b/extmod/asyncio/event.py
similarity index 94%
rename from extmod/uasyncio/event.py
rename to extmod/asyncio/event.py
index 3b5e79d8f23e..e0b41f732424 100644
--- a/extmod/uasyncio/event.py
+++ b/extmod/asyncio/event.py
@@ -1,8 +1,9 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
+
# Event class for primitive events that can be waited on, set, and cleared
class Event:
def __init__(self):
@@ -23,7 +24,8 @@ def set(self):
def clear(self):
self.state = False
- async def wait(self):
+ # async
+ def wait(self):
if not self.state:
# Event not set, put the calling task on the event's waiting queue
self.waiting.push(core.cur_task)
@@ -38,9 +40,9 @@ async def wait(self):
# that asyncio will poll until a flag is set.
# Note: Unlike Event, this is self-clearing after a wait().
try:
- import uio
+ import io
- class ThreadSafeFlag(uio.IOBase):
+ class ThreadSafeFlag(io.IOBase):
def __init__(self):
self.state = 0
diff --git a/extmod/uasyncio/funcs.py b/extmod/asyncio/funcs.py
similarity index 97%
rename from extmod/uasyncio/funcs.py
rename to extmod/asyncio/funcs.py
index 96883e4fe106..599091dfbdc2 100644
--- a/extmod/uasyncio/funcs.py
+++ b/extmod/asyncio/funcs.py
@@ -1,10 +1,10 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019-2022 Damien P. George
from . import core
-def _run(waiter, aw):
+async def _run(waiter, aw):
try:
result = await aw
status = True
@@ -61,7 +61,8 @@ def remove(t):
pass
-async def gather(*aws, return_exceptions=False):
+# async
+def gather(*aws, return_exceptions=False):
if not aws:
return []
@@ -122,7 +123,7 @@ def done(t, er):
# Either this gather was cancelled, or one of the sub-tasks raised an exception with
# return_exceptions==False, so reraise the exception here.
- if state is not 0:
+ if state:
raise state
# Return the list of return values of each sub-task.
diff --git a/extmod/uasyncio/lock.py b/extmod/asyncio/lock.py
similarity index 96%
rename from extmod/uasyncio/lock.py
rename to extmod/asyncio/lock.py
index f50213d7c186..0a46ac32619d 100644
--- a/extmod/uasyncio/lock.py
+++ b/extmod/asyncio/lock.py
@@ -1,8 +1,9 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
+
# Lock class for primitive mutex capability
class Lock:
def __init__(self):
@@ -28,7 +29,8 @@ def release(self):
# No Task waiting so unlock
self.state = 0
- async def acquire(self):
+ # async
+ def acquire(self):
if self.state != 0:
# Lock unavailable, put the calling Task on the waiting queue
self.waiting.push(core.cur_task)
diff --git a/extmod/asyncio/manifest.py b/extmod/asyncio/manifest.py
new file mode 100644
index 000000000000..e8dc7643250a
--- /dev/null
+++ b/extmod/asyncio/manifest.py
@@ -0,0 +1,18 @@
+# This list of package files doesn't include task.py because that's provided
+# by the C module.
+package(
+ "asyncio",
+ (
+ "__init__.py",
+ "core.py",
+ "event.py",
+ "funcs.py",
+ "lock.py",
+ "stream.py",
+ ),
+ base_path="..",
+ opt=3,
+)
+
+# Backwards-compatible uasyncio module.
+module("uasyncio.py", opt=3)
diff --git a/extmod/uasyncio/stream.py b/extmod/asyncio/stream.py
similarity index 92%
rename from extmod/uasyncio/stream.py
rename to extmod/asyncio/stream.py
index 785e43555ddd..c47c48cf0982 100644
--- a/extmod/uasyncio/stream.py
+++ b/extmod/asyncio/stream.py
@@ -1,4 +1,4 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
from . import core
@@ -26,7 +26,8 @@ async def wait_closed(self):
# TODO yield?
self.s.close()
- async def read(self, n=-1):
+ # async
+ def read(self, n=-1):
r = b""
while True:
yield core._io_queue.queue_read(self.s)
@@ -38,11 +39,13 @@ async def read(self, n=-1):
return r
r += r2
- async def readinto(self, buf):
+ # async
+ def readinto(self, buf):
yield core._io_queue.queue_read(self.s)
return self.s.readinto(buf)
- async def readexactly(self, n):
+ # async
+ def readexactly(self, n):
r = b""
while n:
yield core._io_queue.queue_read(self.s)
@@ -54,7 +57,8 @@ async def readexactly(self, n):
n -= len(r2)
return r
- async def readline(self):
+ # async
+ def readline(self):
l = b""
while True:
yield core._io_queue.queue_read(self.s)
@@ -73,10 +77,11 @@ def write(self, buf):
buf = buf[ret:]
self.out_buf += buf
- async def drain(self):
+ # async
+ def drain(self):
if not self.out_buf:
# Drain must always yield, so a tight loop of write+drain can't block the scheduler.
- return await core.sleep_ms(0)
+ return (yield from core.sleep_ms(0))
mv = memoryview(self.out_buf)
off = 0
while off < len(mv):
@@ -93,9 +98,11 @@ async def drain(self):
# Create a TCP stream connection to a remote host
-async def open_connection(host, port):
- from uerrno import EINPROGRESS
- import usocket as socket
+#
+# async
+def open_connection(host, port):
+ from errno import EINPROGRESS
+ import socket
ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
s = socket.socket(ai[0], ai[1], ai[2])
@@ -147,7 +154,7 @@ async def _serve(self, s, cb):
# Helper function to start a TCP stream server, running as a new task
# TODO could use an accept-callback on socket read activity instead of creating a task
async def start_server(cb, host, port, backlog=5):
- import usocket as socket
+ import socket
# Create and bind server socket.
host = socket.getaddrinfo(host, port)[0] # TODO this is blocking!
diff --git a/extmod/uasyncio/task.py b/extmod/asyncio/task.py
similarity index 99%
rename from extmod/uasyncio/task.py
rename to extmod/asyncio/task.py
index 4ead2a130843..30be2170eb0a 100644
--- a/extmod/uasyncio/task.py
+++ b/extmod/asyncio/task.py
@@ -1,4 +1,4 @@
-# MicroPython uasyncio module
+# MicroPython asyncio module
# MIT license; Copyright (c) 2019-2020 Damien P. George
# This file contains the core TaskQueue based on a pairing heap, and the core Task class.
diff --git a/extmod/asyncio/uasyncio.py b/extmod/asyncio/uasyncio.py
new file mode 100644
index 000000000000..67e6ddcfa36d
--- /dev/null
+++ b/extmod/asyncio/uasyncio.py
@@ -0,0 +1,8 @@
+# This module just allows `import uasyncio` to work. It lazy-loads from
+# `asyncio` without duplicating its globals dict.
+
+
+def __getattr__(attr):
+ import asyncio
+
+ return getattr(asyncio, attr)
diff --git a/extmod/axtls-include/axtls_os_port.h b/extmod/axtls-include/axtls_os_port.h
index ef2683acfc70..057642f9741b 100644
--- a/extmod/axtls-include/axtls_os_port.h
+++ b/extmod/axtls-include/axtls_os_port.h
@@ -26,7 +26,11 @@
#ifndef AXTLS_OS_PORT_H
#define AXTLS_OS_PORT_H
+#ifndef __ets__
+#include
+#endif
#include
+#include
#include "py/stream.h"
#include "lib/crypto-algorithms/sha256.h"
diff --git a/extmod/btstack/btstack.cmake b/extmod/btstack/btstack.cmake
new file mode 100644
index 000000000000..dd416fcbfbd3
--- /dev/null
+++ b/extmod/btstack/btstack.cmake
@@ -0,0 +1,60 @@
+set(BTSTACK_LIB_DIR "${MICROPY_DIR}/lib/btstack")
+set(BTSTACK_EXTMOD_DIR "${MICROPY_DIR}/extmod/btstack")
+
+add_library(micropy_extmod_btstack INTERFACE)
+
+target_include_directories(micropy_extmod_btstack INTERFACE
+ ${MICROPY_DIR}/
+ ${MICROPY_PORT_DIR}/
+ ${BTSTACK_EXTMOD_DIR}/
+ ${BTSTACK_LIB_DIR}/src
+ ${BTSTACK_LIB_DIR}/3rd-party/bluedroid/decoder/include
+ ${BTSTACK_LIB_DIR}/3rd-party/bluedroid/encoder/include
+ ${BTSTACK_LIB_DIR}/3rd-party/md5
+ ${BTSTACK_LIB_DIR}/3rd-party/yxml
+)
+
+target_sources(micropy_extmod_btstack INTERFACE
+ ${BTSTACK_LIB_DIR}/platform/embedded/hci_dump_embedded_stdout.c
+ ${BTSTACK_LIB_DIR}/src/ad_parser.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/ancs_client.c
+ ${BTSTACK_LIB_DIR}/src/ble/att_db.c
+ ${BTSTACK_LIB_DIR}/src/ble/att_db_util.c
+ ${BTSTACK_LIB_DIR}/src/ble/att_dispatch.c
+ ${BTSTACK_LIB_DIR}/src/ble/att_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/battery_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/cycling_power_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/cycling_speed_and_cadence_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/device_information_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/heart_rate_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/hids_device.c
+ ${BTSTACK_LIB_DIR}/src/mesh/gatt-service/mesh_provisioning_service_server.c
+ ${BTSTACK_LIB_DIR}/src/mesh/gatt-service/mesh_proxy_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/nordic_spp_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt-service/ublox_spp_service_server.c
+ ${BTSTACK_LIB_DIR}/src/ble/gatt_client.c
+ ${BTSTACK_LIB_DIR}/src/ble/le_device_db_memory.c
+ ${BTSTACK_LIB_DIR}/src/ble/sm.c
+ ${BTSTACK_LIB_DIR}/src/btstack_audio.c
+ ${BTSTACK_LIB_DIR}/src/btstack_base64_decoder.c
+ ${BTSTACK_LIB_DIR}/src/btstack_crypto.c
+ ${BTSTACK_LIB_DIR}/src/btstack_hid_parser.c
+ ${BTSTACK_LIB_DIR}/src/btstack_linked_list.c
+ ${BTSTACK_LIB_DIR}/src/btstack_memory.c
+ ${BTSTACK_LIB_DIR}/src/btstack_memory_pool.c
+ ${BTSTACK_LIB_DIR}/src/btstack_resample.c
+ ${BTSTACK_LIB_DIR}/src/btstack_ring_buffer.c
+ ${BTSTACK_LIB_DIR}/src/btstack_run_loop.c
+ ${BTSTACK_LIB_DIR}/src/btstack_run_loop_base.c
+ ${BTSTACK_LIB_DIR}/src/btstack_slip.c
+ ${BTSTACK_LIB_DIR}/src/btstack_tlv.c
+ ${BTSTACK_LIB_DIR}/src/btstack_tlv_none.c
+ ${BTSTACK_LIB_DIR}/src/btstack_util.c
+ ${BTSTACK_LIB_DIR}/src/hci.c
+ ${BTSTACK_LIB_DIR}/src/hci_cmd.c
+ ${BTSTACK_LIB_DIR}/src/hci_dump.c
+ ${BTSTACK_LIB_DIR}/src/hci_transport_em9304_spi.c
+ ${BTSTACK_LIB_DIR}/src/hci_transport_h4.c
+ ${BTSTACK_LIB_DIR}/src/l2cap.c
+ ${BTSTACK_LIB_DIR}/src/l2cap_signaling.c
+)
diff --git a/extmod/btstack/btstack.mk b/extmod/btstack/btstack.mk
index ca95931562cd..281d032ae110 100644
--- a/extmod/btstack/btstack.mk
+++ b/extmod/btstack/btstack.mk
@@ -6,6 +6,7 @@ GIT_SUBMODULES += lib/btstack
MICROPY_BLUETOOTH_BTSTACK_USB ?= 0
MICROPY_BLUETOOTH_BTSTACK_H4 ?= 1
+MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE ?= '"extmod/btstack/btstack_config_common.h"'
BTSTACK_EXTMOD_DIR = extmod/btstack
@@ -14,6 +15,7 @@ SRC_EXTMOD_C += $(BTSTACK_EXTMOD_DIR)/modbluetooth_btstack.c
INC += -I$(TOP)/$(BTSTACK_EXTMOD_DIR)
CFLAGS_EXTMOD += -DMICROPY_BLUETOOTH_BTSTACK=1
+CFLAGS_EXTMOD += -DMICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE=$(MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE)
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS=1
CFLAGS_EXTMOD += -DMICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING=1
@@ -33,6 +35,7 @@ INC += -I$(BTSTACK_DIR)/3rd-party/yxml
SRC_BTSTACK_C = \
$(addprefix lib/btstack/src/, $(SRC_FILES)) \
$(addprefix lib/btstack/src/ble/, $(filter-out %_tlv.c, $(SRC_BLE_FILES))) \
+ lib/btstack/platform/embedded/hci_dump_embedded_stdout.c \
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_USB),1)
ifeq ($(MICROPY_BLUETOOTH_BTSTACK_H4),1)
diff --git a/extmod/btstack/btstack_config.h b/extmod/btstack/btstack_config.h
index e56a84f94a16..84f0dab2bdb4 100644
--- a/extmod/btstack/btstack_config.h
+++ b/extmod/btstack/btstack_config.h
@@ -1,48 +1,6 @@
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
-// BTstack features that can be enabled
-#define ENABLE_BLE
-#define ENABLE_LE_PERIPHERAL
-#define ENABLE_LE_CENTRAL
-// #define ENABLE_CLASSIC
-#define ENABLE_LE_DATA_CHANNELS
-// #define ENABLE_LOG_INFO
-// #define ENABLE_LOG_DEBUG
-#define ENABLE_LOG_ERROR
-
-// BTstack configuration. buffers, sizes, ...
-#define HCI_ACL_PAYLOAD_SIZE 1021
-#define MAX_NR_GATT_CLIENTS 1
-#define MAX_NR_HCI_CONNECTIONS 1
-#define MAX_NR_L2CAP_SERVICES 3
-#define MAX_NR_L2CAP_CHANNELS 3
-#define MAX_NR_RFCOMM_MULTIPLEXERS 1
-#define MAX_NR_RFCOMM_SERVICES 1
-#define MAX_NR_RFCOMM_CHANNELS 1
-#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
-#define MAX_NR_BNEP_SERVICES 1
-#define MAX_NR_BNEP_CHANNELS 1
-#define MAX_NR_HFP_CONNECTIONS 1
-#define MAX_NR_WHITELIST_ENTRIES 1
-#define MAX_NR_SM_LOOKUP_ENTRIES 3
-#define MAX_NR_SERVICE_RECORD_ITEMS 1
-#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
-#define MAX_NR_AVDTP_CONNECTIONS 1
-#define MAX_NR_AVRCP_CONNECTIONS 1
-
-#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
-
-// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
-// #define NVM_NUM_DEVICE_DB_ENTRIES 16
-
-// We don't give btstack a malloc, so use a fixed-size ATT DB.
-#define MAX_ATT_DB_SIZE 512
-
-// BTstack HAL configuration
-#define HAVE_EMBEDDED_TIME_MS
-
-// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
-#define HCI_RESET_RESEND_TIMEOUT_MS 1000
+#include MICROPY_BLUETOOTH_BTSTACK_CONFIG_FILE
#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_H
diff --git a/extmod/btstack/btstack_config_common.h b/extmod/btstack/btstack_config_common.h
new file mode 100644
index 000000000000..0f616f7505e6
--- /dev/null
+++ b/extmod/btstack/btstack_config_common.h
@@ -0,0 +1,49 @@
+#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_COMMON_H
+#define MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_COMMON_H
+
+// BTstack features that can be enabled
+#define ENABLE_BLE
+#define ENABLE_LE_PERIPHERAL
+#define ENABLE_LE_CENTRAL
+// #define ENABLE_CLASSIC
+#define ENABLE_L2CAP_LE_CREDIT_BASED_FLOW_CONTROL_MODE
+#define ENABLE_PRINTF_HEXDUMP
+// #define ENABLE_LOG_INFO
+// #define ENABLE_LOG_DEBUG
+#define ENABLE_LOG_ERROR
+
+// BTstack configuration. buffers, sizes, ...
+#define HCI_ACL_PAYLOAD_SIZE 1021
+#define MAX_NR_GATT_CLIENTS 1
+#define MAX_NR_HCI_CONNECTIONS 1
+#define MAX_NR_L2CAP_SERVICES 3
+#define MAX_NR_L2CAP_CHANNELS 3
+#define MAX_NR_RFCOMM_MULTIPLEXERS 1
+#define MAX_NR_RFCOMM_SERVICES 1
+#define MAX_NR_RFCOMM_CHANNELS 1
+#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 2
+#define MAX_NR_BNEP_SERVICES 1
+#define MAX_NR_BNEP_CHANNELS 1
+#define MAX_NR_HFP_CONNECTIONS 1
+#define MAX_NR_WHITELIST_ENTRIES 1
+#define MAX_NR_SM_LOOKUP_ENTRIES 3
+#define MAX_NR_SERVICE_RECORD_ITEMS 1
+#define MAX_NR_AVDTP_STREAM_ENDPOINTS 1
+#define MAX_NR_AVDTP_CONNECTIONS 1
+#define MAX_NR_AVRCP_CONNECTIONS 1
+
+#define MAX_NR_LE_DEVICE_DB_ENTRIES 4
+
+// Link Key DB and LE Device DB using TLV on top of Flash Sector interface
+// #define NVM_NUM_DEVICE_DB_ENTRIES 16
+
+// We don't give btstack a malloc, so use a fixed-size ATT DB.
+#define MAX_ATT_DB_SIZE 512
+
+// BTstack HAL configuration
+#define HAVE_EMBEDDED_TIME_MS
+
+// Some USB dongles take longer to respond to HCI reset (e.g. BCM20702A).
+#define HCI_RESET_RESEND_TIMEOUT_MS 1000
+
+#endif // MICROPY_INCLUDED_EXTMOD_BTSTACK_BTSTACK_CONFIG_COMMON_H
diff --git a/extmod/btstack/btstack_hci_uart.c b/extmod/btstack/btstack_hci_uart.c
index 83e865b71d2d..f945efc762cb 100644
--- a/extmod/btstack/btstack_hci_uart.c
+++ b/extmod/btstack/btstack_hci_uart.c
@@ -159,6 +159,12 @@ const btstack_uart_block_t mp_bluetooth_btstack_hci_uart_block = {
&btstack_uart_get_supported_sleep_modes,
&btstack_uart_set_sleep,
&btstack_uart_set_wakeup_handler,
+
+ // The following are needed for H5 mode only.
+ NULL, // set_frame_received
+ NULL, // set_frame_sent,
+ NULL, // receive_frame,
+ NULL, // send_frame,
};
void mp_bluetooth_btstack_hci_uart_process(void) {
diff --git a/extmod/btstack/btstack_hci_uart.h b/extmod/btstack/btstack_hci_uart.h
index 8011e587dee3..74983808ec28 100644
--- a/extmod/btstack/btstack_hci_uart.h
+++ b/extmod/btstack/btstack_hci_uart.h
@@ -28,7 +28,7 @@
#ifndef MICROPY_INCLUDED_EXTMOD_BTSTACK_HCI_UART_H
#define MICROPY_INCLUDED_EXTMOD_BTSTACK_HCI_UART_H
-#include "lib/btstack/src/btstack.h"
+#include "lib/btstack/src/btstack_uart_block.h"
// --- Used by the port to create the HCI transport ---------------------------
extern const btstack_uart_block_t mp_bluetooth_btstack_hci_uart_block;
diff --git a/extmod/btstack/modbluetooth_btstack.c b/extmod/btstack/modbluetooth_btstack.c
index b58be78a9942..0c15e9343159 100644
--- a/extmod/btstack/modbluetooth_btstack.c
+++ b/extmod/btstack/modbluetooth_btstack.c
@@ -93,156 +93,57 @@ STATIC mp_obj_bluetooth_uuid_t create_mp_uuid(uint16_t uuid16, const uint8_t *uu
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
-// Notes on supporting background ops (e.g. an attempt to gatts_notify while
-// an existing notification is in progress):
-
-// GATTS Notify/Indicate (att_server_notify/indicate)
-// * When available, copies buffer immediately.
-// * Otherwise fails with BTSTACK_ACL_BUFFERS_FULL
-// * Use att_server_request_to_send_notification/indication to get callback
-// * Takes btstack_context_callback_registration_t (and takes ownership) and conn_handle.
-// * Callback is invoked with just the context member of the btstack_context_callback_registration_t
-
-// GATTC Write without response (gatt_client_write_value_of_characteristic_without_response)
-// * When available, copies buffer immediately.
-// * Otherwise, fails with GATT_CLIENT_BUSY.
-// * Use gatt_client_request_can_write_without_response_event to get callback
-// * Takes btstack_packet_handler_t (function pointer) and conn_handle
-// * Callback is invoked, use gatt_event_can_write_without_response_get_handle to get the conn_handle (no other context)
-// * There can only be one pending gatt_client_request_can_write_without_response_event (otherwise we fail with EALREADY).
-
-// GATTC Write with response (gatt_client_write_value_of_characteristic)
-// * When peripheral is available, takes ownership of buffer.
-// * Otherwise, fails with GATT_CLIENT_IN_WRONG_STATE (we fail the operation).
-// * Raises GATT_EVENT_QUERY_COMPLETE to the supplied packet handler.
-
-// For notify/indicate/write-without-response that proceed immediately, nothing extra required.
-// For all other cases, buffer needs to be copied and protected from GC.
-// For notify/indicate:
-// * btstack_context_callback_registration_t:
-// * needs to be malloc'ed
-// * needs to be protected from GC
-// * context arg needs to point back to the callback registration so it can be freed and un-protected
-// For write-without-response
-// * only the conn_handle is available in the callback
-// * so we need a queue of conn_handle->(value_handle, copied buffer)
-
-// Pending operation types.
-enum {
- // Queued for sending when possible.
- MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY, // Waiting for context callback
- MP_BLUETOOTH_BTSTACK_PENDING_INDICATE, // Waiting for context callback
- MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE, // Waiting for conn handle
- // Hold buffer pointer until complete.
- MP_BLUETOOTH_BTSTACK_PENDING_WRITE, // Waiting for write done event
-};
-
-// Pending operation:
-// - Holds a GC reference to the copied outgoing buffer.
-// - Provides enough information for the callback handler to execute the desired operation.
-struct _mp_btstack_pending_op_t {
+#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+typedef struct _mp_btstack_active_connection_t {
btstack_linked_item_t *next; // Must be first field to match btstack_linked_item.
- // See enum above.
- uint16_t op_type;
-
- // For all op types.
uint16_t conn_handle;
- uint16_t value_handle;
-
- // For notify/indicate only.
- // context_registration.context will point back to this struct.
- btstack_context_callback_registration_t context_registration;
-
- // For notify/indicate/write-without-response, this is the actual buffer to send.
- // For write-with-response, just holding onto the buffer for GC ref.
- size_t len;
- uint8_t buf[];
-};
-// Must hold MICROPY_PY_BLUETOOTH_ENTER.
-STATIC void btstack_remove_pending_operation(mp_btstack_pending_op_t *pending_op, bool del) {
- bool removed = btstack_linked_list_remove(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->pending_ops, (btstack_linked_item_t *)pending_op);
- assert(removed);
- (void)removed;
- if (del) {
- m_del_var(mp_btstack_pending_op_t, uint8_t, pending_op->len, pending_op);
- }
-}
-
-// Called in response to a gatts_notify/indicate being unable to complete, which then calls
-// att_server_request_to_send_notification.
-// We now have an opportunity to re-try the operation with an empty ACL buffer.
-STATIC void btstack_notify_indicate_ready_handler(void *context) {
- MICROPY_PY_BLUETOOTH_ENTER
- mp_btstack_pending_op_t *pending_op = (mp_btstack_pending_op_t *)context;
- DEBUG_printf("btstack_notify_indicate_ready_handler op_type=%d conn_handle=%d value_handle=%d len=%zu\n", pending_op->op_type, pending_op->conn_handle, pending_op->value_handle, pending_op->len);
- if (pending_op->op_type == MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY) {
- int err = att_server_notify(pending_op->conn_handle, pending_op->value_handle, pending_op->buf, pending_op->len);
- DEBUG_printf("btstack_notify_indicate_ready_handler: sending notification err=%d\n", err);
- assert(err == ERROR_CODE_SUCCESS);
- (void)err;
- } else {
- assert(pending_op->op_type == MP_BLUETOOTH_BTSTACK_PENDING_INDICATE);
- int err = att_server_indicate(pending_op->conn_handle, pending_op->value_handle, NULL, 0);
- DEBUG_printf("btstack_notify_indicate_ready_handler: sending indication err=%d\n", err);
- assert(err == ERROR_CODE_SUCCESS);
- (void)err;
- }
- // Can't free the pending op as we're in IRQ context. Leave it for the GC.
- btstack_remove_pending_operation(pending_op, false /* del */);
- MICROPY_PY_BLUETOOTH_EXIT
-}
-
-// Register a pending background operation -- copies the buffer, and makes it known to the GC.
-STATIC mp_btstack_pending_op_t *btstack_enqueue_pending_operation(uint16_t op_type, uint16_t conn_handle, uint16_t value_handle, const uint8_t *buf, size_t len) {
- DEBUG_printf("btstack_enqueue_pending_operation op_type=%d conn_handle=%d value_handle=%d len=%zu\n", op_type, conn_handle, value_handle, len);
- mp_btstack_pending_op_t *pending_op = m_new_obj_var(mp_btstack_pending_op_t, uint8_t, len);
- pending_op->op_type = op_type;
- pending_op->conn_handle = conn_handle;
- pending_op->value_handle = value_handle;
- pending_op->len = len;
- memcpy(pending_op->buf, buf, len);
-
- if (op_type == MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY || op_type == MP_BLUETOOTH_BTSTACK_PENDING_INDICATE) {
- pending_op->context_registration.callback = &btstack_notify_indicate_ready_handler;
- pending_op->context_registration.context = pending_op;
- }
-
- MICROPY_PY_BLUETOOTH_ENTER
- bool added = btstack_linked_list_add(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->pending_ops, (btstack_linked_item_t *)pending_op);
- assert(added);
+ // Read/write.
+ uint16_t pending_value_handle;
+
+ // Write only. Buffer must be retained until the operation completes.
+ uint8_t *pending_write_value;
+ size_t pending_write_value_len;
+} mp_btstack_active_connection_t;
+
+STATIC mp_btstack_active_connection_t *create_active_connection(uint16_t conn_handle) {
+ DEBUG_printf("create_active_connection: conn_handle=%d\n", conn_handle);
+ mp_btstack_active_connection_t *conn = m_new(mp_btstack_active_connection_t, 1);
+ conn->conn_handle = conn_handle;
+ conn->pending_value_handle = 0xffff;
+ conn->pending_write_value = NULL;
+ conn->pending_write_value_len = 0;
+ bool added = btstack_linked_list_add(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->active_connections, (btstack_linked_item_t *)conn);
(void)added;
- MICROPY_PY_BLUETOOTH_EXIT
-
- return pending_op;
+ assert(added);
+ return conn;
}
-#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
-
-// Cleans up a pending op of the specified type for this conn_handle (and if specified, value_handle).
-// Used by MP_BLUETOOTH_BTSTACK_PENDING_WRITE and MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE.
-// At the moment, both will set value_handle=0xffff as the events do not know their value_handle.
-// TODO: Can we make btstack give us the value_handle for regular write (with response) so that we
-// know for sure that we're using the correct entry.
-STATIC mp_btstack_pending_op_t *btstack_finish_pending_operation(uint16_t op_type, uint16_t conn_handle, uint16_t value_handle, bool del) {
- MICROPY_PY_BLUETOOTH_ENTER
- DEBUG_printf("btstack_finish_pending_operation op_type=%d conn_handle=%d value_handle=%d\n", op_type, conn_handle, value_handle);
+STATIC mp_btstack_active_connection_t *find_active_connection(uint16_t conn_handle) {
+ DEBUG_printf("find_active_connection: conn_handle=%d\n", conn_handle);
btstack_linked_list_iterator_t it;
- btstack_linked_list_iterator_init(&it, &MP_STATE_PORT(bluetooth_btstack_root_pointers)->pending_ops);
+ btstack_linked_list_iterator_init(&it, &MP_STATE_PORT(bluetooth_btstack_root_pointers)->active_connections);
+ mp_btstack_active_connection_t *conn = NULL;
while (btstack_linked_list_iterator_has_next(&it)) {
- mp_btstack_pending_op_t *pending_op = (mp_btstack_pending_op_t *)btstack_linked_list_iterator_next(&it);
-
- if (pending_op->op_type == op_type && pending_op->conn_handle == conn_handle && (value_handle == 0xffff || pending_op->value_handle == value_handle)) {
- DEBUG_printf("btstack_finish_pending_operation: found value_handle=%d len=%zu\n", pending_op->value_handle, pending_op->len);
- btstack_remove_pending_operation(pending_op, del);
- MICROPY_PY_BLUETOOTH_EXIT
- return del ? NULL : pending_op;
+ conn = (mp_btstack_active_connection_t *)btstack_linked_list_iterator_next(&it);
+ DEBUG_printf(" --> iter conn %d\n", conn->conn_handle);
+ if (conn->conn_handle == conn_handle) {
+ break;
}
}
- DEBUG_printf("btstack_finish_pending_operation: not found\n");
- MICROPY_PY_BLUETOOTH_EXIT
- return NULL;
+ return conn;
+}
+
+STATIC void remove_active_connection(uint16_t conn_handle) {
+ DEBUG_printf("remove_active_connection: conn_handle=%d\n", conn_handle);
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (conn) {
+ bool removed = btstack_linked_list_remove(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->active_connections, (btstack_linked_item_t *)conn);
+ (void)removed;
+ assert(removed);
+ m_del(mp_btstack_active_connection_t, conn, 1);
+ }
}
#endif
@@ -271,12 +172,14 @@ STATIC void btstack_packet_handler_att_server(uint8_t packet_type, uint16_t chan
uint8_t status = att_event_handle_value_indication_complete_get_status(packet);
mp_bluetooth_gatts_on_indicate_complete(conn_handle, value_handle, status);
} else if (event_type == ATT_EVENT_MTU_EXCHANGE_COMPLETE) {
+ DEBUG_printf(" --> att mtu exchange complete\n");
// This is triggered in peripheral mode, when exchange initiated by us or remote.
uint16_t conn_handle = att_event_mtu_exchange_complete_get_handle(packet);
uint16_t mtu = att_event_mtu_exchange_complete_get_MTU(packet);
mp_bluetooth_gatts_on_mtu_exchanged(conn_handle, mtu);
} else if (event_type == HCI_EVENT_LE_META || event_type == HCI_EVENT_DISCONNECTION_COMPLETE) {
// Ignore, duplicated by att_server.c.
+ DEBUG_printf(" --> hci att server event type: le_meta/disconnection (0x%02x)\n", event_type);
} else {
DEBUG_printf(" --> hci att server event type: unknown (0x%02x)\n", event_type);
}
@@ -290,8 +193,10 @@ STATIC bool controller_static_addr_available = false;
STATIC const uint8_t read_static_address_command_complete_prefix[] = { 0x0e, 0x1b, 0x01, 0x09, 0xfc };
#endif
-STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t irq) {
- DEBUG_printf("btstack_packet_handler(packet_type=%u, packet=%p)\n", packet_type, packet);
+STATIC void btstack_packet_handler_generic(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
+ (void)channel;
+ (void)size;
+ DEBUG_printf("btstack_packet_handler_generic(packet_type=%u, packet=%p)\n", packet_type, packet);
if (packet_type != HCI_EVENT_PACKET) {
return;
}
@@ -314,6 +219,9 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
// Slave role.
irq_event = MP_BLUETOOTH_IRQ_CENTRAL_CONNECT;
}
+ #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+ create_active_connection(conn_handle);
+ #endif
mp_bluetooth_gap_on_connected_disconnected(irq_event, conn_handle, addr_type, addr);
break;
}
@@ -368,7 +276,7 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
event_type == SM_EVENT_PAIRING_COMPLETE ||
// event_type == GAP_EVENT_DEDICATED_BONDING_COMPLETED || // No conn_handle
event_type == HCI_EVENT_ENCRYPTION_CHANGE) {
- DEBUG_printf(" --> enc/auth/pair/bond change\n", );
+ DEBUG_printf(" --> enc/auth/pair/bond change\n");
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
uint16_t conn_handle;
switch (event_type) {
@@ -407,6 +315,9 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
}
uint8_t addr[6] = {0};
mp_bluetooth_gap_on_connected_disconnected(irq_event, conn_handle, 0xff, addr);
+ #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+ remove_active_connection(conn_handle);
+ #endif
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
} else if (event_type == GAP_EVENT_ADVERTISING_REPORT) {
DEBUG_printf(" --> gap advertising report\n");
@@ -420,51 +331,12 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
mp_bluetooth_gap_on_scan_result(address_type, address, adv_event_type, rssi, data, length);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
#if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
- } else if (event_type == GATT_EVENT_QUERY_COMPLETE) {
- uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
- uint16_t status = gatt_event_query_complete_get_att_status(packet);
- DEBUG_printf(" --> gatt query complete irq=%d conn_handle=%d status=%d\n", irq, conn_handle, status);
- if (irq == MP_BLUETOOTH_IRQ_GATTC_READ_DONE || irq == MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE) {
- // TODO there is no value_handle available to pass here.
- // TODO try and get this implemented in btstack.
- mp_bluetooth_gattc_on_read_write_status(irq, conn_handle, 0xffff, status);
- // Unref the saved buffer for the write operation on this conn_handle.
- if (irq == MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE) {
- btstack_finish_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_WRITE, conn_handle, 0xffff, false /* del */);
- }
- } else if (irq == MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE ||
- irq == MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE ||
- irq == MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE) {
- mp_bluetooth_gattc_on_discover_complete(irq, conn_handle, status);
- }
- } else if (event_type == GATT_EVENT_SERVICE_QUERY_RESULT) {
- DEBUG_printf(" --> gatt service query result\n");
- uint16_t conn_handle = gatt_event_service_query_result_get_handle(packet);
- gatt_client_service_t service;
- gatt_event_service_query_result_get_service(packet, &service);
- mp_obj_bluetooth_uuid_t service_uuid = create_mp_uuid(service.uuid16, service.uuid128);
- mp_bluetooth_gattc_on_primary_service_result(conn_handle, service.start_group_handle, service.end_group_handle, &service_uuid);
- } else if (event_type == GATT_EVENT_CHARACTERISTIC_QUERY_RESULT) {
- DEBUG_printf(" --> gatt characteristic query result\n");
- uint16_t conn_handle = gatt_event_characteristic_query_result_get_handle(packet);
- gatt_client_characteristic_t characteristic;
- gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
- mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid(characteristic.uuid16, characteristic.uuid128);
- mp_bluetooth_gattc_on_characteristic_result(conn_handle, characteristic.value_handle, characteristic.end_handle, characteristic.properties, &characteristic_uuid);
- } else if (event_type == GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT) {
- DEBUG_printf(" --> gatt descriptor query result\n");
- uint16_t conn_handle = gatt_event_all_characteristic_descriptors_query_result_get_handle(packet);
- gatt_client_characteristic_descriptor_t descriptor;
- gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &descriptor);
- mp_obj_bluetooth_uuid_t descriptor_uuid = create_mp_uuid(descriptor.uuid16, descriptor.uuid128);
- mp_bluetooth_gattc_on_descriptor_result(conn_handle, descriptor.handle, &descriptor_uuid);
- } else if (event_type == GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) {
- DEBUG_printf(" --> gatt characteristic value query result\n");
- uint16_t conn_handle = gatt_event_characteristic_value_query_result_get_handle(packet);
- uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
- uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
- const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet);
- mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, &data, &len, 1);
+ } else if (event_type == GATT_EVENT_MTU) {
+ // This is triggered in central mode.
+ DEBUG_printf(" --> gatt event mtu\n");
+ uint16_t conn_handle = gatt_event_mtu_get_handle(packet);
+ uint16_t mtu = gatt_event_mtu_get_MTU(packet);
+ mp_bluetooth_gatts_on_mtu_exchanged(conn_handle, mtu);
} else if (event_type == GATT_EVENT_NOTIFICATION) {
DEBUG_printf(" --> gatt notification\n");
uint16_t conn_handle = gatt_event_notification_get_handle(packet);
@@ -482,28 +354,24 @@ STATIC void btstack_packet_handler(uint8_t packet_type, uint8_t *packet, uint8_t
} else if (event_type == GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE) {
uint16_t conn_handle = gatt_event_can_write_without_response_get_handle(packet);
DEBUG_printf(" --> gatt can write without response %d\n", conn_handle);
- mp_btstack_pending_op_t *pending_op = btstack_finish_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE, conn_handle, 0xffff, false /* !del */);
- if (pending_op) {
- DEBUG_printf(" --> ready for value_handle=%d len=%zu\n", pending_op->value_handle, pending_op->len);
- gatt_client_write_value_of_characteristic_without_response(pending_op->conn_handle, pending_op->value_handle, pending_op->len, (uint8_t *)pending_op->buf);
- // Note: Can't "del" the pending_op from IRQ context. Leave it for the GC.
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (!conn || conn->pending_value_handle == 0xffff || !conn->pending_write_value) {
+ return;
}
-
+ DEBUG_printf(" --> ready for value_handle=%d len=%lu\n", conn->pending_value_handle, conn->pending_write_value_len);
+ int err = gatt_client_write_value_of_characteristic_without_response(conn_handle, conn->pending_value_handle, conn->pending_write_value_len, conn->pending_write_value);
+ (void)err;
+ assert(err == ERROR_CODE_SUCCESS);
+ conn->pending_value_handle = 0xffff;
+ m_del(uint8_t, conn->pending_write_value, conn->pending_write_value_len);
+ conn->pending_write_value = NULL;
+ conn->pending_write_value_len = 0;
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
} else {
DEBUG_printf(" --> hci event type: unknown (0x%02x)\n", event_type);
}
}
-// Because the packet handler callbacks don't support an argument, we use a specific
-// handler when we need to provide additional state to the handler (in the "irq" parameter).
-// This is the generic handler for when you don't need extra state.
-STATIC void btstack_packet_handler_generic(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
- (void)channel;
- (void)size;
- btstack_packet_handler(packet_type, packet, 0);
-}
-
STATIC btstack_packet_callback_registration_t hci_event_callback_registration = {
.callback = &btstack_packet_handler_generic
};
@@ -513,35 +381,121 @@ STATIC btstack_packet_callback_registration_t hci_event_callback_registration =
STATIC void btstack_packet_handler_discover_services(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
- btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE);
+ if (packet_type != HCI_EVENT_PACKET) {
+ return;
+ }
+ uint8_t event_type = hci_event_packet_get_type(packet);
+ if (event_type == GATT_EVENT_SERVICE_QUERY_RESULT) {
+ DEBUG_printf(" --> gatt service query result\n");
+ uint16_t conn_handle = gatt_event_service_query_result_get_handle(packet);
+ gatt_client_service_t service;
+ gatt_event_service_query_result_get_service(packet, &service);
+ mp_obj_bluetooth_uuid_t service_uuid = create_mp_uuid(service.uuid16, service.uuid128);
+ mp_bluetooth_gattc_on_primary_service_result(conn_handle, service.start_group_handle, service.end_group_handle, &service_uuid);
+ } else if (event_type == GATT_EVENT_QUERY_COMPLETE) {
+ uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
+ uint16_t status = gatt_event_query_complete_get_att_status(packet);
+ DEBUG_printf(" --> gatt query services complete conn_handle=%d status=%d\n", conn_handle, status);
+ mp_bluetooth_gattc_on_discover_complete(MP_BLUETOOTH_IRQ_GATTC_SERVICE_DONE, conn_handle, status);
+ }
}
// For when the handler is being used for characteristic discovery.
STATIC void btstack_packet_handler_discover_characteristics(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
- btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE);
+ if (packet_type != HCI_EVENT_PACKET) {
+ return;
+ }
+ uint8_t event_type = hci_event_packet_get_type(packet);
+ if (event_type == GATT_EVENT_CHARACTERISTIC_QUERY_RESULT) {
+ DEBUG_printf(" --> gatt characteristic query result\n");
+ uint16_t conn_handle = gatt_event_characteristic_query_result_get_handle(packet);
+ gatt_client_characteristic_t characteristic;
+ gatt_event_characteristic_query_result_get_characteristic(packet, &characteristic);
+ mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid(characteristic.uuid16, characteristic.uuid128);
+ mp_bluetooth_gattc_on_characteristic_result(conn_handle, characteristic.value_handle, characteristic.end_handle, characteristic.properties, &characteristic_uuid);
+ } else if (event_type == GATT_EVENT_QUERY_COMPLETE) {
+ uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
+ uint16_t status = gatt_event_query_complete_get_att_status(packet);
+ DEBUG_printf(" --> gatt query characteristics complete conn_handle=%d status=%d\n", conn_handle, status);
+ mp_bluetooth_gattc_on_discover_complete(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE, conn_handle, status);
+ }
}
// For when the handler is being used for descriptor discovery.
STATIC void btstack_packet_handler_discover_descriptors(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
- btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE);
+ if (packet_type != HCI_EVENT_PACKET) {
+ return;
+ }
+ uint8_t event_type = hci_event_packet_get_type(packet);
+ if (event_type == GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT) {
+ DEBUG_printf(" --> gatt descriptor query result\n");
+ uint16_t conn_handle = gatt_event_all_characteristic_descriptors_query_result_get_handle(packet);
+ gatt_client_characteristic_descriptor_t descriptor;
+ gatt_event_all_characteristic_descriptors_query_result_get_characteristic_descriptor(packet, &descriptor);
+ mp_obj_bluetooth_uuid_t descriptor_uuid = create_mp_uuid(descriptor.uuid16, descriptor.uuid128);
+ mp_bluetooth_gattc_on_descriptor_result(conn_handle, descriptor.handle, &descriptor_uuid);
+ } else if (event_type == GATT_EVENT_QUERY_COMPLETE) {
+ uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
+ uint16_t status = gatt_event_query_complete_get_att_status(packet);
+ DEBUG_printf(" --> gatt query descriptors complete conn_handle=%d status=%d\n", conn_handle, status);
+ mp_bluetooth_gattc_on_discover_complete(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_DONE, conn_handle, status);
+ }
}
// For when the handler is being used for a read query.
STATIC void btstack_packet_handler_read(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
- btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_READ_DONE);
+ if (packet_type != HCI_EVENT_PACKET) {
+ return;
+ }
+ uint8_t event_type = hci_event_packet_get_type(packet);
+ if (event_type == GATT_EVENT_QUERY_COMPLETE) {
+ uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
+ uint16_t status = gatt_event_query_complete_get_att_status(packet);
+ DEBUG_printf(" --> gatt query read complete conn_handle=%d status=%d\n", conn_handle, status);
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (!conn) {
+ return;
+ }
+ mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_READ_DONE, conn_handle, conn->pending_value_handle, status);
+ conn->pending_value_handle = 0xffff;
+ } else if (event_type == GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) {
+ DEBUG_printf(" --> gatt characteristic value query result\n");
+ uint16_t conn_handle = gatt_event_characteristic_value_query_result_get_handle(packet);
+ uint16_t value_handle = gatt_event_characteristic_value_query_result_get_value_handle(packet);
+ uint16_t len = gatt_event_characteristic_value_query_result_get_value_length(packet);
+ const uint8_t *data = gatt_event_characteristic_value_query_result_get_value(packet);
+ mp_bluetooth_gattc_on_data_available(MP_BLUETOOTH_IRQ_GATTC_READ_RESULT, conn_handle, value_handle, &data, &len, 1);
+ }
}
// For when the handler is being used for write-with-response.
STATIC void btstack_packet_handler_write_with_response(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
(void)channel;
(void)size;
- btstack_packet_handler(packet_type, packet, MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE);
+ if (packet_type != HCI_EVENT_PACKET) {
+ return;
+ }
+ uint8_t event_type = hci_event_packet_get_type(packet);
+ if (event_type == GATT_EVENT_QUERY_COMPLETE) {
+ uint16_t conn_handle = gatt_event_query_complete_get_handle(packet);
+ uint16_t status = gatt_event_query_complete_get_att_status(packet);
+ DEBUG_printf(" --> gatt query write complete conn_handle=%d status=%d\n", conn_handle, status);
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (!conn) {
+ return;
+ }
+ mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, conn->pending_value_handle, status);
+ conn->pending_value_handle = 0xffff;
+ m_del(uint8_t, conn->pending_write_value, conn->pending_write_value_len);
+ conn->pending_write_value = NULL;
+ conn->pending_write_value_len = 0;
+ }
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
@@ -590,8 +544,6 @@ STATIC void set_random_address(void) {
DEBUG_printf("set_random_address: Generating static address using mp_hal_get_mac\n");
mp_hal_get_mac(MP_HAL_MAC_BDADDR, static_addr);
- // Mark it as STATIC (not RPA or NRPA).
- static_addr[0] |= 0xc0;
#else
@@ -604,6 +556,8 @@ STATIC void set_random_address(void) {
}
#endif // MICROPY_BLUETOOTH_USE_MP_HAL_GET_MAC_STATIC_ADDRESS
+ // Mark it as STATIC (not RPA or NRPA).
+ static_addr[0] |= 0xc0;
DEBUG_printf("set_random_address: Address generated.\n");
gap_random_address_set(static_addr);
@@ -625,6 +579,19 @@ STATIC void set_random_address(void) {
DEBUG_printf("set_random_address: Address loaded by controller\n");
}
+STATIC void deinit_stack(void) {
+ mp_bluetooth_btstack_state = MP_BLUETOOTH_BTSTACK_STATE_OFF;
+
+ // Deinitialise BTstack components.
+ sm_deinit();
+ l2cap_deinit();
+ hci_deinit();
+ btstack_memory_deinit();
+ btstack_run_loop_deinit();
+
+ MP_STATE_PORT(bluetooth_btstack_root_pointers) = NULL;
+}
+
int mp_bluetooth_init(void) {
DEBUG_printf("mp_bluetooth_init\n");
@@ -702,8 +669,8 @@ int mp_bluetooth_init(void) {
// Attempt a shutdown (may not do anything).
mp_bluetooth_btstack_port_deinit();
- // Clean up.
- MP_STATE_PORT(bluetooth_btstack_root_pointers) = NULL;
+ // Clean up BTstack.
+ deinit_stack();
return timeout ? MP_ETIMEDOUT : MP_EINVAL;
}
@@ -726,6 +693,13 @@ int mp_bluetooth_init(void) {
gatt_client_listen_for_characteristic_value_updates(&MP_STATE_PORT(bluetooth_btstack_root_pointers)->notification, &btstack_packet_handler_generic, GATT_CLIENT_ANY_CONNECTION, NULL);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
+ // Always include at least the standard GAP and GATT default services. A
+ // peripheral (likely a server) will almost always override this with its
+ // own services, but a central should get the default services, e.g. so
+ // the remote end can find out its GAP name.
+ mp_bluetooth_gatts_register_service_begin(false);
+ mp_bluetooth_gatts_register_service_end();
+
return 0;
}
@@ -757,8 +731,8 @@ void mp_bluetooth_deinit(void) {
}
btstack_run_loop_remove_timer(&btstack_init_deinit_timeout);
- mp_bluetooth_btstack_state = MP_BLUETOOTH_BTSTACK_STATE_OFF;
- MP_STATE_PORT(bluetooth_btstack_root_pointers) = NULL;
+ // Clean up BTstack.
+ deinit_stack();
DEBUG_printf("mp_bluetooth_deinit: complete\n");
}
@@ -836,7 +810,7 @@ void mp_bluetooth_set_io_capability(uint8_t capability) {
#endif // MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
size_t mp_bluetooth_gap_get_device_name(const uint8_t **buf) {
- uint8_t *value = NULL;
+ const uint8_t *value = NULL;
size_t value_len = 0;
mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, BTSTACK_GAP_DEVICE_NAME_HANDLE, &value, &value_len);
*buf = value;
@@ -909,14 +883,14 @@ int mp_bluetooth_gatts_register_service_begin(bool append) {
if (!append) {
// This will reset the DB.
- // Becase the DB is statically allocated, there's no problem with just re-initing it.
+ // Because the DB is statically allocated, there's no problem with just re-initing it.
// Note this would be a memory leak if we enabled HAVE_MALLOC (there's no API to free the existing db).
att_db_util_init();
att_db_util_add_service_uuid16(GAP_SERVICE_UUID);
uint16_t handle = att_db_util_add_characteristic_uuid16(GAP_DEVICE_NAME_UUID, ATT_PROPERTY_READ | ATT_PROPERTY_DYNAMIC, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0);
- assert(handle == BTSTACK_GAP_DEVICE_NAME_HANDLE);
(void)handle;
+ assert(handle == BTSTACK_GAP_DEVICE_NAME_HANDLE);
att_db_util_add_service_uuid16(0x1801);
att_db_util_add_characteristic_uuid16(0x2a05, ATT_PROPERTY_READ, ATT_SECURITY_NONE, ATT_SECURITY_NONE, NULL, 0);
@@ -968,7 +942,11 @@ STATIC int att_write_callback(hci_con_handle_t connection_handle, uint16_t att_h
entry->data_len = MIN(entry->data_alloc, buffer_size + append_offset);
memcpy(entry->data + append_offset, buffer, entry->data_len - append_offset);
- mp_bluetooth_gatts_on_write(connection_handle, att_handle);
+ uint16_t handle_uuid = att_uuid_for_handle(att_handle);
+ if (handle_uuid != GATT_CLIENT_CHARACTERISTICS_CONFIGURATION) {
+ // Suppress the Python callback for writes to the CCCD.
+ mp_bluetooth_gatts_on_write(connection_handle, att_handle);
+ }
return 0;
}
@@ -1020,7 +998,7 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m
size_t handle_index = 0;
size_t descriptor_index = 0;
- static uint8_t cccb_buf[2] = {0};
+ static uint8_t cccd_buf[2] = {0};
for (size_t i = 0; i < num_characteristics; ++i) {
uint16_t props = (characteristic_flags[i] & 0x7f) | ATT_PROPERTY_DYNAMIC;
@@ -1036,11 +1014,11 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m
return MP_EINVAL;
}
mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, handles[handle_index], MP_BLUETOOTH_DEFAULT_ATTR_LEN);
- // If a NOTIFY or INDICATE characteristic is added, then we need to manage a value for the CCCB.
+ // If a NOTIFY or INDICATE characteristic is added, then we need to manage a value for the CCCD.
if (props & (ATT_PROPERTY_NOTIFY | ATT_PROPERTY_INDICATE)) {
- // btstack creates the CCCB as the next handle.
- mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, handles[handle_index] + 1, MP_BLUETOOTH_CCCB_LEN);
- int ret = mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, handles[handle_index] + 1, cccb_buf, sizeof(cccb_buf));
+ // btstack automatically creates the CCCD as the next handle if the notify or indicate properties are set.
+ mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, handles[handle_index] + 1, MP_BLUETOOTH_CCCD_LEN);
+ int ret = mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, handles[handle_index] + 1, cccd_buf, sizeof(cccd_buf));
if (ret) {
return ret;
}
@@ -1077,7 +1055,7 @@ int mp_bluetooth_gatts_register_service_end(void) {
return 0;
}
-int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
+int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len) {
DEBUG_printf("mp_bluetooth_gatts_read\n");
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
@@ -1091,90 +1069,152 @@ int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
if (send_update) {
- return MP_EOPNOTSUPP;
+ DEBUG_printf(" --> send_update\n");
+ // If a characteristic has notify or indicate set, then btstack automatically creates the CCCD as the next handle.
+ // So if the next handle is a CCCD, then this characteristic must have had notify/indicate set.
+ uint16_t next_handle_uuid = att_uuid_for_handle(value_handle + 1);
+ if (next_handle_uuid != GATT_CLIENT_CHARACTERISTICS_CONFIGURATION) {
+ return MP_EINVAL;
+ }
+ DEBUG_printf(" --> got handle for cccd: %d\n", value_handle + 1);
+ }
+ int err = mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
+ if (!send_update || err) {
+ return err;
}
- return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, value, value_len);
-}
-int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
- DEBUG_printf("mp_bluetooth_gatts_notify\n");
+ // Read the CCCD value. TODO: These should be per-connection.
+ const uint8_t *cccd;
+ size_t cccd_len;
+ err = mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle + 1, &cccd, &cccd_len);
+ if (cccd_len != 2 || err) {
+ return err;
+ }
- if (!mp_bluetooth_is_active()) {
- return ERRNO_BLUETOOTH_NOT_ACTIVE;
+ // Notify/indicate all active connections.
+ btstack_linked_list_iterator_t it;
+ hci_connections_get_iterator(&it);
+ while (btstack_linked_list_iterator_has_next(&it)) {
+ hci_connection_t *connection = (hci_connection_t *)btstack_linked_list_iterator_next(&it);
+ if (cccd[0] & 1) {
+ err = mp_bluetooth_gatts_notify_indicate(connection->con_handle, value_handle, MP_BLUETOOTH_GATTS_OP_NOTIFY, value, value_len);
+ if (err) {
+ return err;
+ }
+ }
+ if (cccd[0] & 2) {
+ err = mp_bluetooth_gatts_notify_indicate(connection->con_handle, value_handle, MP_BLUETOOTH_GATTS_OP_INDICATE, value, value_len);
+ if (err) {
+ return err;
+ }
+ }
}
- // Note: btstack doesn't appear to support sending a notification without a value, so include the stored value.
- uint8_t *data = NULL;
- size_t len = 0;
- mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &data, &len);
- return mp_bluetooth_gatts_notify_send(conn_handle, value_handle, data, len);
+ return 0;
}
-int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
- DEBUG_printf("mp_bluetooth_gatts_notify_send\n");
+#if !MICROPY_TRACKED_ALLOC
+#error "btstack requires MICROPY_TRACKED_ALLOC"
+#endif
- if (!mp_bluetooth_is_active()) {
- return ERRNO_BLUETOOTH_NOT_ACTIVE;
- }
+typedef struct {
+ btstack_context_callback_registration_t btstack_registration;
+ int gatts_op;
+ uint16_t conn_handle;
+ uint16_t value_handle;
+ size_t value_len;
+ uint8_t value[];
+} notify_indicate_pending_op_t;
- // Attempt to send immediately. If it succeeds, btstack will copy the buffer.
+// Called in response to a gatts_notify/indicate being unable to complete, which then calls
+// att_server_request_to_send_notification.
+STATIC void btstack_notify_indicate_ready_handler(void *context) {
MICROPY_PY_BLUETOOTH_ENTER
- int err = att_server_notify(conn_handle, value_handle, value, value_len);
- MICROPY_PY_BLUETOOTH_EXIT
-
- if (err == BTSTACK_ACL_BUFFERS_FULL) {
- DEBUG_printf("mp_bluetooth_gatts_notify_send: ACL buffer full, scheduling callback\n");
- // Schedule callback, making a copy of the buffer.
- mp_btstack_pending_op_t *pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_NOTIFY, conn_handle, value_handle, value, value_len);
-
- err = att_server_request_to_send_notification(&pending_op->context_registration, conn_handle);
-
- if (err != ERROR_CODE_SUCCESS) {
- // Failure. Unref and free the pending operation.
- btstack_remove_pending_operation(pending_op, true /* del */);
- }
-
- return 0;
- } else {
- return btstack_error_to_errno(err);
+ notify_indicate_pending_op_t *pending_op = (notify_indicate_pending_op_t *)context;
+ DEBUG_printf("btstack_notify_indicate_ready_handler gatts_op=%d conn_handle=%d value_handle=%d len=%lu\n", pending_op->gatts_op, pending_op->conn_handle, pending_op->value_handle, pending_op->value_len);
+ int err = ERROR_CODE_SUCCESS;
+ switch (pending_op->gatts_op) {
+ case MP_BLUETOOTH_GATTS_OP_NOTIFY:
+ err = att_server_notify(pending_op->conn_handle, pending_op->value_handle, pending_op->value, pending_op->value_len);
+ DEBUG_printf("btstack_notify_indicate_ready_handler: sending notification err=%d\n", err);
+ break;
+ case MP_BLUETOOTH_GATTS_OP_INDICATE:
+ err = att_server_indicate(pending_op->conn_handle, pending_op->value_handle, pending_op->value, pending_op->value_len);
+ DEBUG_printf("btstack_notify_indicate_ready_handler: sending indication err=%d\n", err);
+ break;
}
+ assert(err == ERROR_CODE_SUCCESS);
+ (void)err;
+ MICROPY_PY_BLUETOOTH_EXIT
+ m_tracked_free(pending_op);
}
-int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
- DEBUG_printf("mp_bluetooth_gatts_indicate\n");
+int mp_bluetooth_gatts_notify_indicate(uint16_t conn_handle, uint16_t value_handle, int gatts_op, const uint8_t *value, size_t value_len) {
+ DEBUG_printf("mp_bluetooth_gatts_notify_indicate: gatts_op=%d\n", gatts_op);
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- uint8_t *data = NULL;
- size_t len = 0;
- mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &data, &len);
+ if (!value) {
+ // NULL value means "use DB value".
+ mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_btstack_root_pointers)->gatts_db, value_handle, &value, &value_len);
+ }
+
+ // Even if a lower MTU is negotiated, btstack allows sending a larger
+ // notification/indication. Truncate at the MTU-3 (to match NimBLE).
+ uint16_t current_mtu = att_server_get_mtu(conn_handle);
+ if (current_mtu) {
+ current_mtu -= 3;
+ value_len = MIN(value_len, current_mtu);
+ }
- // Indicate will raise ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE when
- // acknowledged (or timeout/error).
+ int err = ERROR_CODE_UNKNOWN_HCI_COMMAND;
- // Attempt to send immediately, will copy buffer.
+ // Attempt to send immediately. If it succeeds, btstack will copy the buffer.
MICROPY_PY_BLUETOOTH_ENTER
- int err = att_server_indicate(conn_handle, value_handle, data, len);
+ switch (gatts_op) {
+ case MP_BLUETOOTH_GATTS_OP_NOTIFY:
+ err = att_server_notify(conn_handle, value_handle, value, value_len);
+ break;
+ case MP_BLUETOOTH_GATTS_OP_INDICATE:
+ // Indicate will raise ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE when
+ // acknowledged (or timeout/error).
+ err = att_server_indicate(conn_handle, value_handle, value, value_len);
+ break;
+ }
MICROPY_PY_BLUETOOTH_EXIT
- if (err == BTSTACK_ACL_BUFFERS_FULL) {
- DEBUG_printf("mp_bluetooth_gatts_indicate: ACL buffer full, scheduling callback\n");
- // Schedule callback, making a copy of the buffer.
- mp_btstack_pending_op_t *pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_INDICATE, conn_handle, value_handle, data, len);
-
- err = att_server_request_to_send_indication(&pending_op->context_registration, conn_handle);
+ if (err == BTSTACK_ACL_BUFFERS_FULL || err == ATT_HANDLE_VALUE_INDICATION_IN_PROGRESS) {
+ DEBUG_printf("mp_bluetooth_gatts_notify_indicate: ACL buffer full / indication in progress, scheduling callback\n");
+
+ // Copy the value and ask btstack to let us know when it can be sent.
+ notify_indicate_pending_op_t *pending_op = m_tracked_calloc(1, sizeof(notify_indicate_pending_op_t) + value_len);
+ pending_op->btstack_registration.context = pending_op;
+ pending_op->btstack_registration.callback = &btstack_notify_indicate_ready_handler;
+ pending_op->gatts_op = gatts_op;
+ pending_op->conn_handle = conn_handle;
+ pending_op->value_handle = value_handle;
+ pending_op->value_len = value_len;
+ memcpy(pending_op->value, value, value_len);
+
+ MICROPY_PY_BLUETOOTH_ENTER
+ switch (gatts_op) {
+ case MP_BLUETOOTH_GATTS_OP_NOTIFY:
+ err = att_server_request_to_send_notification(&pending_op->btstack_registration, conn_handle);
+ break;
+ case MP_BLUETOOTH_GATTS_OP_INDICATE:
+ err = att_server_request_to_send_indication(&pending_op->btstack_registration, conn_handle);
+ break;
+ }
+ MICROPY_PY_BLUETOOTH_EXIT
if (err != ERROR_CODE_SUCCESS) {
- // Failure. Unref and free the pending operation.
- btstack_remove_pending_operation(pending_op, true /* del */);
+ m_tracked_free(pending_op);
}
-
- return 0;
- } else {
- return btstack_error_to_errno(err);
}
+
+ return btstack_error_to_errno(err);
}
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {
@@ -1374,58 +1414,99 @@ int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- return btstack_error_to_errno(gatt_client_read_value_of_characteristic_using_value_handle(&btstack_packet_handler_read, conn_handle, value_handle));
+
+ // There can only be a single pending GATT client operation per connection.
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (!conn) {
+ DEBUG_printf(" --> no active connection %d\n", conn_handle);
+ return MP_ENOTCONN;
+ }
+ if (conn->pending_value_handle != 0xffff) {
+ // There's either a read in progress, a write-with-response in progress, or a pending can-write-without-response request outstanding.
+ DEBUG_printf("--> busy\n");
+ return MP_EALREADY;
+ }
+ conn->pending_value_handle = value_handle;
+ int err = gatt_client_read_value_of_characteristic_using_value_handle(&btstack_packet_handler_read, conn_handle, value_handle);
+ if (err != ERROR_CODE_SUCCESS) {
+ DEBUG_printf("--> can't send read %d\n", err);
+ conn->pending_value_handle = 0xffff;
+ }
+ return btstack_error_to_errno(err);
}
-int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode) {
+int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len, unsigned int mode) {
DEBUG_printf("mp_bluetooth_gattc_write\n");
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- // We should be distinguishing between gatt_client_write_value_of_characteristic vs
+ // Note: We should be distinguishing between gatt_client_write_value_of_characteristic vs
// gatt_client_write_characteristic_descriptor_using_descriptor_handle.
// However both are implemented using send_gatt_write_attribute_value_request under the hood,
// and we get the exact same event to the packet handler.
// Same story for the "without response" version.
int err;
- mp_btstack_pending_op_t *pending_op = NULL;
if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) {
- // If possible, this will send immediately, copying the buffer directly to the ACL buffer.
- err = gatt_client_write_value_of_characteristic_without_response(conn_handle, value_handle, *value_len, (uint8_t *)value);
- if (err == GATT_CLIENT_BUSY) {
- DEBUG_printf("mp_bluetooth_gattc_write: client busy\n");
- // Can't send right now, need to take a copy of the buffer and add it to the queue.
- pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_WRITE_NO_RESPONSE, conn_handle, value_handle, value, *value_len);
- // Notify when this conn_handle can write.
- err = gatt_client_request_can_write_without_response_event(&btstack_packet_handler_generic, conn_handle);
- } else {
- DEBUG_printf("mp_bluetooth_gattc_write: other failure: %d\n", err);
+ // Simplest case -- if the write can be dispatched directly, then the buffer is copied directly to the ACL buffer.
+ err = gatt_client_write_value_of_characteristic_without_response(conn_handle, value_handle, value_len, (uint8_t *)value);
+ if (err != GATT_CLIENT_BUSY) {
+ DEBUG_printf("--> can't send write-without-response %d\n", err);
+ return btstack_error_to_errno(err);
}
+ }
+
+ // There can only be a single pending read/write request per connection.
+ mp_btstack_active_connection_t *conn = find_active_connection(conn_handle);
+ if (!conn) {
+ DEBUG_printf(" --> no active connection %d\n", conn_handle);
+ return MP_ENOTCONN;
+ }
+ if (conn->pending_value_handle != 0xffff) {
+ // There's either a read in progress, a write-with-response in progress, or a pending can-write-without-response request outstanding.
+ DEBUG_printf(" --> busy\n");
+ return MP_EALREADY;
+ }
+ conn->pending_value_handle = value_handle;
+ conn->pending_write_value_len = value_len;
+ conn->pending_write_value = m_new(uint8_t, value_len);
+ memcpy(conn->pending_write_value, value, value_len);
+
+ if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) {
+ DEBUG_printf(" --> client busy\n");
+ // Raise the GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE event when
+ // write-without-response will succeed. The only way this fails is if
+ // there's an outstanding request (unlike for the server-equivalent,
+ // att_server_request_to_send_notification, which has a queue) but
+ // we've already checked that there isn't one.
+ err = gatt_client_request_can_write_without_response_event(&btstack_packet_handler_generic, conn_handle);
} else if (mode == MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE) {
- // Pending operation copies the value buffer and keeps a GC reference
- // until the response comes back (there is always a response).
- pending_op = btstack_enqueue_pending_operation(MP_BLUETOOTH_BTSTACK_PENDING_WRITE, conn_handle, value_handle, value, *value_len);
- err = gatt_client_write_value_of_characteristic(&btstack_packet_handler_write_with_response, conn_handle, value_handle, pending_op->len, pending_op->buf);
+ // Attempt to write immediately. This can fail if there's another
+ // client operation in progress (e.g. discover).
+ err = gatt_client_write_value_of_characteristic(&btstack_packet_handler_write_with_response, conn_handle, value_handle, value_len, conn->pending_write_value);
} else {
return MP_EINVAL;
}
- if (pending_op && err != ERROR_CODE_SUCCESS) {
- // Failure. Unref and free the pending operation.
- btstack_remove_pending_operation(pending_op, true /* del */);
+ if (err != ERROR_CODE_SUCCESS) {
+ DEBUG_printf("--> write failed %d\n", err);
+ // We knew that there was no read/write in progress, but some other
+ // client operation is in progress, so release the pending state.
+ m_del(uint8_t, conn->pending_write_value, value_len);
+ conn->pending_write_value_len = 0;
+ conn->pending_value_handle = 0xffff;
}
return btstack_error_to_errno(err);
}
int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle) {
- DEBUG_printf("mp_bluetooth_exchange_mtu: conn_handle=%d mtu=%d\n", conn_handle, l2cap_max_le_mtu());
+ DEBUG_printf("mp_bluetooth_gattc_exchange_mtu: conn_handle=%d mtu=%d\n", conn_handle, l2cap_max_le_mtu());
- gatt_client_send_mtu_negotiation(&btstack_packet_handler_att_server, conn_handle);
+ gatt_client_send_mtu_negotiation(&btstack_packet_handler_generic, conn_handle);
return 0;
}
diff --git a/extmod/btstack/modbluetooth_btstack.h b/extmod/btstack/modbluetooth_btstack.h
index 7890bbfae2c4..7f4a1820737a 100644
--- a/extmod/btstack/modbluetooth_btstack.h
+++ b/extmod/btstack/modbluetooth_btstack.h
@@ -33,8 +33,6 @@
#include "lib/btstack/src/btstack.h"
-typedef struct _mp_btstack_pending_op_t mp_btstack_pending_op_t;
-
typedef struct _mp_bluetooth_btstack_root_pointers_t {
// This stores both the advertising data and the scan response data, concatenated together.
uint8_t *adv_data;
@@ -44,11 +42,12 @@ typedef struct _mp_bluetooth_btstack_root_pointers_t {
// Characteristic (and descriptor) value storage.
mp_gatts_db_t gatts_db;
- btstack_linked_list_t pending_ops;
-
- #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
+ #if MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
// Registration for notify/indicate events.
gatt_client_notification_t notification;
+
+ // Active connections (only used for GATT clients).
+ btstack_linked_list_t active_connections;
#endif
} mp_bluetooth_btstack_root_pointers_t;
diff --git a/extmod/extmod.cmake b/extmod/extmod.cmake
index 954bfc7e96e1..305cdee94276 100644
--- a/extmod/extmod.cmake
+++ b/extmod/extmod.cmake
@@ -6,6 +6,7 @@ set(MICROPY_OOFATFS_DIR "${MICROPY_DIR}/lib/oofatfs")
set(MICROPY_SOURCE_EXTMOD
${MICROPY_DIR}/shared/libc/abort_.c
${MICROPY_DIR}/shared/libc/printf.c
+ ${MICROPY_EXTMOD_DIR}/btstack/modbluetooth_btstack.c
${MICROPY_EXTMOD_DIR}/machine_bitstream.c
${MICROPY_EXTMOD_DIR}/machine_i2c.c
${MICROPY_EXTMOD_DIR}/machine_mem.c
@@ -18,27 +19,30 @@ set(MICROPY_SOURCE_EXTMOD
${MICROPY_EXTMOD_DIR}/modlwip.c
${MICROPY_EXTMOD_DIR}/modnetwork.c
${MICROPY_EXTMOD_DIR}/modonewire.c
- ${MICROPY_EXTMOD_DIR}/moduasyncio.c
- ${MICROPY_EXTMOD_DIR}/modubinascii.c
- ${MICROPY_EXTMOD_DIR}/moducryptolib.c
+ ${MICROPY_EXTMOD_DIR}/modasyncio.c
+ ${MICROPY_EXTMOD_DIR}/modbinascii.c
+ ${MICROPY_EXTMOD_DIR}/modcryptolib.c
${MICROPY_EXTMOD_DIR}/moductypes.c
- ${MICROPY_EXTMOD_DIR}/moduhashlib.c
- ${MICROPY_EXTMOD_DIR}/moduheapq.c
- ${MICROPY_EXTMOD_DIR}/modujson.c
- ${MICROPY_EXTMOD_DIR}/moduos.c
- ${MICROPY_EXTMOD_DIR}/moduplatform.c
- ${MICROPY_EXTMOD_DIR}/modurandom.c
- ${MICROPY_EXTMOD_DIR}/modure.c
- ${MICROPY_EXTMOD_DIR}/moduselect.c
- ${MICROPY_EXTMOD_DIR}/modusocket.c
- ${MICROPY_EXTMOD_DIR}/modussl_axtls.c
- ${MICROPY_EXTMOD_DIR}/modussl_mbedtls.c
- ${MICROPY_EXTMOD_DIR}/modutimeq.c
- ${MICROPY_EXTMOD_DIR}/moduwebsocket.c
- ${MICROPY_EXTMOD_DIR}/moduzlib.c
+ ${MICROPY_EXTMOD_DIR}/moddeflate.c
+ ${MICROPY_EXTMOD_DIR}/modhashlib.c
+ ${MICROPY_EXTMOD_DIR}/modheapq.c
+ ${MICROPY_EXTMOD_DIR}/modjson.c
+ ${MICROPY_EXTMOD_DIR}/modos.c
+ ${MICROPY_EXTMOD_DIR}/modplatform.c
+ ${MICROPY_EXTMOD_DIR}/modrandom.c
+ ${MICROPY_EXTMOD_DIR}/modre.c
+ ${MICROPY_EXTMOD_DIR}/modselect.c
+ ${MICROPY_EXTMOD_DIR}/modsocket.c
+ ${MICROPY_EXTMOD_DIR}/modssl_axtls.c
+ ${MICROPY_EXTMOD_DIR}/modssl_mbedtls.c
+ ${MICROPY_EXTMOD_DIR}/modtime.c
+ ${MICROPY_EXTMOD_DIR}/modwebsocket.c
${MICROPY_EXTMOD_DIR}/modwebrepl.c
- ${MICROPY_EXTMOD_DIR}/uos_dupterm.c
- ${MICROPY_EXTMOD_DIR}/utime_mphal.c
+ ${MICROPY_EXTMOD_DIR}/network_cyw43.c
+ ${MICROPY_EXTMOD_DIR}/network_lwip.c
+ ${MICROPY_EXTMOD_DIR}/network_ninaw10.c
+ ${MICROPY_EXTMOD_DIR}/network_wiznet5k.c
+ ${MICROPY_EXTMOD_DIR}/os_dupterm.c
${MICROPY_EXTMOD_DIR}/vfs.c
${MICROPY_EXTMOD_DIR}/vfs_blockdev.c
${MICROPY_EXTMOD_DIR}/vfs_fat.c
@@ -93,6 +97,7 @@ if(MICROPY_PY_BTREE)
)
list(APPEND MICROPY_DEF_CORE
+ MICROPY_PY_BTREE=1
__DBINTERFACE_PRIVATE=1
"virt_fd_t=void*"
)
@@ -149,7 +154,6 @@ if(MICROPY_SSL_MBEDTLS)
${MICROPY_LIB_MBEDTLS_DIR}/library/md4.c
${MICROPY_LIB_MBEDTLS_DIR}/library/md5.c
${MICROPY_LIB_MBEDTLS_DIR}/library/md.c
- ${MICROPY_LIB_MBEDTLS_DIR}/library/md_wrap.c
${MICROPY_LIB_MBEDTLS_DIR}/library/oid.c
${MICROPY_LIB_MBEDTLS_DIR}/library/padlock.c
${MICROPY_LIB_MBEDTLS_DIR}/library/pem.c
@@ -174,9 +178,11 @@ if(MICROPY_SSL_MBEDTLS)
${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_cli.c
${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_cookie.c
${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_srv.c
+ ${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_msg.c
${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_ticket.c
${MICROPY_LIB_MBEDTLS_DIR}/library/ssl_tls.c
${MICROPY_LIB_MBEDTLS_DIR}/library/timing.c
+ ${MICROPY_LIB_MBEDTLS_DIR}/library/constant_time.c
${MICROPY_LIB_MBEDTLS_DIR}/library/x509.c
${MICROPY_LIB_MBEDTLS_DIR}/library/x509_create.c
${MICROPY_LIB_MBEDTLS_DIR}/library/x509_crl.c
@@ -187,8 +193,12 @@ if(MICROPY_SSL_MBEDTLS)
${MICROPY_LIB_MBEDTLS_DIR}/library/xtea.c
)
+ if(NOT MBEDTLS_CONFIG_FILE)
+ set(MBEDTLS_CONFIG_FILE "${MICROPY_PORT_DIR}/mbedtls/mbedtls_config.h")
+ endif()
+
target_compile_definitions(micropy_lib_mbedtls INTERFACE
- MBEDTLS_CONFIG_FILE="${MICROPY_PORT_DIR}/mbedtls/mbedtls_config.h"
+ MBEDTLS_CONFIG_FILE="${MBEDTLS_CONFIG_FILE}"
)
list(APPEND MICROPY_INC_CORE
diff --git a/extmod/extmod.mk b/extmod/extmod.mk
index 3b10fc857c80..a15b7e4a5fcd 100644
--- a/extmod/extmod.mk
+++ b/extmod/extmod.mk
@@ -10,36 +10,37 @@ SRC_EXTMOD_C += \
extmod/machine_pwm.c \
extmod/machine_signal.c \
extmod/machine_spi.c \
+ extmod/machine_timer.c \
+ extmod/modasyncio.c \
+ extmod/modbinascii.c \
extmod/modbluetooth.c \
extmod/modbtree.c \
+ extmod/modcryptolib.c \
+ extmod/moddeflate.c \
extmod/modframebuf.c \
+ extmod/modhashlib.c \
+ extmod/modheapq.c \
+ extmod/modjson.c \
extmod/modlwip.c \
extmod/modnetwork.c \
extmod/modonewire.c \
- extmod/moduasyncio.c \
- extmod/modubinascii.c \
- extmod/moducryptolib.c \
+ extmod/modos.c \
+ extmod/modplatform.c\
+ extmod/modrandom.c \
+ extmod/modre.c \
+ extmod/modselect.c \
+ extmod/modsocket.c \
+ extmod/modssl_axtls.c \
+ extmod/modssl_mbedtls.c \
+ extmod/modtime.c \
extmod/moductypes.c \
- extmod/moduhashlib.c \
- extmod/moduheapq.c \
- extmod/modujson.c \
- extmod/moduos.c \
- extmod/moduplatform.c\
- extmod/modurandom.c \
- extmod/modure.c \
- extmod/moduselect.c \
- extmod/modusocket.c \
- extmod/modussl_axtls.c \
- extmod/modussl_mbedtls.c \
- extmod/modutimeq.c \
- extmod/moduwebsocket.c \
- extmod/moduzlib.c \
extmod/modwebrepl.c \
+ extmod/modwebsocket.c \
extmod/network_cyw43.c \
+ extmod/network_lwip.c \
extmod/network_ninaw10.c \
extmod/network_wiznet5k.c \
- extmod/uos_dupterm.c \
- extmod/utime_mphal.c \
+ extmod/os_dupterm.c \
extmod/vfs.c \
extmod/vfs_blockdev.c \
extmod/vfs_fat.c \
@@ -106,8 +107,8 @@ endif
################################################################################
# ussl
-ifeq ($(MICROPY_PY_USSL),1)
-CFLAGS_EXTMOD += -DMICROPY_PY_USSL=1
+ifeq ($(MICROPY_PY_SSL),1)
+CFLAGS_EXTMOD += -DMICROPY_PY_SSL=1
ifeq ($(MICROPY_SSL_AXTLS),1)
AXTLS_DIR = lib/axtls
GIT_SUBMODULES += $(AXTLS_DIR)
@@ -130,7 +131,9 @@ SRC_THIRDPARTY_C += $(addprefix $(AXTLS_DIR)/,\
)
else ifeq ($(MICROPY_SSL_MBEDTLS),1)
MBEDTLS_DIR = lib/mbedtls
+MBEDTLS_CONFIG_FILE ?= \"mbedtls/mbedtls_config.h\"
GIT_SUBMODULES += $(MBEDTLS_DIR)
+CFLAGS_EXTMOD += -DMBEDTLS_CONFIG_FILE=$(MBEDTLS_CONFIG_FILE)
CFLAGS_EXTMOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include
SRC_THIRDPARTY_C += lib/mbedtls_errors/mp_mbedtls_errors.c
SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\
@@ -168,7 +171,6 @@ SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\
md4.c \
md5.c \
md.c \
- md_wrap.c \
oid.c \
padlock.c \
pem.c \
@@ -193,9 +195,11 @@ SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\
ssl_cli.c \
ssl_cookie.c \
ssl_srv.c \
+ ssl_msg.c \
ssl_ticket.c \
ssl_tls.c \
timing.c \
+ constant_time.c \
x509.c \
x509_create.c \
x509_crl.c \
@@ -289,7 +293,7 @@ SRC_THIRDPARTY_C += $(addprefix $(BTREE_DIR)/,\
CFLAGS_EXTMOD += -DMICROPY_PY_BTREE=1
# we need to suppress certain warnings to get berkeley-db to compile cleanly
# and we have separate BTREE_DEFS so the definitions don't interfere with other source code
-$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter $(BTREE_DEFS)
+$(BUILD)/$(BTREE_DIR)/%.o: CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter -Wno-deprecated-non-prototype -Wno-unknown-warning-option $(BTREE_DEFS)
$(BUILD)/extmod/modbtree.o: CFLAGS += $(BTREE_DEFS)
endif
@@ -297,11 +301,23 @@ endif
# networking
ifeq ($(MICROPY_PY_NETWORK_CYW43),1)
+CYW43_DIR = lib/cyw43-driver
+GIT_SUBMODULES += $(CYW43_DIR)
CFLAGS_EXTMOD += -DMICROPY_PY_NETWORK_CYW43=1
-DRIVERS_SRC_C += drivers/cyw43/cyw43_ctrl.c drivers/cyw43/cyw43_lwip.c
-LIBS += $(TOP)/drivers/cyw43/libcyw43.a
+SRC_THIRDPARTY_C += $(addprefix $(CYW43_DIR)/src/,\
+ cyw43_ctrl.c \
+ cyw43_lwip.c \
+ cyw43_ll.c \
+ cyw43_sdio.c \
+ cyw43_stats.c \
+ )
+ifeq ($(MICROPY_PY_BLUETOOTH),1)
+DRIVERS_SRC_C += drivers/cyw43/cywbt.c
endif
+$(BUILD)/$(CYW43_DIR)/src/cyw43_%.o: CFLAGS += -std=c11
+endif # MICROPY_PY_NETWORK_CYW43
+
ifneq ($(MICROPY_PY_NETWORK_WIZNET5K),)
ifneq ($(MICROPY_PY_NETWORK_WIZNET5K),0)
WIZNET5K_DIR=lib/wiznet5k
diff --git a/extmod/machine_pwm.c b/extmod/machine_pwm.c
index 220d34d7da58..8a633b37939d 100644
--- a/extmod/machine_pwm.c
+++ b/extmod/machine_pwm.c
@@ -34,13 +34,11 @@
#include MICROPY_PY_MACHINE_PWM_INCLUDEFILE
#endif
-#if MICROPY_PY_MACHINE_PWM_INIT
STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_machine_pwm_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init);
-#endif
// PWM.deinit()
STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self_in) {
@@ -82,8 +80,6 @@ STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) {
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_obj, 1, 2, machine_pwm_duty);
#endif
-#if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
-
// PWM.duty_u16([value])
STATIC mp_obj_t machine_pwm_duty_u16(size_t n_args, const mp_obj_t *args) {
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(args[0]);
@@ -114,21 +110,15 @@ STATIC mp_obj_t machine_pwm_duty_ns(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pwm_duty_ns_obj, 1, 2, machine_pwm_duty_ns);
-#endif
-
STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {
- #if MICROPY_PY_MACHINE_PWM_INIT
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) },
- #endif
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_pwm_freq_obj) },
#if MICROPY_PY_MACHINE_PWM_DUTY
{ MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&machine_pwm_duty_obj) },
#endif
- #if MICROPY_PY_MACHINE_PWM_DUTY_U16_NS
{ MP_ROM_QSTR(MP_QSTR_duty_u16), MP_ROM_PTR(&machine_pwm_duty_u16_obj) },
{ MP_ROM_QSTR(MP_QSTR_duty_ns), MP_ROM_PTR(&machine_pwm_duty_ns_obj) },
- #endif
};
STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table);
diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c
index bb35cff38e61..8c4d91a3cf63 100644
--- a/extmod/machine_spi.c
+++ b/extmod/machine_spi.c
@@ -28,6 +28,9 @@
#include
#include "py/runtime.h"
+
+#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
+
#include "extmod/machine_spi.h"
// if a port didn't define MSB/LSB constants then provide them
@@ -39,8 +42,6 @@
/******************************************************************************/
// MicroPython bindings for generic machine.SPI
-#if MICROPY_PY_MACHINE_SPI || MICROPY_PY_MACHINE_SOFTSPI
-
STATIC mp_obj_t machine_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_obj_base_t *s = (mp_obj_base_t *)MP_OBJ_TO_PTR(args[0]);
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t *)MP_OBJ_TYPE_GET_SLOT(s->type, protocol);
diff --git a/extmod/machine_timer.c b/extmod/machine_timer.c
new file mode 100644
index 000000000000..68702cb74f60
--- /dev/null
+++ b/extmod/machine_timer.c
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_MACHINE_TIMER
+
+#include "shared/runtime/softtimer.h"
+
+typedef soft_timer_entry_t machine_timer_obj_t;
+
+const mp_obj_type_t machine_timer_type;
+
+STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ qstr mode = self->mode == SOFT_TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC;
+ mp_printf(print, "Timer(mode=%q, period=%u)", mode, self->delta_ms);
+}
+
+STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SOFT_TIMER_MODE_PERIODIC} },
+ { MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
+ { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
+ { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ };
+
+ // Parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ self->mode = args[ARG_mode].u_int;
+
+ uint64_t delta_ms = self->delta_ms;
+ if (args[ARG_freq].u_obj != mp_const_none) {
+ // Frequency specified in Hz
+ #if MICROPY_PY_BUILTINS_FLOAT
+ delta_ms = (uint32_t)(MICROPY_FLOAT_CONST(1000.0) / mp_obj_get_float(args[ARG_freq].u_obj));
+ #else
+ delta_ms = 1000 / mp_obj_get_int(args[ARG_freq].u_obj);
+ #endif
+ } else if (args[ARG_period].u_int != 0xffffffff) {
+ // Period specified
+ delta_ms = (uint64_t)args[ARG_period].u_int * 1000 / args[ARG_tick_hz].u_int;
+ }
+
+ if (delta_ms < 1) {
+ delta_ms = 1;
+ } else if (delta_ms >= 0x40000000) {
+ mp_raise_ValueError(MP_ERROR_TEXT("period too large"));
+ }
+ self->delta_ms = (uint32_t)delta_ms;
+
+ if (args[ARG_callback].u_obj != MP_OBJ_NULL) {
+ self->py_callback = args[ARG_callback].u_obj;
+ }
+
+ if (self->py_callback != mp_const_none) {
+ soft_timer_insert(self, self->delta_ms);
+ }
+
+ return mp_const_none;
+}
+
+STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ machine_timer_obj_t *self = m_new_obj(machine_timer_obj_t);
+ self->pairheap.base.type = &machine_timer_type;
+ self->flags = SOFT_TIMER_FLAG_PY_CALLBACK | SOFT_TIMER_FLAG_GC_ALLOCATED;
+ self->delta_ms = 1000;
+ self->py_callback = mp_const_none;
+
+ // Get timer id (only soft timer (-1) supported at the moment)
+ mp_int_t id = -1;
+ if (n_args > 0) {
+ id = mp_obj_get_int(args[0]);
+ --n_args;
+ ++args;
+ }
+ if (id != -1) {
+ mp_raise_ValueError(MP_ERROR_TEXT("Timer doesn't exist"));
+ }
+
+ if (n_args > 0 || n_kw > 0) {
+ // Start the timer
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ machine_timer_init_helper(self, n_args, args, &kw_args);
+ }
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ machine_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ soft_timer_remove(self);
+ return machine_timer_init_helper(self, n_args - 1, args + 1, kw_args);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
+
+STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
+ machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ soft_timer_remove(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
+
+STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(SOFT_TIMER_MODE_ONE_SHOT) },
+ { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(SOFT_TIMER_MODE_PERIODIC) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ machine_timer_type,
+ MP_QSTR_Timer,
+ MP_TYPE_FLAG_NONE,
+ make_new, machine_timer_make_new,
+ print, machine_timer_print,
+ locals_dict, &machine_timer_locals_dict
+ );
+
+#endif // MICROPY_PY_MACHINE_TIMER
diff --git a/extmod/mbedtls/mbedtls_config_common.h b/extmod/mbedtls/mbedtls_config_common.h
new file mode 100644
index 000000000000..bfbc6f7ba298
--- /dev/null
+++ b/extmod/mbedtls/mbedtls_config_common.h
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018-2022 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
+#define MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
+
+// If you want to debug MBEDTLS uncomment the following and
+// pass "3" to mbedtls_debug_set_threshold in socket_new.
+// #define MBEDTLS_DEBUG_C
+
+// Set mbedtls configuration.
+#define MBEDTLS_DEPRECATED_REMOVED
+#define MBEDTLS_AES_ROM_TABLES
+#define MBEDTLS_CIPHER_MODE_CBC
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+// #define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED // enabling this currently breaks ssl_data.py test
+#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+#define MBEDTLS_NO_PLATFORM_ENTROPY
+#define MBEDTLS_PKCS1_V15
+#define MBEDTLS_SHA256_SMALLER
+#define MBEDTLS_SSL_PROTO_TLS1
+#define MBEDTLS_SSL_PROTO_TLS1_1
+#define MBEDTLS_SSL_PROTO_TLS1_2
+#define MBEDTLS_SSL_SERVER_NAME_INDICATION
+
+// Use a smaller output buffer to reduce size of SSL context.
+#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384)
+#define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN)
+#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096)
+
+// Enable mbedtls modules.
+#define MBEDTLS_AES_C
+#define MBEDTLS_ASN1_PARSE_C
+#define MBEDTLS_ASN1_WRITE_C
+#define MBEDTLS_BIGNUM_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_CTR_DRBG_C
+#define MBEDTLS_ECDH_C
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ENTROPY_C
+#define MBEDTLS_ERROR_C
+#define MBEDTLS_MD_C
+#define MBEDTLS_MD5_C
+#define MBEDTLS_OID_C
+#define MBEDTLS_PKCS5_C
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_PLATFORM_C
+#define MBEDTLS_RSA_C
+#define MBEDTLS_SHA1_C
+#define MBEDTLS_SHA256_C
+#define MBEDTLS_SHA512_C
+#define MBEDTLS_SSL_CLI_C
+#define MBEDTLS_SSL_SRV_C
+#define MBEDTLS_SSL_TLS_C
+#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE
+#define MBEDTLS_X509_CRT_PARSE_C
+#define MBEDTLS_X509_USE_C
+
+// A port may enable this option to select additional bare-metal configuration.
+#if MICROPY_MBEDTLS_CONFIG_BARE_METAL
+
+// Bare-metal mbedtls configuration.
+#define MBEDTLS_PLATFORM_MEMORY
+#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+#define MBEDTLS_ENTROPY_HARDWARE_ALT
+
+// Bare-metal memory allocation hooks.
+#include
+#include
+void *m_tracked_calloc(size_t nmemb, size_t size);
+void m_tracked_free(void *ptr);
+#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc
+#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free
+#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
+
+#endif
+
+// Include mbedtls configuration checker.
+#include "mbedtls/check_config.h"
+
+#endif // MICROPY_INCLUDED_MBEDTLS_CONFIG_COMMON_H
diff --git a/extmod/misc.h b/extmod/misc.h
index a9392aa10b7b..80e5b59a08ee 100644
--- a/extmod/misc.h
+++ b/extmod/misc.h
@@ -32,17 +32,17 @@
#include
#include "py/runtime.h"
-MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_dupterm_obj);
#if MICROPY_PY_OS_DUPTERM
-bool mp_uos_dupterm_is_builtin_stream(mp_const_obj_t stream);
-void mp_uos_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached);
-uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags);
-int mp_uos_dupterm_rx_chr(void);
-void mp_uos_dupterm_tx_strn(const char *str, size_t len);
-void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
+bool mp_os_dupterm_is_builtin_stream(mp_const_obj_t stream);
+void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached);
+uintptr_t mp_os_dupterm_poll(uintptr_t poll_flags);
+int mp_os_dupterm_rx_chr(void);
+void mp_os_dupterm_tx_strn(const char *str, size_t len);
+void mp_os_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc);
#else
-#define mp_uos_dupterm_tx_strn(s, l)
+#define mp_os_dupterm_tx_strn(s, l)
#endif
#endif // MICROPY_INCLUDED_EXTMOD_MISC_H
diff --git a/extmod/modasyncio.c b/extmod/modasyncio.c
new file mode 100644
index 000000000000..a6a54eba8765
--- /dev/null
+++ b/extmod/modasyncio.c
@@ -0,0 +1,321 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/smallint.h"
+#include "py/pairheap.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_ASYNCIO
+
+// Used when task cannot be guaranteed to be non-NULL.
+#define TASK_PAIRHEAP(task) ((task) ? &(task)->pairheap : NULL)
+
+#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
+#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
+#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
+
+#define TASK_IS_DONE(task) ( \
+ (task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
+ || (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
+
+typedef struct _mp_obj_task_t {
+ mp_pairheap_t pairheap;
+ mp_obj_t coro;
+ mp_obj_t data;
+ mp_obj_t state;
+ mp_obj_t ph_key;
+} mp_obj_task_t;
+
+typedef struct _mp_obj_task_queue_t {
+ mp_obj_base_t base;
+ mp_obj_task_t *heap;
+} mp_obj_task_queue_t;
+
+STATIC const mp_obj_type_t task_queue_type;
+STATIC const mp_obj_type_t task_type;
+
+STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
+
+/******************************************************************************/
+// Ticks for task ordering in pairing heap
+
+STATIC mp_obj_t ticks(void) {
+ return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_TIME_TICKS_PERIOD - 1));
+}
+
+STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
+ mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
+ mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
+ mp_int_t diff = ((t1 - t0 + MICROPY_PY_TIME_TICKS_PERIOD / 2) & (MICROPY_PY_TIME_TICKS_PERIOD - 1))
+ - MICROPY_PY_TIME_TICKS_PERIOD / 2;
+ return diff;
+}
+
+STATIC int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
+ mp_obj_task_t *t1 = (mp_obj_task_t *)n1;
+ mp_obj_task_t *t2 = (mp_obj_task_t *)n2;
+ return MP_OBJ_SMALL_INT_VALUE(ticks_diff(t1->ph_key, t2->ph_key)) < 0;
+}
+
+/******************************************************************************/
+// TaskQueue class
+
+STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ (void)args;
+ mp_arg_check_num(n_args, n_kw, 0, 0, false);
+ mp_obj_task_queue_t *self = mp_obj_malloc(mp_obj_task_queue_t, type);
+ self->heap = (mp_obj_task_t *)mp_pairheap_new(task_lt);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t task_queue_peek(mp_obj_t self_in) {
+ mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->heap == NULL) {
+ return mp_const_none;
+ } else {
+ return MP_OBJ_FROM_PTR(self->heap);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_peek_obj, task_queue_peek);
+
+STATIC mp_obj_t task_queue_push(size_t n_args, const mp_obj_t *args) {
+ mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_task_t *task = MP_OBJ_TO_PTR(args[1]);
+ task->data = mp_const_none;
+ if (n_args == 2) {
+ task->ph_key = ticks();
+ } else {
+ assert(mp_obj_is_small_int(args[2]));
+ task->ph_key = args[2];
+ }
+ self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, TASK_PAIRHEAP(self->heap), TASK_PAIRHEAP(task));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_obj, 2, 3, task_queue_push);
+
+STATIC mp_obj_t task_queue_pop(mp_obj_t self_in) {
+ mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_task_t *head = (mp_obj_task_t *)mp_pairheap_peek(task_lt, &self->heap->pairheap);
+ if (head == NULL) {
+ mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
+ }
+ self->heap = (mp_obj_task_t *)mp_pairheap_pop(task_lt, &self->heap->pairheap);
+ return MP_OBJ_FROM_PTR(head);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_pop_obj, task_queue_pop);
+
+STATIC mp_obj_t task_queue_remove(mp_obj_t self_in, mp_obj_t task_in) {
+ mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_task_t *task = MP_OBJ_TO_PTR(task_in);
+ self->heap = (mp_obj_task_t *)mp_pairheap_delete(task_lt, &self->heap->pairheap, &task->pairheap);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_queue_remove_obj, task_queue_remove);
+
+STATIC const mp_rom_map_elem_t task_queue_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_peek), MP_ROM_PTR(&task_queue_peek_obj) },
+ { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&task_queue_push_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&task_queue_pop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&task_queue_remove_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(task_queue_locals_dict, task_queue_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ task_queue_type,
+ MP_QSTR_TaskQueue,
+ MP_TYPE_FLAG_NONE,
+ make_new, task_queue_make_new,
+ locals_dict, &task_queue_locals_dict
+ );
+
+/******************************************************************************/
+// Task class
+
+// This is the core asyncio context with cur_task, _task_queue and CancelledError.
+STATIC mp_obj_t asyncio_context = MP_OBJ_NULL;
+
+STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 2, false);
+ mp_obj_task_t *self = m_new_obj(mp_obj_task_t);
+ self->pairheap.base.type = type;
+ mp_pairheap_init_node(task_lt, &self->pairheap);
+ self->coro = args[0];
+ self->data = mp_const_none;
+ self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
+ self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
+ if (n_args == 2) {
+ asyncio_context = args[1];
+ }
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_obj_t task_done(mp_obj_t self_in) {
+ mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(TASK_IS_DONE(self));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_done_obj, task_done);
+
+STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
+ mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+ // Check if task is already finished.
+ if (TASK_IS_DONE(self)) {
+ return mp_const_false;
+ }
+ // Can't cancel self (not supported yet).
+ mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
+ if (self_in == cur_task) {
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
+ }
+ // If Task waits on another task then forward the cancel to the one it's waiting on.
+ while (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(self->data)), MP_OBJ_FROM_PTR(&task_type))) {
+ self = MP_OBJ_TO_PTR(self->data);
+ }
+
+ mp_obj_t _task_queue = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
+
+ // Reschedule Task as a cancelled task.
+ mp_obj_t dest[3];
+ mp_load_method_maybe(self->data, MP_QSTR_remove, dest);
+ if (dest[0] != MP_OBJ_NULL) {
+ // Not on the main running queue, remove the task from the queue it's on.
+ dest[2] = MP_OBJ_FROM_PTR(self);
+ mp_call_method_n_kw(1, 0, dest);
+ // _task_queue.push(self)
+ dest[0] = _task_queue;
+ dest[1] = MP_OBJ_FROM_PTR(self);
+ task_queue_push(2, dest);
+ } else if (ticks_diff(self->ph_key, ticks()) > 0) {
+ // On the main running queue but scheduled in the future, so bring it forward to now.
+ // _task_queue.remove(self)
+ task_queue_remove(_task_queue, MP_OBJ_FROM_PTR(self));
+ // _task_queue.push(self)
+ dest[0] = _task_queue;
+ dest[1] = MP_OBJ_FROM_PTR(self);
+ task_queue_push(2, dest);
+ }
+
+ self->data = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
+
+ return mp_const_true;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
+
+STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+ if (dest[0] == MP_OBJ_NULL) {
+ // Load
+ if (attr == MP_QSTR_coro) {
+ dest[0] = self->coro;
+ } else if (attr == MP_QSTR_data) {
+ dest[0] = self->data;
+ } else if (attr == MP_QSTR_state) {
+ dest[0] = self->state;
+ } else if (attr == MP_QSTR_done) {
+ dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
+ dest[1] = self_in;
+ } else if (attr == MP_QSTR_cancel) {
+ dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
+ dest[1] = self_in;
+ } else if (attr == MP_QSTR_ph_key) {
+ dest[0] = self->ph_key;
+ }
+ } else if (dest[1] != MP_OBJ_NULL) {
+ // Store
+ if (attr == MP_QSTR_data) {
+ self->data = dest[1];
+ dest[0] = MP_OBJ_NULL;
+ } else if (attr == MP_QSTR_state) {
+ self->state = dest[1];
+ dest[0] = MP_OBJ_NULL;
+ }
+ }
+}
+
+STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
+ (void)iter_buf;
+ mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+ if (TASK_IS_DONE(self)) {
+ // Signal that the completed-task has been await'ed on.
+ self->state = TASK_STATE_DONE_WAS_WAITED_ON;
+ } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
+ // Allocate the waiting queue.
+ self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
+ } else if (mp_obj_get_type(self->state) != &task_queue_type) {
+ // Task has state used for another purpose, so can't also wait on it.
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't wait"));
+ }
+ return self_in;
+}
+
+STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
+ mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
+ if (TASK_IS_DONE(self)) {
+ // Task finished, raise return value to caller so it can continue.
+ nlr_raise(self->data);
+ } else {
+ // Put calling task on waiting queue.
+ mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
+ mp_obj_t args[2] = { self->state, cur_task };
+ task_queue_push(2, args);
+ // Set calling task's data to this task that it waits on, to double-link it.
+ ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
+ }
+ return mp_const_none;
+}
+
+STATIC const mp_getiter_iternext_custom_t task_getiter_iternext = {
+ .getiter = task_getiter,
+ .iternext = task_iternext,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ task_type,
+ MP_QSTR_Task,
+ MP_TYPE_FLAG_ITER_IS_CUSTOM,
+ make_new, task_make_new,
+ attr, task_attr,
+ iter, &task_getiter_iternext
+ );
+
+/******************************************************************************/
+// C-level asyncio module
+
+STATIC const mp_rom_map_elem_t mp_module_asyncio_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__asyncio) },
+ { MP_ROM_QSTR(MP_QSTR_TaskQueue), MP_ROM_PTR(&task_queue_type) },
+ { MP_ROM_QSTR(MP_QSTR_Task), MP_ROM_PTR(&task_type) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_asyncio_globals, mp_module_asyncio_globals_table);
+
+const mp_obj_module_t mp_module_asyncio = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_asyncio_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__asyncio, mp_module_asyncio);
+
+#endif // MICROPY_PY_ASYNCIO
diff --git a/extmod/modbinascii.c b/extmod/modbinascii.c
new file mode 100644
index 000000000000..ed39960180ae
--- /dev/null
+++ b/extmod/modbinascii.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/binary.h"
+#include "py/objstr.h"
+
+#if MICROPY_PY_BINASCII
+
+#if MICROPY_PY_BUILTINS_BYTES_HEX
+STATIC mp_obj_t bytes_hex_as_bytes(size_t n_args, const mp_obj_t *args) {
+ return mp_obj_bytes_hex(n_args, args, &mp_type_bytes);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_hex_as_bytes_obj, 1, 2, bytes_hex_as_bytes);
+
+STATIC mp_obj_t bytes_fromhex_bytes(mp_obj_t data) {
+ return mp_obj_bytes_fromhex(MP_OBJ_FROM_PTR(&mp_type_bytes), data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(bytes_fromhex_obj, bytes_fromhex_bytes);
+#endif
+
+// If ch is a character in the base64 alphabet, and is not a pad character, then
+// the corresponding integer between 0 and 63, inclusively, is returned.
+// Otherwise, -1 is returned.
+static int mod_binascii_sextet(byte ch) {
+ if (ch >= 'A' && ch <= 'Z') {
+ return ch - 'A';
+ } else if (ch >= 'a' && ch <= 'z') {
+ return ch - 'a' + 26;
+ } else if (ch >= '0' && ch <= '9') {
+ return ch - '0' + 52;
+ } else if (ch == '+') {
+ return 62;
+ } else if (ch == '/') {
+ return 63;
+ } else {
+ return -1;
+ }
+}
+
+STATIC mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
+ byte *in = bufinfo.buf;
+
+ vstr_t vstr;
+ vstr_init(&vstr, (bufinfo.len * 3) / 4 + 1); // Potentially over-allocate
+ byte *out = (byte *)vstr.buf;
+
+ uint shift = 0;
+ int nbits = 0; // Number of meaningful bits in shift
+ bool hadpad = false; // Had a pad character since last valid character
+ for (size_t i = 0; i < bufinfo.len; i++) {
+ if (in[i] == '=') {
+ if ((nbits == 2) || ((nbits == 4) && hadpad)) {
+ nbits = 0;
+ break;
+ }
+ hadpad = true;
+ }
+
+ int sextet = mod_binascii_sextet(in[i]);
+ if (sextet == -1) {
+ continue;
+ }
+ hadpad = false;
+ shift = (shift << 6) | sextet;
+ nbits += 6;
+
+ if (nbits >= 8) {
+ nbits -= 8;
+ out[vstr.len++] = (shift >> nbits) & 0xFF;
+ }
+ }
+
+ if (nbits) {
+ mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
+ }
+
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
+
+STATIC mp_obj_t mod_binascii_b2a_base64(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_newline };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_newline, MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ uint8_t newline = args[ARG_newline].u_bool;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(pos_args[0], &bufinfo, MP_BUFFER_READ);
+
+ vstr_t vstr;
+ vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + newline);
+
+ // First pass, we convert input buffer to numeric base 64 values
+ byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
+ mp_uint_t i;
+ for (i = bufinfo.len; i >= 3; i -= 3) {
+ *out++ = (in[0] & 0xFC) >> 2;
+ *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
+ *out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6;
+ *out++ = in[2] & 0x3F;
+ in += 3;
+ }
+ if (i != 0) {
+ *out++ = (in[0] & 0xFC) >> 2;
+ if (i == 2) {
+ *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
+ *out++ = (in[1] & 0x0F) << 2;
+ } else {
+ *out++ = (in[0] & 0x03) << 4;
+ *out++ = 64;
+ }
+ *out = 64;
+ }
+
+ // Second pass, we convert number base 64 values to actual base64 ascii encoding
+ out = (byte *)vstr.buf;
+ for (mp_uint_t j = vstr.len - newline; j--;) {
+ if (*out < 26) {
+ *out += 'A';
+ } else if (*out < 52) {
+ *out += 'a' - 26;
+ } else if (*out < 62) {
+ *out += '0' - 52;
+ } else if (*out == 62) {
+ *out = '+';
+ } else if (*out == 63) {
+ *out = '/';
+ } else {
+ *out = '=';
+ }
+ out++;
+ }
+ if (newline) {
+ *out = '\n';
+ }
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_binascii_b2a_base64_obj, 1, mod_binascii_b2a_base64);
+
+#if MICROPY_PY_BINASCII_CRC32 && MICROPY_PY_DEFLATE
+#include "lib/uzlib/uzlib.h"
+
+STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
+ uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;
+ crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
+ return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
+#endif
+
+STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_binascii) },
+ #if MICROPY_PY_BUILTINS_BYTES_HEX
+ { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&bytes_hex_as_bytes_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&bytes_fromhex_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },
+ { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },
+ #if MICROPY_PY_BINASCII_CRC32 && MICROPY_PY_DEFLATE
+ { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
+
+const mp_obj_module_t mp_module_binascii = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_binascii, mp_module_binascii);
+
+#endif // MICROPY_PY_BINASCII
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index 3a51fb8b2399..7b13f9556c4f 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -733,7 +733,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gap_passkey_obj, 4, 4,
STATIC mp_obj_t bluetooth_ble_gatts_read(mp_obj_t self_in, mp_obj_t value_handle_in) {
(void)self_in;
size_t len = 0;
- uint8_t *buf;
+ const uint8_t *buf;
mp_bluetooth_gatts_read(mp_obj_get_int(value_handle_in), &buf, &len);
return mp_obj_new_bytes(buf, len);
}
@@ -751,32 +751,30 @@ STATIC mp_obj_t bluetooth_ble_gatts_write(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_write_obj, 3, 4, bluetooth_ble_gatts_write);
-STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
+STATIC mp_obj_t bluetooth_ble_gatts_notify_indicate(size_t n_args, const mp_obj_t *args, int gatts_op) {
mp_int_t conn_handle = mp_obj_get_int(args[1]);
mp_int_t value_handle = mp_obj_get_int(args[2]);
+ const uint8_t *value = NULL;
+ size_t value_len = 0;
if (n_args == 4 && args[3] != mp_const_none) {
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
- int err = mp_bluetooth_gatts_notify_send(conn_handle, value_handle, bufinfo.buf, bufinfo.len);
- bluetooth_handle_errno(err);
- return mp_const_none;
- } else {
- int err = mp_bluetooth_gatts_notify(conn_handle, value_handle);
- return bluetooth_handle_errno(err);
+ value = bufinfo.buf;
+ value_len = bufinfo.len;
}
+ return bluetooth_handle_errno(mp_bluetooth_gatts_notify_indicate(conn_handle, value_handle, gatts_op, value, value_len));
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
-STATIC mp_obj_t bluetooth_ble_gatts_indicate(mp_obj_t self_in, mp_obj_t conn_handle_in, mp_obj_t value_handle_in) {
- (void)self_in;
- mp_int_t conn_handle = mp_obj_get_int(conn_handle_in);
- mp_int_t value_handle = mp_obj_get_int(value_handle_in);
+STATIC mp_obj_t bluetooth_ble_gatts_notify(size_t n_args, const mp_obj_t *args) {
+ return bluetooth_ble_gatts_notify_indicate(n_args, args, MP_BLUETOOTH_GATTS_OP_NOTIFY);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_notify_obj, 3, 4, bluetooth_ble_gatts_notify);
- int err = mp_bluetooth_gatts_indicate(conn_handle, value_handle);
- return bluetooth_handle_errno(err);
+STATIC mp_obj_t bluetooth_ble_gatts_indicate(size_t n_args, const mp_obj_t *args) {
+ return bluetooth_ble_gatts_notify_indicate(n_args, args, MP_BLUETOOTH_GATTS_OP_INDICATE);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(bluetooth_ble_gatts_indicate_obj, bluetooth_ble_gatts_indicate);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gatts_indicate_obj, 3, 4, bluetooth_ble_gatts_indicate);
STATIC mp_obj_t bluetooth_ble_gatts_set_buffer(size_t n_args, const mp_obj_t *args) {
mp_int_t value_handle = mp_obj_get_int(args[1]);
@@ -843,12 +841,11 @@ STATIC mp_obj_t bluetooth_ble_gattc_write(size_t n_args, const mp_obj_t *args) {
mp_obj_t data = args[3];
mp_buffer_info_t bufinfo = {0};
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
- size_t len = bufinfo.len;
unsigned int mode = MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE;
if (n_args == 5) {
mode = mp_obj_get_int(args[4]);
}
- return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, &len, mode));
+ return bluetooth_handle_errno(mp_bluetooth_gattc_write(conn_handle, value_handle, bufinfo.buf, bufinfo.len, mode));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_gattc_write_obj, 4, 5, bluetooth_ble_gattc_write);
@@ -988,7 +985,7 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
);
STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubluetooth) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bluetooth) },
{ MP_ROM_QSTR(MP_QSTR_BLE), MP_ROM_PTR(&mp_type_bluetooth_ble) },
{ MP_ROM_QSTR(MP_QSTR_UUID), MP_ROM_PTR(&mp_type_bluetooth_uuid) },
@@ -1002,12 +999,16 @@ STATIC const mp_rom_map_elem_t mp_module_bluetooth_globals_table[] = {
STATIC MP_DEFINE_CONST_DICT(mp_module_bluetooth_globals, mp_module_bluetooth_globals_table);
-const mp_obj_module_t mp_module_ubluetooth = {
+const mp_obj_module_t mp_module_bluetooth = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_bluetooth_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_ubluetooth, mp_module_ubluetooth);
+// This module should not be extensible (as it is not a CPython standard
+// library nor is it necessary to override from the filesystem), however it
+// has previously been known as `ubluetooth`, so by making it extensible the
+// `ubluetooth` alias will continue to work.
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_bluetooth, mp_module_bluetooth);
// Helpers
@@ -1718,7 +1719,7 @@ mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, ui
return MP_OBJ_TO_PTR(elem->value);
}
-int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len) {
+int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, const uint8_t **value, size_t *value_len) {
MICROPY_PY_BLUETOOTH_ENTER
mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle);
if (entry) {
diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h
index ca6436b678d1..630a2705231e 100644
--- a/extmod/modbluetooth.h
+++ b/extmod/modbluetooth.h
@@ -84,7 +84,7 @@
#define MP_BLUETOOTH_DEFAULT_ATTR_LEN (20)
#endif
-#define MP_BLUETOOTH_CCCB_LEN (2)
+#define MP_BLUETOOTH_CCCD_LEN (2)
// Advertisement packet lengths
#define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32)
@@ -186,6 +186,10 @@
#define MP_BLUETOOTH_PASSKEY_ACTION_DISPLAY (3)
#define MP_BLUETOOTH_PASSKEY_ACTION_NUMERIC_COMPARISON (4)
+// These are the ops for mp_bluetooth_gatts_notify_indicate.
+#define MP_BLUETOOTH_GATTS_OP_NOTIFY (1)
+#define MP_BLUETOOTH_GATTS_OP_INDICATE (2)
+
/*
These aren't included in the module for space reasons, but can be used
in your Python code if necessary.
@@ -333,15 +337,11 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m
int mp_bluetooth_gatts_register_service_end(void);
// Read the value from the local gatts db (likely this has been written by a central).
-int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len);
+int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len);
// Write a value to the local gatts db (ready to be queried by a central). Optionally send notifications/indications.
int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len, bool send_update);
-// Notify the central that it should do a read.
-int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle);
-// Notify the central, including a data payload. (Note: does not set the gatts db value).
-int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len);
-// Indicate the central.
-int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle);
+// Send a notification/indication to the central, optionally with custom payload (otherwise the DB value is used).
+int mp_bluetooth_gatts_notify_indicate(uint16_t conn_handle, uint16_t value_handle, int gatts_op, const uint8_t *value, size_t value_len);
// Resize and enable/disable append-mode on a value.
// Append-mode means that remote writes will append and local reads will clear after reading.
@@ -391,7 +391,7 @@ int mp_bluetooth_gattc_discover_descriptors(uint16_t conn_handle, uint16_t start
int mp_bluetooth_gattc_read(uint16_t conn_handle, uint16_t value_handle);
// Write the value to the remote peripheral.
-int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode);
+int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len, unsigned int mode);
// Initiate MTU exchange for a specific connection using the preferred MTU.
int mp_bluetooth_gattc_exchange_mtu(uint16_t conn_handle);
@@ -508,7 +508,7 @@ STATIC inline void mp_bluetooth_gatts_db_reset(mp_gatts_db_t db) {
void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len);
mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle);
-int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len);
+int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, const uint8_t **value, size_t *value_len);
int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len);
int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append);
diff --git a/extmod/modbtree.c b/extmod/modbtree.c
index 2da65a2c7aff..9b2d184a1ee7 100644
--- a/extmod/modbtree.c
+++ b/extmod/modbtree.c
@@ -24,16 +24,39 @@
* THE SOFTWARE.
*/
-#include
-#include
-#include // for declaration of global errno variable
-#include
-
#include "py/runtime.h"
#include "py/stream.h"
#if MICROPY_PY_BTREE
+#include
+#include // for declaration of global errno variable
+#include
+
+// Undefine queue macros that will be defined in berkeley-db-1.xx headers
+// below, in case they clash with system ones defined in headers above.
+#undef LIST_HEAD
+#undef LIST_ENTRY
+#undef LIST_INIT
+#undef LIST_INSERT_AFTER
+#undef LIST_INSERT_HEAD
+#undef LIST_REMOVE
+#undef TAILQ_HEAD
+#undef TAILQ_ENTRY
+#undef TAILQ_INIT
+#undef TAILQ_INSERT_HEAD
+#undef TAILQ_INSERT_TAIL
+#undef TAILQ_INSERT_AFTER
+#undef TAILQ_REMOVE
+#undef CIRCLEQ_HEAD
+#undef CIRCLEQ_ENTRY
+#undef CIRCLEQ_INIT
+#undef CIRCLEQ_INSERT_AFTER
+#undef CIRCLEQ_INSERT_BEFORE
+#undef CIRCLEQ_INSERT_HEAD
+#undef CIRCLEQ_INSERT_TAIL
+#undef CIRCLEQ_REMOVE
+
#include
#include <../../btree/btree.h>
diff --git a/extmod/modcryptolib.c b/extmod/modcryptolib.c
new file mode 100644
index 000000000000..b33d8533fc5e
--- /dev/null
+++ b/extmod/modcryptolib.c
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2018 Paul Sokolovsky
+ * Copyright (c) 2018 Yonatan Goldschmidt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpconfig.h"
+
+#if MICROPY_PY_CRYPTOLIB
+
+#include
+#include
+
+#include "py/runtime.h"
+
+// This module implements crypto ciphers API, roughly following
+// https://www.python.org/dev/peps/pep-0272/ . Exact implementation
+// of PEP 272 can be made with a simple wrapper which adds all the
+// needed boilerplate.
+
+// values follow PEP 272
+enum {
+ UCRYPTOLIB_MODE_ECB = 1,
+ UCRYPTOLIB_MODE_CBC = 2,
+ UCRYPTOLIB_MODE_CTR = 6,
+};
+
+struct ctr_params {
+ // counter is the IV of the AES context.
+
+ size_t offset; // in encrypted_counter
+ // encrypted counter
+ uint8_t encrypted_counter[16];
+};
+
+#if MICROPY_SSL_AXTLS
+#include "lib/axtls/crypto/crypto.h"
+
+#define AES_CTX_IMPL AES_CTX
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+#include
+
+// we can't run mbedtls AES key schedule until we know whether we're used for encrypt or decrypt.
+// therefore, we store the key & keysize and on the first call to encrypt/decrypt we override them
+// with the mbedtls_aes_context, as they are not longer required. (this is done to save space)
+struct mbedtls_aes_ctx_with_key {
+ union {
+ mbedtls_aes_context mbedtls_ctx;
+ struct {
+ uint8_t key[32];
+ uint8_t keysize;
+ } init_data;
+ } u;
+ unsigned char iv[16];
+};
+#define AES_CTX_IMPL struct mbedtls_aes_ctx_with_key
+#endif
+
+typedef struct _mp_obj_aes_t {
+ mp_obj_base_t base;
+ AES_CTX_IMPL ctx;
+ uint8_t block_mode : 6;
+#define AES_KEYTYPE_NONE 0
+#define AES_KEYTYPE_ENC 1
+#define AES_KEYTYPE_DEC 2
+ uint8_t key_type : 2;
+} mp_obj_aes_t;
+
+static inline bool is_ctr_mode(int block_mode) {
+ #if MICROPY_PY_CRYPTOLIB_CTR
+ return block_mode == UCRYPTOLIB_MODE_CTR;
+ #else
+ return false;
+ #endif
+}
+
+static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
+ // ctr_params follows aes object struct
+ return (struct ctr_params *)&o[1];
+}
+
+#if MICROPY_SSL_AXTLS
+STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
+ assert(16 == keysize || 32 == keysize);
+ AES_set_key(ctx, key, iv, (16 == keysize) ? AES_MODE_128 : AES_MODE_256);
+}
+
+STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
+ if (!encrypt) {
+ AES_convert_key(ctx);
+ }
+}
+
+STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
+ memcpy(out, in, 16);
+ // We assume that out (vstr.buf or given output buffer) is uint32_t aligned
+ uint32_t *p = (uint32_t *)out;
+ // axTLS likes it weird and complicated with byteswaps
+ for (int i = 0; i < 4; i++) {
+ p[i] = MP_HTOBE32(p[i]);
+ }
+ if (encrypt) {
+ AES_encrypt(ctx, p);
+ } else {
+ AES_decrypt(ctx, p);
+ }
+ for (int i = 0; i < 4; i++) {
+ p[i] = MP_BE32TOH(p[i]);
+ }
+}
+
+STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
+ if (encrypt) {
+ AES_cbc_encrypt(ctx, in, out, in_len);
+ } else {
+ AES_cbc_decrypt(ctx, in, out, in_len);
+ }
+}
+
+#if MICROPY_PY_CRYPTOLIB_CTR
+// axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive.
+STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
+ size_t n = ctr_params->offset;
+ uint8_t *const counter = ctx->iv;
+
+ while (in_len--) {
+ if (n == 0) {
+ aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true);
+
+ // increment the 128-bit counter
+ for (int i = 15; i >= 0; --i) {
+ if (++counter[i] != 0) {
+ break;
+ }
+ }
+ }
+
+ *out++ = *in++ ^ ctr_params->encrypted_counter[n];
+ n = (n + 1) & 0xf;
+ }
+
+ ctr_params->offset = n;
+}
+#endif
+
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
+ ctx->u.init_data.keysize = keysize;
+ memcpy(ctx->u.init_data.key, key, keysize);
+
+ if (NULL != iv) {
+ memcpy(ctx->iv, iv, sizeof(ctx->iv));
+ }
+}
+
+STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
+ // first, copy key aside
+ uint8_t key[32];
+ uint8_t keysize = ctx->u.init_data.keysize;
+ memcpy(key, ctx->u.init_data.key, keysize);
+ // now, override key with the mbedtls context object
+ mbedtls_aes_init(&ctx->u.mbedtls_ctx);
+
+ // setkey call will succeed, we've already checked the keysize earlier.
+ assert(16 == keysize || 32 == keysize);
+ if (encrypt) {
+ mbedtls_aes_setkey_enc(&ctx->u.mbedtls_ctx, key, keysize * 8);
+ } else {
+ mbedtls_aes_setkey_dec(&ctx->u.mbedtls_ctx, key, keysize * 8);
+ }
+}
+
+STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
+ mbedtls_aes_crypt_ecb(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in, out);
+}
+
+STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
+ mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);
+}
+
+#if MICROPY_PY_CRYPTOLIB_CTR
+STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
+ mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out);
+}
+#endif
+
+#endif
+
+STATIC mp_obj_t cryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 2, 3, false);
+
+ const mp_int_t block_mode = mp_obj_get_int(args[1]);
+
+ switch (block_mode) {
+ case UCRYPTOLIB_MODE_ECB:
+ case UCRYPTOLIB_MODE_CBC:
+ #if MICROPY_PY_CRYPTOLIB_CTR
+ case UCRYPTOLIB_MODE_CTR:
+ #endif
+ break;
+
+ default:
+ mp_raise_ValueError(MP_ERROR_TEXT("mode"));
+ }
+
+ mp_obj_aes_t *o = mp_obj_malloc_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode), type);
+
+ o->block_mode = block_mode;
+ o->key_type = AES_KEYTYPE_NONE;
+
+ mp_buffer_info_t keyinfo;
+ mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);
+ if (32 != keyinfo.len && 16 != keyinfo.len) {
+ mp_raise_ValueError(MP_ERROR_TEXT("key"));
+ }
+
+ mp_buffer_info_t ivinfo;
+ ivinfo.buf = NULL;
+ if (n_args > 2 && args[2] != mp_const_none) {
+ mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ);
+
+ if (16 != ivinfo.len) {
+ mp_raise_ValueError(MP_ERROR_TEXT("IV"));
+ }
+ } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("IV"));
+ }
+
+ if (is_ctr_mode(block_mode)) {
+ ctr_params_from_aes(o)->offset = 0;
+ }
+
+ aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);
+
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
+ mp_obj_aes_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ mp_obj_t in_buf = args[1];
+ mp_obj_t out_buf = MP_OBJ_NULL;
+ if (n_args > 2) {
+ out_buf = args[2];
+ }
+
+ mp_buffer_info_t in_bufinfo;
+ mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);
+
+ if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("blksize % 16"));
+ }
+
+ vstr_t vstr;
+ mp_buffer_info_t out_bufinfo;
+ uint8_t *out_buf_ptr;
+
+ if (out_buf != MP_OBJ_NULL) {
+ mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE);
+ if (out_bufinfo.len < in_bufinfo.len) {
+ mp_raise_ValueError(MP_ERROR_TEXT("output too small"));
+ }
+ out_buf_ptr = out_bufinfo.buf;
+ } else {
+ vstr_init_len(&vstr, in_bufinfo.len);
+ out_buf_ptr = (uint8_t *)vstr.buf;
+ }
+
+ if (AES_KEYTYPE_NONE == self->key_type) {
+ // always set key for encryption if CTR mode.
+ const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode);
+ aes_final_set_key_impl(&self->ctx, encrypt_mode);
+ self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;
+ } else {
+ if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||
+ (!encrypt && self->key_type == AES_KEYTYPE_ENC)) {
+
+ mp_raise_ValueError(MP_ERROR_TEXT("can't encrypt & decrypt"));
+ }
+ }
+
+ switch (self->block_mode) {
+ case UCRYPTOLIB_MODE_ECB: {
+ uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;
+ uint8_t *top = in + in_bufinfo.len;
+ for (; in < top; in += 16, out += 16) {
+ aes_process_ecb_impl(&self->ctx, in, out, encrypt);
+ }
+ break;
+ }
+
+ case UCRYPTOLIB_MODE_CBC:
+ aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);
+ break;
+
+ #if MICROPY_PY_CRYPTOLIB_CTR
+ case UCRYPTOLIB_MODE_CTR:
+ aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len,
+ ctr_params_from_aes(self));
+ break;
+ #endif
+ }
+
+ if (out_buf != MP_OBJ_NULL) {
+ return out_buf;
+ }
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+
+STATIC mp_obj_t cryptolib_aes_encrypt(size_t n_args, const mp_obj_t *args) {
+ return aes_process(n_args, args, true);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(cryptolib_aes_encrypt_obj, 2, 3, cryptolib_aes_encrypt);
+
+STATIC mp_obj_t cryptolib_aes_decrypt(size_t n_args, const mp_obj_t *args) {
+ return aes_process(n_args, args, false);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(cryptolib_aes_decrypt_obj, 2, 3, cryptolib_aes_decrypt);
+
+STATIC const mp_rom_map_elem_t cryptolib_aes_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&cryptolib_aes_encrypt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&cryptolib_aes_decrypt_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(cryptolib_aes_locals_dict, cryptolib_aes_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ cryptolib_aes_type,
+ MP_QSTR_aes,
+ MP_TYPE_FLAG_NONE,
+ make_new, cryptolib_aes_make_new,
+ locals_dict, &cryptolib_aes_locals_dict
+ );
+
+STATIC const mp_rom_map_elem_t mp_module_cryptolib_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cryptolib) },
+ { MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&cryptolib_aes_type) },
+ #if MICROPY_PY_CRYPTOLIB_CONSTS
+ { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },
+ { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },
+ #if MICROPY_PY_CRYPTOLIB_CTR
+ { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) },
+ #endif
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_cryptolib_globals, mp_module_cryptolib_globals_table);
+
+const mp_obj_module_t mp_module_cryptolib = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_cryptolib_globals,
+};
+
+// This module should not be extensible (as it is not a CPython standard
+// library nor is it necessary to override from the filesystem), however it
+// has previously been known as `ucryptolib`, so by making it extensible the
+// `ucryptolib` alias will continue to work.
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_cryptolib, mp_module_cryptolib);
+
+#endif // MICROPY_PY_CRYPTOLIB
diff --git a/extmod/moddeflate.c b/extmod/moddeflate.c
new file mode 100644
index 000000000000..1d8a8acf73b0
--- /dev/null
+++ b/extmod/moddeflate.c
@@ -0,0 +1,404 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Jim Mussared
+ *
+ * Based on extmod/modzlib.c
+ * Copyright (c) 2014-2016 Paul Sokolovsky
+ * Copyright (c) 2021-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+
+#if MICROPY_PY_DEFLATE
+
+#include "lib/uzlib/uzlib.h"
+
+#if 0 // print debugging info
+#define DEBUG_printf DEBUG_printf
+#else // don't print debugging info
+#define DEBUG_printf(...) (void)0
+#endif
+
+typedef enum {
+ DEFLATEIO_FORMAT_MIN = 0,
+ DEFLATEIO_FORMAT_AUTO = DEFLATEIO_FORMAT_MIN, // Read mode this means auto-detect zlib/gzip, write mode this means RAW.
+ DEFLATEIO_FORMAT_RAW = 1,
+ DEFLATEIO_FORMAT_ZLIB = 2,
+ DEFLATEIO_FORMAT_GZIP = 3,
+ DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP,
+} deflateio_format_t;
+
+const int DEFLATEIO_DEFAULT_WBITS = 8;
+
+typedef struct {
+ void *window;
+ uzlib_uncomp_t decomp;
+ bool eof;
+} mp_obj_deflateio_read_t;
+
+#if MICROPY_PY_DEFLATE_COMPRESS
+typedef struct {
+ void *window;
+ size_t input_len;
+ uint32_t input_checksum;
+ uzlib_lz77_state_t lz77;
+} mp_obj_deflateio_write_t;
+#endif
+
+typedef struct {
+ mp_obj_base_t base;
+ mp_obj_t stream;
+ uint8_t format : 2;
+ uint8_t window_bits : 4;
+ bool close : 1;
+ mp_obj_deflateio_read_t *read;
+ #if MICROPY_PY_DEFLATE_COMPRESS
+ mp_obj_deflateio_write_t *write;
+ #endif
+} mp_obj_deflateio_t;
+
+STATIC int deflateio_read_stream(void *data) {
+ mp_obj_deflateio_t *self = data;
+ const mp_stream_p_t *stream = mp_get_stream(self->stream);
+ int err;
+ byte c;
+ mp_uint_t out_sz = stream->read(self->stream, &c, 1, &err);
+ if (out_sz == MP_STREAM_ERROR) {
+ mp_raise_OSError(err);
+ }
+ if (out_sz == 0) {
+ mp_raise_type(&mp_type_EOFError);
+ }
+ return c;
+}
+
+STATIC bool deflateio_init_read(mp_obj_deflateio_t *self) {
+ if (self->read) {
+ return true;
+ }
+
+ mp_get_stream_raise(self->stream, MP_STREAM_OP_READ);
+
+ self->read = m_new_obj(mp_obj_deflateio_read_t);
+ memset(&self->read->decomp, 0, sizeof(self->read->decomp));
+ self->read->decomp.source_read_data = self;
+ self->read->decomp.source_read_cb = deflateio_read_stream;
+ self->read->eof = false;
+
+ // Don't modify self->window_bits as it may also be used for write.
+ int wbits = self->window_bits;
+
+ // Parse the header if we're in NONE/ZLIB/GZIP modes.
+ if (self->format != DEFLATEIO_FORMAT_RAW) {
+ int header_wbits = wbits;
+ int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits);
+ if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) {
+ return false;
+ }
+ if (wbits == 0 && header_wbits < 15) {
+ // If the header specified something lower than the default, then
+ // use that instead.
+ wbits = header_wbits;
+ }
+ }
+
+ if (wbits == 0) {
+ wbits = DEFLATEIO_DEFAULT_WBITS;
+ }
+
+ size_t window_len = 1 << wbits;
+ self->read->window = m_new(uint8_t, window_len);
+
+ uzlib_uncompress_init(&self->read->decomp, self->read->window, window_len);
+
+ return true;
+}
+
+#if MICROPY_PY_DEFLATE_COMPRESS
+STATIC void deflateio_out_byte(void *data, uint8_t b) {
+ mp_obj_deflateio_t *self = data;
+ const mp_stream_p_t *stream = mp_get_stream(self->stream);
+ int err;
+ mp_uint_t ret = stream->write(self->stream, &b, 1, &err);
+ if (ret == MP_STREAM_ERROR) {
+ mp_raise_OSError(err);
+ }
+}
+
+STATIC bool deflateio_init_write(mp_obj_deflateio_t *self) {
+ if (self->write) {
+ return true;
+ }
+
+ const mp_stream_p_t *stream = mp_get_stream_raise(self->stream, MP_STREAM_OP_WRITE);
+
+ self->write = m_new_obj(mp_obj_deflateio_write_t);
+ self->write->input_len = 0;
+
+ int wbits = self->window_bits;
+ if (wbits == 0) {
+ wbits = DEFLATEIO_DEFAULT_WBITS;
+ }
+ size_t window_len = 1 << wbits;
+ self->write->window = m_new(uint8_t, window_len);
+
+ uzlib_lz77_init(&self->write->lz77, self->write->window, window_len);
+ self->write->lz77.dest_write_data = self;
+ self->write->lz77.dest_write_cb = deflateio_out_byte;
+
+ // Write header if needed.
+ mp_uint_t ret = 0;
+ int err;
+ if (self->format == DEFLATEIO_FORMAT_ZLIB) {
+ // -----CMF------ ----------FLG---------------
+ // CINFO(5) CM(3) FLEVEL(2) FDICT(1) FCHECK(5)
+ uint8_t buf[] = { 0x08, 0x80 }; // CM=2 (deflate), FLEVEL=2 (default), FDICT=0 (no dictionary)
+ buf[0] |= MAX(wbits - 8, 1) << 4; // base-2 logarithm of the LZ77 window size, minus eight.
+ buf[1] |= 31 - ((buf[0] * 256 + buf[1]) % 31); // (CMF*256 + FLG) % 31 == 0.
+ ret = stream->write(self->stream, buf, sizeof(buf), &err);
+
+ self->write->input_checksum = 1; // ADLER32
+ } else if (self->format == DEFLATEIO_FORMAT_GZIP) {
+ // ID1(8) ID2(8) CM(8) ---FLG--- MTIME(32) XFL(8) OS(8)
+ // FLG: x x x FCOMMENT FNAME FEXTRA FHCRC FTEXT
+ uint8_t buf[] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03 }; // MTIME=0, XFL=4 (fastest), OS=3 (unix)
+ ret = stream->write(self->stream, buf, sizeof(buf), &err);
+
+ self->write->input_checksum = ~0; // CRC32
+ }
+ if (ret == MP_STREAM_ERROR) {
+ return false;
+ }
+
+ // Write starting block.
+ uzlib_start_block(&self->write->lz77);
+
+ return true;
+}
+#endif
+
+STATIC mp_obj_t deflateio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
+ // args: stream, format=NONE, wbits=0, close=False
+ mp_arg_check_num(n_args, n_kw, 1, 4, false);
+
+ mp_int_t format = n_args > 1 ? mp_obj_get_int(args_in[1]) : DEFLATEIO_FORMAT_AUTO;
+ mp_int_t wbits = n_args > 2 ? mp_obj_get_int(args_in[2]) : 0;
+
+ if (format < DEFLATEIO_FORMAT_MIN || format > DEFLATEIO_FORMAT_MAX) {
+ mp_raise_ValueError(MP_ERROR_TEXT("format"));
+ }
+ if (wbits != 0 && (wbits < 5 || wbits > 15)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("wbits"));
+ }
+
+ mp_obj_deflateio_t *self = mp_obj_malloc(mp_obj_deflateio_t, type);
+ self->stream = args_in[0];
+ self->format = format;
+ self->window_bits = wbits;
+ self->read = NULL;
+ #if MICROPY_PY_DEFLATE_COMPRESS
+ self->write = NULL;
+ #endif
+ self->close = n_args > 3 ? mp_obj_is_true(args_in[3]) : false;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC mp_uint_t deflateio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(o_in);
+
+ if (self->stream == MP_OBJ_NULL || !deflateio_init_read(self)) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+
+ if (self->read->eof) {
+ return 0;
+ }
+
+ self->read->decomp.dest = buf;
+ self->read->decomp.dest_limit = (uint8_t *)buf + size;
+ int st = uzlib_uncompress_chksum(&self->read->decomp);
+ if (st == UZLIB_DONE) {
+ self->read->eof = true;
+ }
+ if (st < 0) {
+ DEBUG_printf("uncompress error=" INT_FMT "\n", st);
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ return self->read->decomp.dest - (uint8_t *)buf;
+}
+
+#if MICROPY_PY_DEFLATE_COMPRESS
+STATIC mp_uint_t deflateio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->stream == MP_OBJ_NULL || !deflateio_init_write(self)) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+
+ self->write->input_len += size;
+ if (self->format == DEFLATEIO_FORMAT_ZLIB) {
+ self->write->input_checksum = uzlib_adler32(buf, size, self->write->input_checksum);
+ } else if (self->format == DEFLATEIO_FORMAT_GZIP) {
+ self->write->input_checksum = uzlib_crc32(buf, size, self->write->input_checksum);
+ }
+
+ uzlib_lz77_compress(&self->write->lz77, buf, size);
+ return size;
+}
+
+static inline void put_le32(char *buf, uint32_t value) {
+ buf[0] = value & 0xff;
+ buf[1] = value >> 8 & 0xff;
+ buf[2] = value >> 16 & 0xff;
+ buf[3] = value >> 24 & 0xff;
+}
+
+static inline void put_be32(char *buf, uint32_t value) {
+ buf[3] = value & 0xff;
+ buf[2] = value >> 8 & 0xff;
+ buf[1] = value >> 16 & 0xff;
+ buf[0] = value >> 24 & 0xff;
+}
+#endif
+
+STATIC mp_uint_t deflateio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ if (request == MP_STREAM_CLOSE) {
+ mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
+
+ mp_uint_t ret = 0;
+
+ if (self->stream != MP_OBJ_NULL) {
+ #if MICROPY_PY_DEFLATE_COMPRESS
+ if (self->write) {
+ uzlib_finish_block(&self->write->lz77);
+
+ const mp_stream_p_t *stream = mp_get_stream(self->stream);
+
+ // Write footer if needed.
+ if (self->format == DEFLATEIO_FORMAT_ZLIB || self->format == DEFLATEIO_FORMAT_GZIP) {
+ char footer[8];
+ size_t footer_len;
+ if (self->format == DEFLATEIO_FORMAT_ZLIB) {
+ put_be32(&footer[0], self->write->input_checksum);
+ footer_len = 4;
+ } else { // DEFLATEIO_FORMAT_GZIP
+ put_le32(&footer[0], ~self->write->input_checksum);
+ put_le32(&footer[4], self->write->input_len);
+ footer_len = 8;
+ }
+ if (stream->write(self->stream, footer, footer_len, errcode) == MP_STREAM_ERROR) {
+ ret = MP_STREAM_ERROR;
+ }
+ }
+ }
+ #endif
+
+ // Only close the stream if required. e.g. when using io.BytesIO
+ // it needs to stay open so that getvalue() can be called.
+ if (self->close) {
+ mp_stream_close(self->stream);
+ }
+
+ // Either way, free the reference to the stream.
+ self->stream = MP_OBJ_NULL;
+ }
+
+ return ret;
+ } else {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+}
+
+STATIC const mp_stream_p_t deflateio_stream_p = {
+ .read = deflateio_read,
+ #if MICROPY_PY_DEFLATE_COMPRESS
+ .write = deflateio_write,
+ #endif
+ .ioctl = deflateio_ioctl,
+};
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t deflateio_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ #if MICROPY_PY_DEFLATE_COMPRESS
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ deflateio_type,
+ MP_QSTR_DeflateIO,
+ MP_TYPE_FLAG_NONE,
+ make_new, deflateio_make_new,
+ protocol, &deflateio_stream_p,
+ locals_dict, &deflateio_locals_dict
+ );
+
+STATIC const mp_rom_map_elem_t mp_module_deflate_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_deflate) },
+ { MP_ROM_QSTR(MP_QSTR_DeflateIO), MP_ROM_PTR(&deflateio_type) },
+ { MP_ROM_QSTR(MP_QSTR_AUTO), MP_ROM_INT(DEFLATEIO_FORMAT_AUTO) },
+ { MP_ROM_QSTR(MP_QSTR_RAW), MP_ROM_INT(DEFLATEIO_FORMAT_RAW) },
+ { MP_ROM_QSTR(MP_QSTR_ZLIB), MP_ROM_INT(DEFLATEIO_FORMAT_ZLIB) },
+ { MP_ROM_QSTR(MP_QSTR_GZIP), MP_ROM_INT(DEFLATEIO_FORMAT_GZIP) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_deflate_globals, mp_module_deflate_globals_table);
+
+const mp_obj_module_t mp_module_deflate = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_deflate_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_deflate, mp_module_deflate);
+#endif // !MICROPY_ENABLE_DYNRUNTIME
+
+// Source files #include'd here to make sure they're compiled in
+// only if the module is enabled.
+
+#include "lib/uzlib/tinflate.c"
+#include "lib/uzlib/header.c"
+#include "lib/uzlib/adler32.c"
+#include "lib/uzlib/crc32.c"
+
+#if MICROPY_PY_DEFLATE_COMPRESS
+#include "lib/uzlib/lz77.c"
+#endif
+
+#endif // MICROPY_PY_DEFLATE
diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c
index e7825b59128e..87f7609dd8a8 100644
--- a/extmod/modframebuf.c
+++ b/extmod/modframebuf.c
@@ -748,19 +748,31 @@ STATIC mp_obj_t framebuf_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ys
if (xstep < 0) {
sx = 0;
xend = self->width + xstep;
+ if (xend <= 0) {
+ return mp_const_none;
+ }
dx = 1;
} else {
sx = self->width - 1;
xend = xstep - 1;
+ if (xend >= sx) {
+ return mp_const_none;
+ }
dx = -1;
}
if (ystep < 0) {
y = 0;
yend = self->height + ystep;
+ if (yend <= 0) {
+ return mp_const_none;
+ }
dy = 1;
} else {
y = self->height - 1;
yend = ystep - 1;
+ if (yend >= y) {
+ return mp_const_none;
+ }
dy = -1;
}
for (; y != yend; y += dy) {
diff --git a/extmod/modhashlib.c b/extmod/modhashlib.c
new file mode 100644
index 000000000000..4cdc23fddc6c
--- /dev/null
+++ b/extmod/modhashlib.c
@@ -0,0 +1,379 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/runtime.h"
+
+#if MICROPY_PY_HASHLIB
+
+#if MICROPY_SSL_MBEDTLS
+#include "mbedtls/version.h"
+#endif
+
+#if MICROPY_PY_HASHLIB_SHA256
+
+#if MICROPY_SSL_MBEDTLS
+#include "mbedtls/sha256.h"
+#else
+#include "lib/crypto-algorithms/sha256.h"
+#endif
+
+#endif
+
+#if MICROPY_PY_HASHLIB_SHA1 || MICROPY_PY_HASHLIB_MD5
+
+#if MICROPY_SSL_AXTLS
+#include "lib/axtls/crypto/crypto.h"
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+#include "mbedtls/md5.h"
+#include "mbedtls/sha1.h"
+#endif
+
+#endif
+
+typedef struct _mp_obj_hash_t {
+ mp_obj_base_t base;
+ bool final; // if set, update and digest raise an exception
+ uintptr_t state[0]; // must be aligned to a machine word
+} mp_obj_hash_t;
+
+static void hashlib_ensure_not_final(mp_obj_hash_t *self) {
+ if (self->final) {
+ mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
+ }
+}
+
+#if MICROPY_PY_HASHLIB_SHA256
+STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
+
+#if MICROPY_SSL_MBEDTLS
+
+#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
+#define mbedtls_sha256_starts_ret mbedtls_sha256_starts
+#define mbedtls_sha256_update_ret mbedtls_sha256_update
+#define mbedtls_sha256_finish_ret mbedtls_sha256_finish
+#endif
+
+STATIC mp_obj_t hashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context), type);
+ o->final = false;
+ mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
+ mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
+ if (n_args == 1) {
+ hashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_sha256_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, 32);
+ mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+
+#else
+
+#include "lib/crypto-algorithms/sha256.c"
+
+STATIC mp_obj_t hashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX), type);
+ o->final = false;
+ sha256_init((CRYAL_SHA256_CTX *)o->state);
+ if (n_args == 1) {
+ hashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_sha256_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
+ sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+#endif
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_sha256_update_obj, hashlib_sha256_update);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_sha256_digest_obj, hashlib_sha256_digest);
+
+STATIC const mp_rom_map_elem_t hashlib_sha256_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_sha256_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_sha256_digest_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(hashlib_sha256_locals_dict, hashlib_sha256_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ hashlib_sha256_type,
+ MP_QSTR_sha256,
+ MP_TYPE_FLAG_NONE,
+ make_new, hashlib_sha256_make_new,
+ locals_dict, &hashlib_sha256_locals_dict
+ );
+#endif
+
+#if MICROPY_PY_HASHLIB_SHA1
+STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);
+
+#if MICROPY_SSL_AXTLS
+STATIC mp_obj_t hashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(SHA1_CTX), type);
+ o->final = false;
+ SHA1_Init((SHA1_CTX *)o->state);
+ if (n_args == 1) {
+ hashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_sha1_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, SHA1_SIZE);
+ SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+#endif
+
+#if MICROPY_SSL_MBEDTLS
+
+#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
+#define mbedtls_sha1_starts_ret mbedtls_sha1_starts
+#define mbedtls_sha1_update_ret mbedtls_sha1_update
+#define mbedtls_sha1_finish_ret mbedtls_sha1_finish
+#endif
+
+STATIC mp_obj_t hashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context), type);
+ o->final = false;
+ mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
+ mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
+ if (n_args == 1) {
+ hashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_sha1_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, 20);
+ mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
+ mbedtls_sha1_free((mbedtls_sha1_context *)self->state);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+#endif
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_sha1_update_obj, hashlib_sha1_update);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_sha1_digest_obj, hashlib_sha1_digest);
+
+STATIC const mp_rom_map_elem_t hashlib_sha1_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_sha1_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_sha1_digest_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(hashlib_sha1_locals_dict, hashlib_sha1_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ hashlib_sha1_type,
+ MP_QSTR_sha1,
+ MP_TYPE_FLAG_NONE,
+ make_new, hashlib_sha1_make_new,
+ locals_dict, &hashlib_sha1_locals_dict
+ );
+#endif
+
+#if MICROPY_PY_HASHLIB_MD5
+STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg);
+
+#if MICROPY_SSL_AXTLS
+STATIC mp_obj_t hashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(MD5_CTX), type);
+ o->final = false;
+ MD5_Init((MD5_CTX *)o->state);
+ if (n_args == 1) {
+ hashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_md5_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, MD5_SIZE);
+ MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+#endif // MICROPY_SSL_AXTLS
+
+#if MICROPY_SSL_MBEDTLS
+
+#if MBEDTLS_VERSION_NUMBER < 0x02070000
+#define mbedtls_md5_starts_ret mbedtls_md5_starts
+#define mbedtls_md5_update_ret mbedtls_md5_update
+#define mbedtls_md5_finish_ret mbedtls_md5_finish
+#endif
+
+STATIC mp_obj_t hashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context), type);
+ o->final = false;
+ mbedtls_md5_init((mbedtls_md5_context *)o->state);
+ mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
+ if (n_args == 1) {
+ hashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t hashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t hashlib_md5_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ hashlib_ensure_not_final(self);
+ self->final = true;
+ vstr_t vstr;
+ vstr_init_len(&vstr, 16);
+ mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
+ mbedtls_md5_free((mbedtls_md5_context *)self->state);
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+#endif // MICROPY_SSL_MBEDTLS
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(hashlib_md5_update_obj, hashlib_md5_update);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(hashlib_md5_digest_obj, hashlib_md5_digest);
+
+STATIC const mp_rom_map_elem_t hashlib_md5_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hashlib_md5_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hashlib_md5_digest_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(hashlib_md5_locals_dict, hashlib_md5_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ hashlib_md5_type,
+ MP_QSTR_md5,
+ MP_TYPE_FLAG_NONE,
+ make_new, hashlib_md5_make_new,
+ locals_dict, &hashlib_md5_locals_dict
+ );
+#endif // MICROPY_PY_HASHLIB_MD5
+
+STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) },
+ #if MICROPY_PY_HASHLIB_SHA256
+ { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&hashlib_sha256_type) },
+ #endif
+ #if MICROPY_PY_HASHLIB_SHA1
+ { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&hashlib_sha1_type) },
+ #endif
+ #if MICROPY_PY_HASHLIB_MD5
+ { MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&hashlib_md5_type) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
+
+const mp_obj_module_t mp_module_hashlib = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_hashlib_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_hashlib, mp_module_hashlib);
+
+#endif // MICROPY_PY_HASHLIB
diff --git a/extmod/modheapq.c b/extmod/modheapq.c
new file mode 100644
index 000000000000..db1e35bac283
--- /dev/null
+++ b/extmod/modheapq.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+
+#if MICROPY_PY_HEAPQ
+
+// the algorithm here is modelled on CPython's heapq.py
+
+STATIC mp_obj_list_t *heapq_get_heap(mp_obj_t heap_in) {
+ if (!mp_obj_is_type(heap_in, &mp_type_list)) {
+ mp_raise_TypeError(MP_ERROR_TEXT("heap must be a list"));
+ }
+ return MP_OBJ_TO_PTR(heap_in);
+}
+
+STATIC void heapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
+ mp_obj_t item = heap->items[pos];
+ while (pos > start_pos) {
+ mp_uint_t parent_pos = (pos - 1) >> 1;
+ mp_obj_t parent = heap->items[parent_pos];
+ if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
+ heap->items[pos] = parent;
+ pos = parent_pos;
+ } else {
+ break;
+ }
+ }
+ heap->items[pos] = item;
+}
+
+STATIC void heapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
+ mp_uint_t start_pos = pos;
+ mp_uint_t end_pos = heap->len;
+ mp_obj_t item = heap->items[pos];
+ for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
+ // choose right child if it's <= left child
+ if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
+ child_pos += 1;
+ }
+ // bubble up the smaller child
+ heap->items[pos] = heap->items[child_pos];
+ pos = child_pos;
+ }
+ heap->items[pos] = item;
+ heapq_heap_siftdown(heap, start_pos, pos);
+}
+
+STATIC mp_obj_t mod_heapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
+ mp_obj_list_t *heap = heapq_get_heap(heap_in);
+ mp_obj_list_append(heap_in, item);
+ heapq_heap_siftdown(heap, 0, heap->len - 1);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_heapq_heappush_obj, mod_heapq_heappush);
+
+STATIC mp_obj_t mod_heapq_heappop(mp_obj_t heap_in) {
+ mp_obj_list_t *heap = heapq_get_heap(heap_in);
+ if (heap->len == 0) {
+ mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
+ }
+ mp_obj_t item = heap->items[0];
+ heap->len -= 1;
+ heap->items[0] = heap->items[heap->len];
+ heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
+ if (heap->len) {
+ heapq_heap_siftup(heap, 0);
+ }
+ return item;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_heapq_heappop_obj, mod_heapq_heappop);
+
+STATIC mp_obj_t mod_heapq_heapify(mp_obj_t heap_in) {
+ mp_obj_list_t *heap = heapq_get_heap(heap_in);
+ for (mp_uint_t i = heap->len / 2; i > 0;) {
+ heapq_heap_siftup(heap, --i);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_heapq_heapify_obj, mod_heapq_heapify);
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t mp_module_heapq_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_heapq) },
+ { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_heapq_heappush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_heappop), MP_ROM_PTR(&mod_heapq_heappop_obj) },
+ { MP_ROM_QSTR(MP_QSTR_heapify), MP_ROM_PTR(&mod_heapq_heapify_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_heapq_globals, mp_module_heapq_globals_table);
+
+const mp_obj_module_t mp_module_heapq = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_heapq_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_heapq, mp_module_heapq);
+#endif
+
+#endif // MICROPY_PY_HEAPQ
diff --git a/extmod/modjson.c b/extmod/modjson.c
new file mode 100644
index 000000000000..1772b7299886
--- /dev/null
+++ b/extmod/modjson.c
@@ -0,0 +1,386 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "py/objlist.h"
+#include "py/objstringio.h"
+#include "py/parsenum.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+
+#if MICROPY_PY_JSON
+
+#if MICROPY_PY_JSON_SEPARATORS
+
+enum {
+ DUMP_MODE_TO_STRING = 1,
+ DUMP_MODE_TO_STREAM = 2,
+};
+
+STATIC mp_obj_t mod_json_dump_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, unsigned int mode) {
+ enum { ARG_separators };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ };
+
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - mode, pos_args + mode, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_print_ext_t print_ext;
+
+ if (args[ARG_separators].u_obj == mp_const_none) {
+ print_ext.item_separator = ", ";
+ print_ext.key_separator = ": ";
+ } else {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[ARG_separators].u_obj, 2, &items);
+ print_ext.item_separator = mp_obj_str_get_str(items[0]);
+ print_ext.key_separator = mp_obj_str_get_str(items[1]);
+ }
+
+ if (mode == DUMP_MODE_TO_STRING) {
+ // dumps(obj)
+ vstr_t vstr;
+ vstr_init_print(&vstr, 8, &print_ext.base);
+ mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
+ return mp_obj_new_str_from_utf8_vstr(&vstr);
+ } else {
+ // dump(obj, stream)
+ print_ext.base.data = MP_OBJ_TO_PTR(pos_args[1]);
+ print_ext.base.print_strn = mp_stream_write_adaptor;
+ mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE);
+ mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
+ return mp_const_none;
+ }
+}
+
+STATIC mp_obj_t mod_json_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return mod_json_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STREAM);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_json_dump_obj, 2, mod_json_dump);
+
+STATIC mp_obj_t mod_json_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return mod_json_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STRING);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_json_dumps_obj, 1, mod_json_dumps);
+
+#else
+
+STATIC mp_obj_t mod_json_dump(mp_obj_t obj, mp_obj_t stream) {
+ mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
+ mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
+ mp_obj_print_helper(&print, obj, PRINT_JSON);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_json_dump_obj, mod_json_dump);
+
+STATIC mp_obj_t mod_json_dumps(mp_obj_t obj) {
+ vstr_t vstr;
+ mp_print_t print;
+ vstr_init_print(&vstr, 8, &print);
+ mp_obj_print_helper(&print, obj, PRINT_JSON);
+ return mp_obj_new_str_from_utf8_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_json_dumps_obj, mod_json_dumps);
+
+#endif
+
+// The function below implements a simple non-recursive JSON parser.
+//
+// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt
+// The parser here will parse any valid JSON and return the correct
+// corresponding Python object. It allows through a superset of JSON, since
+// it treats commas and colons as "whitespace", and doesn't care if
+// brackets/braces are correctly paired. It will raise a ValueError if the
+// input is outside it's specs.
+//
+// Most of the work is parsing the primitives (null, false, true, numbers,
+// strings). It does 1 pass over the input stream. It tries to be fast and
+// small in code size, while not using more RAM than necessary.
+
+typedef struct _json_stream_t {
+ mp_obj_t stream_obj;
+ mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
+ int errcode;
+ byte cur;
+} json_stream_t;
+
+#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker
+#define S_END(s) ((s).cur == S_EOF)
+#define S_CUR(s) ((s).cur)
+#define S_NEXT(s) (json_stream_next(&(s)))
+
+STATIC byte json_stream_next(json_stream_t *s) {
+ mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode);
+ if (s->errcode != 0) {
+ mp_raise_OSError(s->errcode);
+ }
+ if (ret == 0) {
+ s->cur = S_EOF;
+ }
+ return s->cur;
+}
+
+STATIC mp_obj_t mod_json_load(mp_obj_t stream_obj) {
+ const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);
+ json_stream_t s = {stream_obj, stream_p->read, 0, 0};
+ vstr_t vstr;
+ vstr_init(&vstr, 8);
+ mp_obj_list_t stack; // we use a list as a simple stack for nested JSON
+ stack.len = 0;
+ stack.items = NULL;
+ mp_obj_t stack_top = MP_OBJ_NULL;
+ const mp_obj_type_t *stack_top_type = NULL;
+ mp_obj_t stack_key = MP_OBJ_NULL;
+ S_NEXT(s);
+ for (;;) {
+ cont:
+ if (S_END(s)) {
+ break;
+ }
+ mp_obj_t next = MP_OBJ_NULL;
+ bool enter = false;
+ byte cur = S_CUR(s);
+ S_NEXT(s);
+ switch (cur) {
+ case ',':
+ case ':':
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ goto cont;
+ case 'n':
+ if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') {
+ S_NEXT(s);
+ next = mp_const_none;
+ } else {
+ goto fail;
+ }
+ break;
+ case 'f':
+ if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') {
+ S_NEXT(s);
+ next = mp_const_false;
+ } else {
+ goto fail;
+ }
+ break;
+ case 't':
+ if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') {
+ S_NEXT(s);
+ next = mp_const_true;
+ } else {
+ goto fail;
+ }
+ break;
+ case '"':
+ vstr_reset(&vstr);
+ for (; !S_END(s) && S_CUR(s) != '"';) {
+ byte c = S_CUR(s);
+ if (c == '\\') {
+ c = S_NEXT(s);
+ switch (c) {
+ case 'b':
+ c = 0x08;
+ break;
+ case 'f':
+ c = 0x0c;
+ break;
+ case 'n':
+ c = 0x0a;
+ break;
+ case 'r':
+ c = 0x0d;
+ break;
+ case 't':
+ c = 0x09;
+ break;
+ case 'u': {
+ mp_uint_t num = 0;
+ for (int i = 0; i < 4; i++) {
+ c = (S_NEXT(s) | 0x20) - '0';
+ if (c > 9) {
+ c -= ('a' - ('9' + 1));
+ }
+ num = (num << 4) | c;
+ }
+ vstr_add_char(&vstr, num);
+ goto str_cont;
+ }
+ }
+ }
+ vstr_add_byte(&vstr, c);
+ str_cont:
+ S_NEXT(s);
+ }
+ if (S_END(s)) {
+ goto fail;
+ }
+ S_NEXT(s);
+ next = mp_obj_new_str(vstr.buf, vstr.len);
+ break;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ bool flt = false;
+ vstr_reset(&vstr);
+ for (;;) {
+ vstr_add_byte(&vstr, cur);
+ cur = S_CUR(s);
+ if (cur == '.' || cur == 'E' || cur == 'e') {
+ flt = true;
+ } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) {
+ // pass
+ } else {
+ break;
+ }
+ S_NEXT(s);
+ }
+ if (flt) {
+ next = mp_parse_num_float(vstr.buf, vstr.len, false, NULL);
+ } else {
+ next = mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
+ }
+ break;
+ }
+ case '[':
+ next = mp_obj_new_list(0, NULL);
+ enter = true;
+ break;
+ case '{':
+ next = mp_obj_new_dict(0);
+ enter = true;
+ break;
+ case '}':
+ case ']': {
+ if (stack_top == MP_OBJ_NULL) {
+ // no object at all
+ goto fail;
+ }
+ if (stack.len == 0) {
+ // finished; compound object
+ goto success;
+ }
+ stack.len -= 1;
+ stack_top = stack.items[stack.len];
+ stack_top_type = mp_obj_get_type(stack_top);
+ goto cont;
+ }
+ default:
+ goto fail;
+ }
+ if (stack_top == MP_OBJ_NULL) {
+ stack_top = next;
+ stack_top_type = mp_obj_get_type(stack_top);
+ if (!enter) {
+ // finished; single primitive only
+ goto success;
+ }
+ } else {
+ // append to list or dict
+ if (stack_top_type == &mp_type_list) {
+ mp_obj_list_append(stack_top, next);
+ } else {
+ if (stack_key == MP_OBJ_NULL) {
+ stack_key = next;
+ if (enter) {
+ goto fail;
+ }
+ } else {
+ mp_obj_dict_store(stack_top, stack_key, next);
+ stack_key = MP_OBJ_NULL;
+ }
+ }
+ if (enter) {
+ if (stack.items == NULL) {
+ mp_obj_list_init(&stack, 1);
+ stack.items[0] = stack_top;
+ } else {
+ mp_obj_list_append(MP_OBJ_FROM_PTR(&stack), stack_top);
+ }
+ stack_top = next;
+ stack_top_type = mp_obj_get_type(stack_top);
+ }
+ }
+ }
+success:
+ // eat trailing whitespace
+ while (unichar_isspace(S_CUR(s))) {
+ S_NEXT(s);
+ }
+ if (!S_END(s)) {
+ // unexpected chars
+ goto fail;
+ }
+ if (stack_top == MP_OBJ_NULL || stack.len != 0) {
+ // not exactly 1 object
+ goto fail;
+ }
+ vstr_clear(&vstr);
+ return stack_top;
+
+fail:
+ mp_raise_ValueError(MP_ERROR_TEXT("syntax error in JSON"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_json_load_obj, mod_json_load);
+
+STATIC mp_obj_t mod_json_loads(mp_obj_t obj) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ);
+ vstr_t vstr = {bufinfo.len, bufinfo.len, (char *)bufinfo.buf, true};
+ mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
+ return mod_json_load(MP_OBJ_FROM_PTR(&sio));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_json_loads_obj, mod_json_loads);
+
+STATIC const mp_rom_map_elem_t mp_module_json_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_json) },
+ { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_json_dump_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_json_dumps_obj) },
+ { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_json_load_obj) },
+ { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_json_loads_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_json_globals, mp_module_json_globals_table);
+
+const mp_obj_module_t mp_module_json = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_json_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_json, mp_module_json);
+
+#endif // MICROPY_PY_JSON
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index f64a5a6250ba..0d4c03c68a87 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -918,7 +918,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_bind_obj, lwip_socket_bind);
STATIC mp_obj_t lwip_socket_listen(size_t n_args, const mp_obj_t *args) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]);
- mp_int_t backlog = MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT;
+ mp_int_t backlog = MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT;
if (n_args > 1) {
backlog = mp_obj_get_int(args[1]);
backlog = (backlog < 0) ? 0 : backlog;
@@ -931,9 +931,20 @@ STATIC mp_obj_t lwip_socket_listen(size_t n_args, const mp_obj_t *args) {
mp_raise_OSError(MP_EOPNOTSUPP);
}
- struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
+ struct tcp_pcb *new_pcb;
+ #if LWIP_VERSION_MACRO < 0x02000100
+ new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
+ #else
+ err_t error;
+ new_pcb = tcp_listen_with_backlog_and_err(socket->pcb.tcp, (u8_t)backlog, &error);
+ #endif
+
if (new_pcb == NULL) {
+ #if LWIP_VERSION_MACRO < 0x02000100
mp_raise_OSError(MP_ENOMEM);
+ #else
+ mp_raise_OSError(error_lookup_table[-error]);
+ #endif
}
socket->pcb.tcp = new_pcb;
@@ -1790,8 +1801,8 @@ const mp_obj_module_t mp_module_lwip = {
MP_REGISTER_MODULE(MP_QSTR_lwip, mp_module_lwip);
-// On LWIP-ports, this is the usocket module (replaces extmod/modusocket.c).
-MP_REGISTER_MODULE(MP_QSTR_usocket, mp_module_lwip);
+// On LWIP-ports, this is the socket module (replaces extmod/modsocket.c).
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_lwip);
MP_REGISTER_ROOT_POINTER(mp_obj_t lwip_slip_stream);
diff --git a/extmod/modnetwork.c b/extmod/modnetwork.c
index b698ee4cf45e..7c1b91de45d0 100644
--- a/extmod/modnetwork.c
+++ b/extmod/modnetwork.c
@@ -31,28 +31,35 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/mphal.h"
-#include "shared/netutils/netutils.h"
-#include "modnetwork.h"
#if MICROPY_PY_NETWORK
-#if MICROPY_PY_LWIP
-#include "lwip/netif.h"
-#include "lwip/timeouts.h"
-#include "lwip/dns.h"
-#include "lwip/dhcp.h"
-#include "lwip/apps/mdns.h"
-#endif
+#include "shared/netutils/netutils.h"
+#include "modnetwork.h"
-#if MICROPY_PY_NETWORK_CYW43 && MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
+#if MICROPY_PY_NETWORK_CYW43
// So that CYW43_LINK_xxx constants are available to MICROPY_PORT_NETWORK_INTERFACES.
#include "lib/cyw43-driver/src/cyw43.h"
#endif
+#ifdef MICROPY_PY_NETWORK_INCLUDEFILE
+#include MICROPY_PY_NETWORK_INCLUDEFILE
+#endif
+
/// \module network - network configuration
///
/// This module provides network drivers and routing configuration.
+char mod_network_country_code[2] = "XX";
+
+#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT
+#error "MICROPY_PY_NETWORK_HOSTNAME_DEFAULT must be set in mpconfigport.h or mpconfigboard.h"
+#endif
+
+char mod_network_hostname[MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN] = MICROPY_PY_NETWORK_HOSTNAME_DEFAULT;
+
+#ifdef MICROPY_PORT_NETWORK_INTERFACES
+
void mod_network_init(void) {
mp_obj_list_init(&MP_STATE_PORT(mod_network_nic_list), 0);
}
@@ -76,7 +83,7 @@ mp_obj_t mod_network_find_nic(const uint8_t *ip) {
for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
// TODO check IP suitability here
- // mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
+ // mod_network_nic_protocol_t *nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(nic), protocol);
return nic;
}
@@ -88,16 +95,61 @@ STATIC mp_obj_t network_route(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route);
+MP_REGISTER_ROOT_POINTER(mp_obj_list_t mod_network_nic_list);
+
+#endif // MICROPY_PORT_NETWORK_INTERFACES
+
+STATIC mp_obj_t network_country(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ return mp_obj_new_str(mod_network_country_code, 2);
+ } else {
+ size_t len;
+ const char *str = mp_obj_str_get_data(args[0], &len);
+ if (len != 2) {
+ mp_raise_ValueError(NULL);
+ }
+ mod_network_country_code[0] = str[0];
+ mod_network_country_code[1] = str[1];
+ return mp_const_none;
+ }
+}
+// TODO: Non-static to allow backwards-compatible pyb.country.
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_network_country_obj, 0, 1, network_country);
+
+STATIC mp_obj_t network_hostname(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ return mp_obj_new_str(mod_network_hostname, strlen(mod_network_hostname));
+ } else {
+ size_t len;
+ const char *str = mp_obj_str_get_data(args[0], &len);
+ if (len >= MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN) {
+ mp_raise_ValueError(NULL);
+ }
+ strcpy(mod_network_hostname, str);
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_network_hostname_obj, 0, 1, network_hostname);
+
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
- { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
+ { MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },
+ { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mod_network_hostname_obj) },
// Defined per port in mpconfigport.h
+ #ifdef MICROPY_PORT_NETWORK_INTERFACES
+ { MP_ROM_QSTR(MP_QSTR_route), MP_ROM_PTR(&network_route_obj) },
MICROPY_PORT_NETWORK_INTERFACES
+ #endif
+ // Allow a port to take mostly full control of the network module.
+ #ifdef MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE
+ #include MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE
+ #else
// Constants
{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(MOD_NETWORK_STA_IF) },
{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(MOD_NETWORK_AP_IF) },
+ #endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
@@ -109,60 +161,4 @@ const mp_obj_module_t mp_module_network = {
MP_REGISTER_MODULE(MP_QSTR_network, mp_module_network);
-/*******************************************************************************/
-// Implementations of network methods that can be used by any interface
-
-#if MICROPY_PY_LWIP
-
-mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) {
- if (n_args == 0) {
- // Get IP addresses
- const ip_addr_t *dns = dns_getserver(0);
- mp_obj_t tuple[4] = {
- netutils_format_ipv4_addr((uint8_t *)&netif->ip_addr, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&netif->netmask, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&netif->gw, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)dns, NETUTILS_BIG),
- };
- return mp_obj_new_tuple(4, tuple);
- } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) {
- // Start the DHCP client
- if (dhcp_supplied_address(netif)) {
- dhcp_renew(netif);
- } else {
- dhcp_stop(netif);
- dhcp_start(netif);
- }
-
- // Wait for DHCP to get IP address
- uint32_t start = mp_hal_ticks_ms();
- while (!dhcp_supplied_address(netif)) {
- if (mp_hal_ticks_ms() - start > 10000) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("timeout waiting for DHCP to get IP address"));
- }
- mp_hal_delay_ms(100);
- }
-
- return mp_const_none;
- } else {
- // Release and stop any existing DHCP
- dhcp_release(netif);
- dhcp_stop(netif);
- // Set static IP addresses
- mp_obj_t *items;
- mp_obj_get_array_fixed_n(args[0], 4, &items);
- netutils_parse_ipv4_addr(items[0], (uint8_t *)&netif->ip_addr, NETUTILS_BIG);
- netutils_parse_ipv4_addr(items[1], (uint8_t *)&netif->netmask, NETUTILS_BIG);
- netutils_parse_ipv4_addr(items[2], (uint8_t *)&netif->gw, NETUTILS_BIG);
- ip_addr_t dns;
- netutils_parse_ipv4_addr(items[3], (uint8_t *)&dns, NETUTILS_BIG);
- dns_setserver(0, &dns);
- return mp_const_none;
- }
-}
-
-#endif
-
-MP_REGISTER_ROOT_POINTER(mp_obj_list_t mod_network_nic_list);
-
#endif // MICROPY_PY_NETWORK
diff --git a/extmod/modnetwork.h b/extmod/modnetwork.h
index 55ee4eb4d3e3..4786596e9b93 100644
--- a/extmod/modnetwork.h
+++ b/extmod/modnetwork.h
@@ -52,19 +52,24 @@
#define MOD_NETWORK_SS_CONNECTED (2)
#define MOD_NETWORK_SS_CLOSED (3)
+extern char mod_network_country_code[2];
+
+#ifndef MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN
+#define MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN (16)
+#endif
+
+extern char mod_network_hostname[MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN];
+
#if MICROPY_PY_LWIP
struct netif;
void mod_network_lwip_init(void);
void mod_network_lwip_poll_wrapper(uint32_t ticks_ms);
mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args);
-#else
+#elif defined(MICROPY_PORT_NETWORK_INTERFACES)
struct _mod_network_socket_obj_t;
-typedef struct _mod_network_nic_type_t {
- // Ensure that this struct is big enough to hold any type size.
- mp_obj_full_type_t base;
-
+typedef struct _mod_network_nic_protocol_t {
// API for non-socket operations
int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
@@ -82,12 +87,12 @@ typedef struct _mod_network_nic_type_t {
int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno);
int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
-} mod_network_nic_type_t;
+} mod_network_nic_protocol_t;
typedef struct _mod_network_socket_obj_t {
mp_obj_base_t base;
mp_obj_t nic;
- mod_network_nic_type_t *nic_type;
+ mod_network_nic_protocol_t *nic_protocol;
uint32_t domain : 5;
uint32_t type : 5;
uint32_t proto : 5;
@@ -96,17 +101,19 @@ typedef struct _mod_network_socket_obj_t {
int32_t timeout;
mp_obj_t callback;
int32_t state : 8;
- #if MICROPY_PY_USOCKET_EXTENDED_STATE
+ #if MICROPY_PY_SOCKET_EXTENDED_STATE
// Extended socket state for NICs/ports that need it.
void *_private;
#endif
} mod_network_socket_obj_t;
-#endif // MICROPY_PY_LWIP
+#endif // MICROPY_PY_LWIP / MICROPY_PORT_NETWORK_INTERFACES
+#ifdef MICROPY_PORT_NETWORK_INTERFACES
void mod_network_init(void);
void mod_network_deinit(void);
void mod_network_register_nic(mp_obj_t nic);
mp_obj_t mod_network_find_nic(const uint8_t *ip);
+#endif
#endif // MICROPY_INCLUDED_MODNETWORK_H
diff --git a/extmod/modos.c b/extmod/modos.c
new file mode 100644
index 000000000000..6df49d7f8497
--- /dev/null
+++ b/extmod/modos.c
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2022 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objstr.h"
+#include "py/runtime.h"
+
+#if MICROPY_PY_OS
+
+#include "extmod/misc.h"
+#include "extmod/vfs.h"
+
+#if MICROPY_VFS_FAT
+#include "extmod/vfs_fat.h"
+#if MICROPY_PY_OS_SYNC
+#include "lib/oofatfs/ff.h"
+#include "lib/oofatfs/diskio.h"
+#endif
+#endif
+
+#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
+#include "extmod/vfs_lfs.h"
+#endif
+
+#if MICROPY_VFS_POSIX
+#include "extmod/vfs_posix.h"
+#endif
+
+#if MICROPY_PY_OS_UNAME
+#include "genhdr/mpversion.h"
+#endif
+
+#ifdef MICROPY_PY_OS_INCLUDEFILE
+#include MICROPY_PY_OS_INCLUDEFILE
+#endif
+
+#ifdef MICROPY_BUILD_TYPE
+#define MICROPY_BUILD_TYPE_PAREN " (" MICROPY_BUILD_TYPE ")"
+#else
+#define MICROPY_BUILD_TYPE_PAREN
+#endif
+
+#if MICROPY_PY_OS_SYNC
+// sync()
+// Sync all filesystems.
+STATIC mp_obj_t mp_os_sync(void) {
+ #if MICROPY_VFS_FAT
+ for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
+ // this assumes that vfs->obj is fs_user_mount_t with block device functions
+ disk_ioctl(MP_OBJ_TO_PTR(vfs->obj), CTRL_SYNC, NULL);
+ }
+ #endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_os_sync_obj, mp_os_sync);
+#endif
+
+#if MICROPY_PY_OS_UNAME
+
+#if MICROPY_PY_OS_UNAME_RELEASE_DYNAMIC
+#define CONST_RELEASE
+#else
+#define CONST_RELEASE const
+#endif
+
+STATIC const qstr mp_os_uname_info_fields[] = {
+ MP_QSTR_sysname,
+ MP_QSTR_nodename,
+ MP_QSTR_release,
+ MP_QSTR_version,
+ MP_QSTR_machine
+};
+STATIC const MP_DEFINE_STR_OBJ(mp_os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(mp_os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC CONST_RELEASE MP_DEFINE_STR_OBJ(mp_os_uname_info_release_obj, MICROPY_VERSION_STRING);
+STATIC const MP_DEFINE_STR_OBJ(mp_os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE MICROPY_BUILD_TYPE_PAREN);
+STATIC const MP_DEFINE_STR_OBJ(mp_os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
+
+STATIC MP_DEFINE_ATTRTUPLE(
+ mp_os_uname_info_obj,
+ mp_os_uname_info_fields,
+ 5,
+ MP_ROM_PTR(&mp_os_uname_info_sysname_obj),
+ MP_ROM_PTR(&mp_os_uname_info_nodename_obj),
+ MP_ROM_PTR(&mp_os_uname_info_release_obj),
+ MP_ROM_PTR(&mp_os_uname_info_version_obj),
+ MP_ROM_PTR(&mp_os_uname_info_machine_obj)
+ );
+
+STATIC mp_obj_t mp_os_uname(void) {
+ #if MICROPY_PY_OS_UNAME_RELEASE_DYNAMIC
+ const char *release = mp_os_uname_release();
+ mp_os_uname_info_release_obj.len = strlen(release);
+ mp_os_uname_info_release_obj.data = (const byte *)release;
+ #endif
+ return MP_OBJ_FROM_PTR(&mp_os_uname_info_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_os_uname_obj, mp_os_uname);
+
+#endif
+
+STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
+
+ #if MICROPY_PY_OS_GETENV_PUTENV_UNSETENV
+ { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mp_os_getenv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_putenv), MP_ROM_PTR(&mp_os_putenv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unsetenv), MP_ROM_PTR(&mp_os_unsetenv_obj) },
+ #endif
+ #if MICROPY_PY_OS_SEP
+ { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
+ #endif
+ #if MICROPY_PY_OS_SYNC
+ { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mp_os_sync_obj) },
+ #endif
+ #if MICROPY_PY_OS_SYSTEM
+ { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mp_os_system_obj) },
+ #endif
+ #if MICROPY_PY_OS_UNAME
+ { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&mp_os_uname_obj) },
+ #endif
+ #if MICROPY_PY_OS_URANDOM
+ { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_os_urandom_obj) },
+ #endif
+
+ #if MICROPY_VFS
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
+ #endif
+
+ // The following are MicroPython extensions.
+
+ #if MICROPY_PY_OS_DUPTERM
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_os_dupterm_obj) },
+ #endif
+ #if MICROPY_PY_OS_DUPTERM_NOTIFY
+ { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&mp_os_dupterm_notify_obj) },
+ #endif
+ #if MICROPY_PY_OS_ERRNO
+ { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_os_errno_obj) },
+ #endif
+
+ #if MICROPY_VFS
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ #if MICROPY_VFS_FAT
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ #endif
+ #if MICROPY_VFS_LFS1
+ { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
+ #endif
+ #if MICROPY_VFS_LFS2
+ { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
+ #endif
+ #if MICROPY_VFS_POSIX
+ { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) },
+ #endif
+ #endif
+};
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t mp_module_os = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&os_module_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_os, mp_module_os);
+
+#endif // MICROPY_PY_OS
diff --git a/extmod/modplatform.c b/extmod/modplatform.c
new file mode 100644
index 000000000000..73846f946d0e
--- /dev/null
+++ b/extmod/modplatform.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "py/mphal.h"
+#include "extmod/modplatform.h"
+#include "genhdr/mpversion.h"
+
+#if MICROPY_PY_PLATFORM
+
+// platform - Access to underlying platform's identifying data
+
+STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, MICROPY_PLATFORM_SYSTEM "-" \
+ MICROPY_VERSION_STRING "-" MICROPY_PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" \
+ MICROPY_PLATFORM_LIBC_LIB "" MICROPY_PLATFORM_LIBC_VER);
+STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, MICROPY_PLATFORM_COMPILER);
+STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, MICROPY_PLATFORM_LIBC_LIB);
+STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, MICROPY_PLATFORM_LIBC_VER);
+STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
+ {&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
+};
+
+STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return MP_OBJ_FROM_PTR(&info_platform_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
+
+STATIC mp_obj_t platform_python_compiler(void) {
+ return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
+
+STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
+
+STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_platform) },
+ { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
+ { MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
+ { MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
+
+const mp_obj_module_t mp_module_platform = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&modplatform_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_platform, mp_module_platform);
+
+#endif // MICROPY_PY_PLATFORM
diff --git a/extmod/modplatform.h b/extmod/modplatform.h
new file mode 100644
index 000000000000..56a50e53c544
--- /dev/null
+++ b/extmod/modplatform.h
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MODPLATFORM_H
+#define MICROPY_INCLUDED_MODPLATFORM_H
+
+#include "py/misc.h" // For MP_STRINGIFY.
+#include "py/mpconfig.h"
+
+// Preprocessor directives identifying the platform.
+// The platform module itself is guarded by MICROPY_PY_PLATFORM, see the
+// .c file, but these are made available because they're generally usable.
+// TODO: Add more architectures, compilers and libraries.
+// See: https://sourceforge.net/p/predef/wiki/Home/
+
+#if defined(__ARM_ARCH)
+#define MICROPY_PLATFORM_ARCH "arm"
+#elif defined(__x86_64__) || defined(_M_X64)
+#define MICROPY_PLATFORM_ARCH "x86_64"
+#elif defined(__i386__) || defined(_M_IX86)
+#define MICROPY_PLATFORM_ARCH "x86"
+#elif defined(__xtensa__)
+#define MICROPY_PLATFORM_ARCH "xtensa"
+#elif defined(__riscv)
+#define MICROPY_PLATFORM_ARCH "riscv"
+#else
+#define MICROPY_PLATFORM_ARCH ""
+#endif
+
+#if defined(__GNUC__)
+#define MICROPY_PLATFORM_COMPILER \
+ "GCC " \
+ MP_STRINGIFY(__GNUC__) "." \
+ MP_STRINGIFY(__GNUC_MINOR__) "." \
+ MP_STRINGIFY(__GNUC_PATCHLEVEL__)
+#elif defined(__ARMCC_VERSION)
+#define MICROPY_PLATFORM_COMPILER \
+ "ARMCC " \
+ MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
+ MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
+ MP_STRINGIFY((__ARMCC_VERSION % 10000))
+#elif defined(_MSC_VER)
+#if defined(_WIN64)
+#define MICROPY_PLATFORM_COMPILER_BITS "64 bit"
+#elif defined(_M_IX86)
+#define MICROPY_PLATFORM_COMPILER_BITS "32 bit"
+#else
+#define MICROPY_PLATFORM_COMPILER_BITS ""
+#endif
+#define MICROPY_PLATFORM_COMPILER \
+ "MSC v." MP_STRINGIFY(_MSC_VER) " " MICROPY_PLATFORM_COMPILER_BITS
+#else
+#define MICROPY_PLATFORM_COMPILER ""
+#endif
+
+#if defined(__GLIBC__)
+#define MICROPY_PLATFORM_LIBC_LIB "glibc"
+#define MICROPY_PLATFORM_LIBC_VER \
+ MP_STRINGIFY(__GLIBC__) "." \
+ MP_STRINGIFY(__GLIBC_MINOR__)
+#elif defined(__NEWLIB__)
+#define MICROPY_PLATFORM_LIBC_LIB "newlib"
+#define MICROPY_PLATFORM_LIBC_VER _NEWLIB_VERSION
+#else
+#define MICROPY_PLATFORM_LIBC_LIB ""
+#define MICROPY_PLATFORM_LIBC_VER ""
+#endif
+
+#if defined(__linux)
+#define MICROPY_PLATFORM_SYSTEM "Linux"
+#elif defined(__unix__)
+#define MICROPY_PLATFORM_SYSTEM "Unix"
+#elif defined(__CYGWIN__)
+#define MICROPY_PLATFORM_SYSTEM "Cygwin"
+#elif defined(_WIN32)
+#define MICROPY_PLATFORM_SYSTEM "Windows"
+#else
+#define MICROPY_PLATFORM_SYSTEM "MicroPython"
+#endif
+
+#ifndef MICROPY_PLATFORM_VERSION
+#define MICROPY_PLATFORM_VERSION ""
+#endif
+
+#endif // MICROPY_INCLUDED_MODPLATFORM_H
diff --git a/extmod/modrandom.c b/extmod/modrandom.c
new file mode 100644
index 000000000000..e65f31488bfe
--- /dev/null
+++ b/extmod/modrandom.c
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/runtime.h"
+
+#if MICROPY_PY_RANDOM
+
+// Work out if the seed will be set on import or not.
+#if MICROPY_MODULE_BUILTIN_INIT && defined(MICROPY_PY_RANDOM_SEED_INIT_FUNC)
+#define SEED_ON_IMPORT (1)
+#else
+#define SEED_ON_IMPORT (0)
+#endif
+
+// Yasmarang random number generator
+// by Ilya Levin
+// http://www.literatecode.com/yasmarang
+// Public Domain
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+#if SEED_ON_IMPORT
+// If the state is seeded on import then keep these variables in the BSS.
+STATIC uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
+STATIC uint8_t yasmarang_dat;
+#else
+// Without seed-on-import these variables must be initialised via the data section.
+STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
+STATIC uint8_t yasmarang_dat = 0;
+#endif
+#endif
+
+STATIC uint32_t yasmarang(void) {
+ yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;
+ yasmarang_pad = (yasmarang_pad << 3) + (yasmarang_pad >> 29);
+ yasmarang_n = yasmarang_pad | 2;
+ yasmarang_d ^= (yasmarang_pad << 31) + (yasmarang_pad >> 1);
+ yasmarang_dat ^= (char)yasmarang_pad ^ (yasmarang_d >> 8) ^ 1;
+
+ return yasmarang_pad ^ (yasmarang_d << 5) ^ (yasmarang_pad >> 18) ^ (yasmarang_dat << 1);
+} /* yasmarang */
+
+// End of Yasmarang
+
+#if MICROPY_PY_RANDOM_EXTRA_FUNCS
+
+// returns an unsigned integer below the given argument
+// n must not be zero
+STATIC uint32_t yasmarang_randbelow(uint32_t n) {
+ uint32_t mask = 1;
+ while ((n & mask) < n) {
+ mask = (mask << 1) | 1;
+ }
+ uint32_t r;
+ do {
+ r = yasmarang() & mask;
+ } while (r >= n);
+ return r;
+}
+
+#endif
+
+STATIC mp_obj_t mod_random_getrandbits(mp_obj_t num_in) {
+ int n = mp_obj_get_int(num_in);
+ if (n > 32 || n < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
+ }
+ if (n == 0) {
+ return MP_OBJ_NEW_SMALL_INT(0);
+ }
+ uint32_t mask = ~0;
+ // Beware of C undefined behavior when shifting by >= than bit size
+ mask >>= (32 - n);
+ return mp_obj_new_int_from_uint(yasmarang() & mask);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_getrandbits_obj, mod_random_getrandbits);
+
+STATIC mp_obj_t mod_random_seed(size_t n_args, const mp_obj_t *args) {
+ mp_uint_t seed;
+ if (n_args == 0 || args[0] == mp_const_none) {
+ #ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC
+ seed = MICROPY_PY_RANDOM_SEED_INIT_FUNC;
+ #else
+ mp_raise_ValueError(MP_ERROR_TEXT("no default seed"));
+ #endif
+ } else {
+ seed = mp_obj_get_int_truncated(args[0]);
+ }
+ yasmarang_pad = seed;
+ yasmarang_n = 69;
+ yasmarang_d = 233;
+ yasmarang_dat = 0;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_random_seed_obj, 0, 1, mod_random_seed);
+
+#if MICROPY_PY_RANDOM_EXTRA_FUNCS
+
+STATIC mp_obj_t mod_random_randrange(size_t n_args, const mp_obj_t *args) {
+ mp_int_t start = mp_obj_get_int(args[0]);
+ if (n_args == 1) {
+ // range(stop)
+ if (start > 0) {
+ return mp_obj_new_int(yasmarang_randbelow(start));
+ } else {
+ goto error;
+ }
+ } else {
+ mp_int_t stop = mp_obj_get_int(args[1]);
+ if (n_args == 2) {
+ // range(start, stop)
+ if (start < stop) {
+ return mp_obj_new_int(start + yasmarang_randbelow(stop - start));
+ } else {
+ goto error;
+ }
+ } else {
+ // range(start, stop, step)
+ mp_int_t step = mp_obj_get_int(args[2]);
+ mp_int_t n;
+ if (step > 0) {
+ n = (stop - start + step - 1) / step;
+ } else if (step < 0) {
+ n = (stop - start + step + 1) / step;
+ } else {
+ goto error;
+ }
+ if (n > 0) {
+ return mp_obj_new_int(start + step * yasmarang_randbelow(n));
+ } else {
+ goto error;
+ }
+ }
+ }
+
+error:
+ mp_raise_ValueError(NULL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_random_randrange_obj, 1, 3, mod_random_randrange);
+
+STATIC mp_obj_t mod_random_randint(mp_obj_t a_in, mp_obj_t b_in) {
+ mp_int_t a = mp_obj_get_int(a_in);
+ mp_int_t b = mp_obj_get_int(b_in);
+ if (a <= b) {
+ return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1));
+ } else {
+ mp_raise_ValueError(NULL);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_randint_obj, mod_random_randint);
+
+STATIC mp_obj_t mod_random_choice(mp_obj_t seq) {
+ mp_int_t len = mp_obj_get_int(mp_obj_len(seq));
+ if (len > 0) {
+ return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
+ } else {
+ mp_raise_type(&mp_type_IndexError);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_choice_obj, mod_random_choice);
+
+#if MICROPY_PY_BUILTINS_FLOAT
+
+// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
+STATIC mp_float_t yasmarang_float(void) {
+ mp_float_union_t u;
+ u.p.sgn = 0;
+ u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
+ if (MP_FLOAT_FRAC_BITS <= 32) {
+ u.p.frc = yasmarang();
+ } else {
+ u.p.frc = ((uint64_t)yasmarang() << 32) | (uint64_t)yasmarang();
+ }
+ return u.f - 1;
+}
+
+STATIC mp_obj_t mod_random_random(void) {
+ return mp_obj_new_float(yasmarang_float());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_random_random_obj, mod_random_random);
+
+STATIC mp_obj_t mod_random_uniform(mp_obj_t a_in, mp_obj_t b_in) {
+ mp_float_t a = mp_obj_get_float(a_in);
+ mp_float_t b = mp_obj_get_float(b_in);
+ return mp_obj_new_float(a + (b - a) * yasmarang_float());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_random_uniform_obj, mod_random_uniform);
+
+#endif
+
+#endif // MICROPY_PY_RANDOM_EXTRA_FUNCS
+
+#if SEED_ON_IMPORT
+STATIC mp_obj_t mod_random___init__(void) {
+ // This module may be imported by more than one name so need to ensure
+ // that it's only ever seeded once.
+ static bool seeded = false;
+ if (!seeded) {
+ seeded = true;
+ mod_random_seed(0, NULL);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_random___init___obj, mod_random___init__);
+#endif
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t mp_module_random_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) },
+ #if SEED_ON_IMPORT
+ { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_random___init___obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_random_getrandbits_obj) },
+ { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_random_seed_obj) },
+ #if MICROPY_PY_RANDOM_EXTRA_FUNCS
+ { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_random_randrange_obj) },
+ { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_random_randint_obj) },
+ { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_random_choice_obj) },
+ #if MICROPY_PY_BUILTINS_FLOAT
+ { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_random_random_obj) },
+ { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_random_uniform_obj) },
+ #endif
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_random_globals, mp_module_random_globals_table);
+
+const mp_obj_module_t mp_module_random = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_random_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_random, mp_module_random);
+#endif
+
+#endif // MICROPY_PY_RANDOM
diff --git a/extmod/modre.c b/extmod/modre.c
new file mode 100644
index 000000000000..7f00b1c23c4a
--- /dev/null
+++ b/extmod/modre.c
@@ -0,0 +1,492 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/binary.h"
+#include "py/objstr.h"
+#include "py/stackctrl.h"
+
+#if MICROPY_PY_BUILTINS_STR_UNICODE
+#include "py/unicode.h"
+#endif
+
+#if MICROPY_PY_RE
+
+#define re1_5_stack_chk() MP_STACK_CHECK()
+
+#include "lib/re1.5/re1.5.h"
+
+#define FLAG_DEBUG 0x1000
+
+typedef struct _mp_obj_re_t {
+ mp_obj_base_t base;
+ ByteProg re;
+} mp_obj_re_t;
+
+typedef struct _mp_obj_match_t {
+ mp_obj_base_t base;
+ int num_matches;
+ mp_obj_t str;
+ const char *caps[0];
+} mp_obj_match_t;
+
+STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args);
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_obj_type_t re_type;
+#endif
+
+STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ (void)kind;
+ mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "", self->num_matches);
+}
+
+STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
+ mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_int_t no = mp_obj_get_int(no_in);
+ if (no < 0 || no >= self->num_matches) {
+ mp_raise_type_arg(&mp_type_IndexError, no_in);
+ }
+
+ const char *start = self->caps[no * 2];
+ if (start == NULL) {
+ // no match for this group
+ return mp_const_none;
+ }
+ return mp_obj_new_str_of_type(mp_obj_get_type(self->str),
+ (const byte *)start, self->caps[no * 2 + 1] - start);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);
+
+#if MICROPY_PY_RE_MATCH_GROUPS
+
+STATIC mp_obj_t match_groups(mp_obj_t self_in) {
+ mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->num_matches <= 1) {
+ return mp_const_empty_tuple;
+ }
+ mp_obj_tuple_t *groups = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->num_matches - 1, NULL));
+ for (int i = 1; i < self->num_matches; ++i) {
+ groups->items[i - 1] = match_group(self_in, MP_OBJ_NEW_SMALL_INT(i));
+ }
+ return MP_OBJ_FROM_PTR(groups);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups);
+
+#endif
+
+#if MICROPY_PY_RE_MATCH_SPAN_START_END
+
+STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) {
+ mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ mp_int_t no = 0;
+ if (n_args == 2) {
+ no = mp_obj_get_int(args[1]);
+ if (no < 0 || no >= self->num_matches) {
+ mp_raise_type_arg(&mp_type_IndexError, args[1]);
+ }
+ }
+
+ mp_int_t s = -1;
+ mp_int_t e = -1;
+ const char *start = self->caps[no * 2];
+ if (start != NULL) {
+ // have a match for this group
+ const char *begin = mp_obj_str_get_str(self->str);
+ s = start - begin;
+ e = self->caps[no * 2 + 1] - begin;
+ }
+
+ #if MICROPY_PY_BUILTINS_STR_UNICODE
+ if (mp_obj_get_type(self->str) == &mp_type_str) {
+ const byte *begin = (const byte *)mp_obj_str_get_str(self->str);
+ if (s != -1) {
+ s = utf8_ptr_to_index(begin, begin + s);
+ }
+ if (e != -1) {
+ e = utf8_ptr_to_index(begin, begin + e);
+ }
+ }
+ #endif
+
+ span[0] = mp_obj_new_int(s);
+ span[1] = mp_obj_new_int(e);
+}
+
+STATIC mp_obj_t match_span(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t span[2];
+ match_span_helper(n_args, args, span);
+ return mp_obj_new_tuple(2, span);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span);
+
+STATIC mp_obj_t match_start(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t span[2];
+ match_span_helper(n_args, args, span);
+ return span[0];
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start);
+
+STATIC mp_obj_t match_end(size_t n_args, const mp_obj_t *args) {
+ mp_obj_t span[2];
+ match_span_helper(n_args, args, span);
+ return span[1];
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end);
+
+#endif
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t match_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },
+ #if MICROPY_PY_RE_MATCH_GROUPS
+ { MP_ROM_QSTR(MP_QSTR_groups), MP_ROM_PTR(&match_groups_obj) },
+ #endif
+ #if MICROPY_PY_RE_MATCH_SPAN_START_END
+ { MP_ROM_QSTR(MP_QSTR_span), MP_ROM_PTR(&match_span_obj) },
+ { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&match_start_obj) },
+ { MP_ROM_QSTR(MP_QSTR_end), MP_ROM_PTR(&match_end_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ match_type,
+ MP_QSTR_match,
+ MP_TYPE_FLAG_NONE,
+ print, match_print,
+ locals_dict, &match_locals_dict
+ );
+#endif
+
+STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ (void)kind;
+ mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "", self);
+}
+
+STATIC mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
+ (void)n_args;
+ mp_obj_re_t *self;
+ if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
+ self = MP_OBJ_TO_PTR(args[0]);
+ } else {
+ self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
+ }
+ Subject subj;
+ size_t len;
+ subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
+ subj.end = subj.begin + len;
+ int caps_num = (self->re.sub + 1) * 2;
+ mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char *, caps_num);
+ // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
+ memset((char *)match->caps, 0, caps_num * sizeof(char *));
+ int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
+ if (res == 0) {
+ m_del_var(mp_obj_match_t, char *, caps_num, match);
+ return mp_const_none;
+ }
+
+ match->base.type = (mp_obj_type_t *)&match_type;
+ match->num_matches = caps_num / 2; // caps_num counts start and end pointers
+ match->str = args[1];
+ return MP_OBJ_FROM_PTR(match);
+}
+
+STATIC mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {
+ return re_exec(true, n_args, args);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
+
+STATIC mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {
+ return re_exec(false, n_args, args);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
+
+STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
+ mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
+ Subject subj;
+ size_t len;
+ const mp_obj_type_t *str_type = mp_obj_get_type(args[1]);
+ subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
+ subj.end = subj.begin + len;
+ int caps_num = (self->re.sub + 1) * 2;
+
+ int maxsplit = 0;
+ if (n_args > 2) {
+ maxsplit = mp_obj_get_int(args[2]);
+ }
+
+ mp_obj_t retval = mp_obj_new_list(0, NULL);
+ const char **caps = mp_local_alloc(caps_num * sizeof(char *));
+ while (true) {
+ // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
+ memset((char **)caps, 0, caps_num * sizeof(char *));
+ int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
+
+ // if we didn't have a match, or had an empty match, it's time to stop
+ if (!res || caps[0] == caps[1]) {
+ break;
+ }
+
+ mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
+ mp_obj_list_append(retval, s);
+ if (self->re.sub > 0) {
+ mp_raise_NotImplementedError(MP_ERROR_TEXT("splitting with sub-captures"));
+ }
+ subj.begin = caps[1];
+ if (maxsplit > 0 && --maxsplit == 0) {
+ break;
+ }
+ }
+ // cast is a workaround for a bug in msvc (see above)
+ mp_local_free((char **)caps);
+
+ mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, subj.end - subj.begin);
+ mp_obj_list_append(retval, s);
+ return retval;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
+
+#if MICROPY_PY_RE_SUB
+
+STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
+ mp_obj_re_t *self;
+ if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
+ self = MP_OBJ_TO_PTR(args[0]);
+ } else {
+ self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
+ }
+ mp_obj_t replace = args[1];
+ mp_obj_t where = args[2];
+ mp_int_t count = 0;
+ if (n_args > 3) {
+ count = mp_obj_get_int(args[3]);
+ // Note: flags are currently ignored
+ }
+
+ size_t where_len;
+ const char *where_str = mp_obj_str_get_data(where, &where_len);
+ Subject subj;
+ subj.begin_line = subj.begin = where_str;
+ subj.end = subj.begin + where_len;
+ int caps_num = (self->re.sub + 1) * 2;
+
+ vstr_t vstr_return;
+ vstr_return.buf = NULL; // We'll init the vstr after the first match
+ mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char *));
+ match->base.type = (mp_obj_type_t *)&match_type;
+ match->num_matches = caps_num / 2; // caps_num counts start and end pointers
+ match->str = where;
+
+ for (;;) {
+ // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
+ memset((char *)match->caps, 0, caps_num * sizeof(char *));
+ int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false);
+
+ // If we didn't have a match, or had an empty match, it's time to stop
+ if (!res || match->caps[0] == match->caps[1]) {
+ break;
+ }
+
+ // Initialise the vstr if it's not already
+ if (vstr_return.buf == NULL) {
+ vstr_init(&vstr_return, match->caps[0] - subj.begin);
+ }
+
+ // Add pre-match string
+ vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin);
+
+ // Get replacement string
+ const char *repl = mp_obj_str_get_str((mp_obj_is_callable(replace) ? mp_call_function_1(replace, MP_OBJ_FROM_PTR(match)) : replace));
+
+ // Append replacement string to result, substituting any regex groups
+ while (*repl != '\0') {
+ if (*repl == '\\') {
+ ++repl;
+ bool is_g_format = false;
+ if (*repl == 'g' && repl[1] == '<') {
+ // Group specified with syntax "\g"
+ repl += 2;
+ is_g_format = true;
+ }
+
+ if ('0' <= *repl && *repl <= '9') {
+ // Group specified with syntax "\g" or "\number"
+ unsigned int match_no = 0;
+ do {
+ match_no = match_no * 10 + (*repl++ - '0');
+ } while ('0' <= *repl && *repl <= '9');
+ if (is_g_format && *repl == '>') {
+ ++repl;
+ }
+
+ if (match_no >= (unsigned int)match->num_matches) {
+ mp_raise_type_arg(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
+ }
+
+ const char *start_match = match->caps[match_no * 2];
+ if (start_match != NULL) {
+ // Add the substring matched by group
+ const char *end_match = match->caps[match_no * 2 + 1];
+ vstr_add_strn(&vstr_return, start_match, end_match - start_match);
+ }
+ } else if (*repl == '\\') {
+ // Add the \ character
+ vstr_add_byte(&vstr_return, *repl++);
+ }
+ } else {
+ // Just add the current byte from the replacement string
+ vstr_add_byte(&vstr_return, *repl++);
+ }
+ }
+
+ // Move start pointer to end of last match
+ subj.begin = match->caps[1];
+
+ // Stop substitutions if count was given and gets to 0
+ if (count > 0 && --count == 0) {
+ break;
+ }
+ }
+
+ mp_local_free(match);
+
+ if (vstr_return.buf == NULL) {
+ // Optimisation for case of no substitutions
+ return where;
+ }
+
+ // Add post-match string
+ vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin);
+
+ if (mp_obj_get_type(where) == &mp_type_str) {
+ return mp_obj_new_str_from_utf8_vstr(&vstr_return);
+ } else {
+ return mp_obj_new_bytes_from_vstr(&vstr_return);
+ }
+}
+
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
+
+#endif
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t re_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
+ { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
+ { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },
+ #if MICROPY_PY_RE_SUB
+ { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ re_type,
+ MP_QSTR_re,
+ MP_TYPE_FLAG_NONE,
+ print, re_print,
+ locals_dict, &re_locals_dict
+ );
+#endif
+
+STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ const char *re_str = mp_obj_str_get_str(args[0]);
+ int size = re1_5_sizecode(re_str);
+ if (size == -1) {
+ goto error;
+ }
+ mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, char, size, (mp_obj_type_t *)&re_type);
+ #if MICROPY_PY_RE_DEBUG
+ int flags = 0;
+ if (n_args > 1) {
+ flags = mp_obj_get_int(args[1]);
+ }
+ #endif
+ int error = re1_5_compilecode(&o->re, re_str);
+ if (error != 0) {
+ error:
+ mp_raise_ValueError(MP_ERROR_TEXT("error in regex"));
+ }
+ #if MICROPY_PY_RE_DEBUG
+ if (flags & FLAG_DEBUG) {
+ re1_5_dumpcode(&o->re);
+ }
+ #endif
+ return MP_OBJ_FROM_PTR(o);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
+
+#if !MICROPY_ENABLE_DYNRUNTIME
+STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_re) },
+ { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
+ { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
+ { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
+ #if MICROPY_PY_RE_SUB
+ { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
+ #endif
+ #if MICROPY_PY_RE_DEBUG
+ { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
+ #endif
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
+
+const mp_obj_module_t mp_module_re = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_re_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_re, mp_module_re);
+#endif
+
+// Source files #include'd here to make sure they're compiled in
+// only if module is enabled by config setting.
+
+#define re1_5_fatal(x) assert(!x)
+
+#include "lib/re1.5/compilecode.c"
+#include "lib/re1.5/recursiveloop.c"
+#include "lib/re1.5/charclass.c"
+
+#if MICROPY_PY_RE_DEBUG
+// Make sure the output print statements go to the same output as other Python output.
+#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
+#include "lib/re1.5/dumpcode.c"
+#undef printf
+#endif
+
+#endif // MICROPY_PY_RE
diff --git a/extmod/modselect.c b/extmod/modselect.c
new file mode 100644
index 000000000000..3d7ccbd99558
--- /dev/null
+++ b/extmod/modselect.c
@@ -0,0 +1,378 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ * Copyright (c) 2015-2017 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpconfig.h"
+#if MICROPY_PY_SELECT
+
+#include
+
+#include "py/runtime.h"
+#include "py/obj.h"
+#include "py/objlist.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+
+// Flags for poll()
+#define FLAG_ONESHOT (1)
+
+typedef struct _poll_obj_t {
+ mp_obj_t obj;
+ mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
+ mp_uint_t flags;
+ mp_uint_t flags_ret;
+} poll_obj_t;
+
+STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {
+ for (mp_uint_t i = 0; i < obj_len; i++) {
+ mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ if (elem->value == MP_OBJ_NULL) {
+ // object not found; get its ioctl and add it to the poll list
+ const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
+ poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
+ poll_obj->obj = obj[i];
+ poll_obj->ioctl = stream_p->ioctl;
+ poll_obj->flags = flags;
+ poll_obj->flags_ret = 0;
+ elem->value = MP_OBJ_FROM_PTR(poll_obj);
+ } else {
+ // object exists; update its flags
+ if (or_flags) {
+ ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags |= flags;
+ } else {
+ ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = flags;
+ }
+ }
+ }
+}
+
+// poll each object in the map
+STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
+ mp_uint_t n_ready = 0;
+ for (mp_uint_t i = 0; i < poll_map->alloc; ++i) {
+ if (!mp_map_slot_is_filled(poll_map, i)) {
+ continue;
+ }
+
+ poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value);
+ int errcode;
+ mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode);
+ poll_obj->flags_ret = ret;
+
+ if (ret == -1) {
+ // error doing ioctl
+ mp_raise_OSError(errcode);
+ }
+
+ if (ret != 0) {
+ // object is ready
+ n_ready += 1;
+ if (rwx_num != NULL) {
+ if (ret & MP_STREAM_POLL_RD) {
+ rwx_num[0] += 1;
+ }
+ if (ret & MP_STREAM_POLL_WR) {
+ rwx_num[1] += 1;
+ }
+ if ((ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
+ rwx_num[2] += 1;
+ }
+ }
+ }
+ }
+ return n_ready;
+}
+
+#if MICROPY_PY_SELECT_SELECT
+// select(rlist, wlist, xlist[, timeout])
+STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
+ // get array data from tuple/list arguments
+ size_t rwx_len[3];
+ mp_obj_t *r_array, *w_array, *x_array;
+ mp_obj_get_array(args[0], &rwx_len[0], &r_array);
+ mp_obj_get_array(args[1], &rwx_len[1], &w_array);
+ mp_obj_get_array(args[2], &rwx_len[2], &x_array);
+
+ // get timeout
+ mp_uint_t timeout = -1;
+ if (n_args == 4) {
+ if (args[3] != mp_const_none) {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ float timeout_f = mp_obj_get_float_to_f(args[3]);
+ if (timeout_f >= 0) {
+ timeout = (mp_uint_t)(timeout_f * 1000);
+ }
+ #else
+ timeout = mp_obj_get_int(args[3]) * 1000;
+ #endif
+ }
+ }
+
+ // merge separate lists and get the ioctl function for each object
+ mp_map_t poll_map;
+ mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]);
+ poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);
+ poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);
+ poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);
+
+ mp_uint_t start_tick = mp_hal_ticks_ms();
+ rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
+ for (;;) {
+ // poll the objects
+ mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len);
+
+ if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
+ // one or more objects are ready, or we had a timeout
+ mp_obj_t list_array[3];
+ list_array[0] = mp_obj_new_list(rwx_len[0], NULL);
+ list_array[1] = mp_obj_new_list(rwx_len[1], NULL);
+ list_array[2] = mp_obj_new_list(rwx_len[2], NULL);
+ rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
+ for (mp_uint_t i = 0; i < poll_map.alloc; ++i) {
+ if (!mp_map_slot_is_filled(&poll_map, i)) {
+ continue;
+ }
+ poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value);
+ if (poll_obj->flags_ret & MP_STREAM_POLL_RD) {
+ ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj;
+ }
+ if (poll_obj->flags_ret & MP_STREAM_POLL_WR) {
+ ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj;
+ }
+ if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
+ ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj;
+ }
+ }
+ mp_map_deinit(&poll_map);
+ return mp_obj_new_tuple(3, list_array);
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
+#endif // MICROPY_PY_SELECT_SELECT
+
+typedef struct _mp_obj_poll_t {
+ mp_obj_base_t base;
+ mp_map_t poll_map;
+ short iter_cnt;
+ short iter_idx;
+ int flags;
+ // callee-owned tuple
+ mp_obj_t ret_tuple;
+} mp_obj_poll_t;
+
+// register(obj[, eventmask])
+STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_uint_t flags;
+ if (n_args == 3) {
+ flags = mp_obj_get_int(args[2]);
+ } else {
+ flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;
+ }
+ poll_map_add(&self->poll_map, &args[1], 1, flags, false);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
+
+// unregister(obj)
+STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
+ // TODO raise KeyError if obj didn't exist in map
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
+
+// modify(obj, eventmask)
+STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
+ if (elem == NULL) {
+ mp_raise_OSError(MP_ENOENT);
+ }
+ ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
+
+STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ // work out timeout (its given already in ms)
+ mp_uint_t timeout = -1;
+ int flags = 0;
+ if (n_args >= 2) {
+ if (args[1] != mp_const_none) {
+ mp_int_t timeout_i = mp_obj_get_int(args[1]);
+ if (timeout_i >= 0) {
+ timeout = timeout_i;
+ }
+ }
+ if (n_args >= 3) {
+ flags = mp_obj_get_int(args[2]);
+ }
+ }
+
+ self->flags = flags;
+
+ mp_uint_t start_tick = mp_hal_ticks_ms();
+ mp_uint_t n_ready;
+ for (;;) {
+ // poll the objects
+ n_ready = poll_map_poll(&self->poll_map, NULL);
+ if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
+ break;
+ }
+ MICROPY_EVENT_POLL_HOOK
+ }
+
+ return n_ready;
+}
+
+STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_uint_t n_ready = poll_poll_internal(n_args, args);
+
+ // one or more objects are ready, or we had a timeout
+ mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));
+ n_ready = 0;
+ for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) {
+ if (!mp_map_slot_is_filled(&self->poll_map, i)) {
+ continue;
+ }
+ poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
+ if (poll_obj->flags_ret != 0) {
+ mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)};
+ ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);
+ if (self->flags & FLAG_ONESHOT) {
+ // Don't poll next time, until new event flags will be set explicitly
+ poll_obj->flags = 0;
+ }
+ }
+ }
+ return MP_OBJ_FROM_PTR(ret_list);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);
+
+STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (self->ret_tuple == MP_OBJ_NULL) {
+ self->ret_tuple = mp_obj_new_tuple(2, NULL);
+ }
+
+ int n_ready = poll_poll_internal(n_args, args);
+ self->iter_cnt = n_ready;
+ self->iter_idx = 0;
+
+ return args[0];
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll);
+
+STATIC mp_obj_t poll_iternext(mp_obj_t self_in) {
+ mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->iter_cnt == 0) {
+ return MP_OBJ_STOP_ITERATION;
+ }
+
+ self->iter_cnt--;
+
+ for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) {
+ self->iter_idx++;
+ if (!mp_map_slot_is_filled(&self->poll_map, i)) {
+ continue;
+ }
+ poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
+ if (poll_obj->flags_ret != 0) {
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);
+ t->items[0] = poll_obj->obj;
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret);
+ if (self->flags & FLAG_ONESHOT) {
+ // Don't poll next time, until new event flags will be set explicitly
+ poll_obj->flags = 0;
+ }
+ return MP_OBJ_FROM_PTR(t);
+ }
+ }
+
+ assert(!"inconsistent number of poll active entries");
+ self->iter_cnt = 0;
+ return MP_OBJ_STOP_ITERATION;
+}
+
+STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) },
+ { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) },
+ { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ mp_type_poll,
+ MP_QSTR_poll,
+ MP_TYPE_FLAG_ITER_IS_ITERNEXT,
+ iter, poll_iternext,
+ locals_dict, &poll_locals_dict
+ );
+
+// poll()
+STATIC mp_obj_t select_poll(void) {
+ mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll);
+ mp_map_init(&poll->poll_map, 0);
+ poll->iter_cnt = 0;
+ poll->ret_tuple = MP_OBJ_NULL;
+ return MP_OBJ_FROM_PTR(poll);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll);
+
+STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_select) },
+ #if MICROPY_PY_SELECT_SELECT
+ { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_select_select_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) },
+ { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(MP_STREAM_POLL_RD) },
+ { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(MP_STREAM_POLL_WR) },
+ { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(MP_STREAM_POLL_ERR) },
+ { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(MP_STREAM_POLL_HUP) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table);
+
+const mp_obj_module_t mp_module_select = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_select_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_select, mp_module_select);
+
+#endif // MICROPY_PY_SELECT
diff --git a/extmod/modsocket.c b/extmod/modsocket.c
new file mode 100644
index 000000000000..488b6d17125d
--- /dev/null
+++ b/extmod/modsocket.c
@@ -0,0 +1,658 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/objtuple.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mperrno.h"
+
+#if MICROPY_PY_NETWORK && MICROPY_PY_SOCKET && !MICROPY_PY_LWIP
+
+#include "shared/netutils/netutils.h"
+#include "modnetwork.h"
+
+/******************************************************************************/
+// socket class
+
+STATIC const mp_obj_type_t socket_type;
+
+STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "",
+ self->fileno, self->timeout, self->domain, self->type, self->proto, self->bound);
+}
+
+// constructor socket(domain=AF_INET, type=SOCK_STREAM, proto=0)
+STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 3, false);
+
+ // create socket object (not bound to any NIC yet)
+ mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ s->base.type = &socket_type;
+ s->nic = MP_OBJ_NULL;
+ s->nic_protocol = NULL;
+ s->domain = MOD_NETWORK_AF_INET;
+ s->type = MOD_NETWORK_SOCK_STREAM;
+ s->proto = 0;
+ s->bound = false;
+ s->fileno = -1;
+ if (n_args > 0) {
+ s->domain = mp_obj_get_int(args[0]);
+ if (n_args > 1) {
+ s->type = mp_obj_get_int(args[1]);
+ if (n_args > 2) {
+ s->proto = mp_obj_get_int(args[2]);
+ }
+ }
+ }
+ s->timeout = -1;
+ s->callback = MP_OBJ_NULL;
+ s->state = MOD_NETWORK_SS_NEW;
+ #if MICROPY_PY_SOCKET_EXTENDED_STATE
+ s->_private = NULL;
+ #endif
+
+ return MP_OBJ_FROM_PTR(s);
+}
+
+STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
+ if (self->nic == MP_OBJ_NULL) {
+ // select NIC based on IP
+ self->nic = mod_network_find_nic(ip);
+ self->nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(self->nic), protocol);
+
+ // call the NIC to open the socket
+ int _errno;
+ if (self->nic_protocol->socket(self, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ #if MICROPY_PY_SOCKET_EXTENDED_STATE
+ // if a timeout was set before binding a NIC, call settimeout to reset it
+ if (self->timeout != -1 && self->nic_protocol->settimeout(self, self->timeout, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+ #endif
+ }
+}
+
+// method socket.bind(address)
+STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to bind the socket
+ int _errno;
+ if (self->nic_protocol->bind(self, ip, port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
+
+// method socket.listen([backlog])
+STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ // TODO I think we can listen even if not bound...
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+
+ mp_int_t backlog = MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT;
+ if (n_args > 1) {
+ backlog = mp_obj_get_int(args[1]);
+ backlog = (backlog < 0) ? 0 : backlog;
+ }
+
+ int _errno;
+ if (self->nic_protocol->listen(self, backlog, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ // set socket state
+ self->state = MOD_NETWORK_SS_LISTENING;
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
+
+// method socket.accept()
+STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->nic == MP_OBJ_NULL) {
+ // not bound
+ mp_raise_OSError(MP_EINVAL);
+ }
+
+ // create new socket object
+ // starts with empty NIC so that finaliser doesn't run close() method if accept() fails
+ mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ socket2->base.type = &socket_type;
+ socket2->nic = MP_OBJ_NULL;
+ socket2->nic_protocol = NULL;
+
+ // set the same address family, socket type and protocol as parent
+ socket2->domain = self->domain;
+ socket2->type = self->type;
+ socket2->proto = self->proto;
+ socket2->bound = false;
+ socket2->fileno = -1;
+ socket2->timeout = -1;
+ socket2->callback = MP_OBJ_NULL;
+ socket2->state = MOD_NETWORK_SS_NEW;
+ #if MICROPY_PY_SOCKET_EXTENDED_STATE
+ socket2->_private = NULL;
+ #endif
+
+ // accept incoming connection
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port;
+ int _errno;
+ if (self->nic_protocol->accept(self, socket2, ip, &port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ // new socket has valid state, so set the NIC to the same as parent
+ socket2->nic = self->nic;
+ socket2->nic_protocol = self->nic_protocol;
+
+ // make the return value
+ mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
+ client->items[0] = MP_OBJ_FROM_PTR(socket2);
+ client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+
+ return MP_OBJ_FROM_PTR(client);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
+
+// method socket.connect(address)
+STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to connect the socket
+ int _errno;
+ if (self->nic_protocol->connect(self, ip, port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ // set socket state
+ self->state = MOD_NETWORK_SS_CONNECTED;
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
+
+// method socket.send(bytes)
+STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_EPIPE);
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ int _errno;
+ mp_uint_t ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
+
+STATIC mp_obj_t socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_EPIPE);
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+
+ int _errno;
+ mp_uint_t ret = 0;
+ if (self->timeout == 0) {
+ ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ } else if (bufinfo.len > ret) {
+ mp_raise_OSError(MP_EAGAIN);
+ }
+ } else {
+ // TODO: In CPython3.5, socket timeout should apply to the
+ // entire sendall() operation, not to individual send() chunks.
+ while (bufinfo.len != 0) {
+ ret = self->nic_protocol->send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ bufinfo.len -= ret;
+ bufinfo.buf = (char *)bufinfo.buf + ret;
+ }
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall);
+
+// method socket.recv(bufsize)
+STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+ mp_int_t len = mp_obj_get_int(len_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+ int _errno;
+ mp_uint_t ret = self->nic_protocol->recv(self, (byte *)vstr.buf, len, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ if (ret == 0) {
+ return mp_const_empty_bytes;
+ }
+ vstr.len = ret;
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
+
+// method socket.sendto(bytes, address)
+STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // get the data
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to sendto
+ int _errno;
+ mp_int_t ret = self->nic_protocol->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
+
+// method socket.recvfrom(bufsize)
+STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ }
+ vstr_t vstr;
+ vstr_init_len(&vstr, mp_obj_get_int(len_in));
+ byte ip[4];
+ mp_uint_t port;
+ int _errno;
+ mp_int_t ret = self->nic_protocol->recvfrom(self, (byte *)vstr.buf, vstr.len, ip, &port, &_errno);
+ if (ret == -1) {
+ mp_raise_OSError(_errno);
+ }
+ mp_obj_t tuple[2];
+ if (ret == 0) {
+ tuple[0] = mp_const_empty_bytes;
+ } else {
+ vstr.len = ret;
+ tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
+ }
+ tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
+
+// method socket.setsockopt(level, optname, value)
+STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+
+ if (self->nic == MP_OBJ_NULL) {
+ // bind to default NIC.
+ uint8_t ip[4] = {0, 0, 0, 0};
+ socket_select_nic(self, ip);
+ }
+
+ mp_int_t level = mp_obj_get_int(args[1]);
+ mp_int_t opt = mp_obj_get_int(args[2]);
+
+ const void *optval;
+ mp_uint_t optlen;
+ mp_int_t val;
+ if (mp_obj_is_integer(args[3])) {
+ val = mp_obj_get_int_truncated(args[3]);
+ optval = &val;
+ optlen = sizeof(val);
+ } else if (opt == 20 && args[3] == mp_const_none) {
+ optval = MP_OBJ_NULL;
+ optlen = 0;
+ } else if (opt == 20 && mp_obj_is_callable(args[3])) {
+ optval = args[3];
+ optlen = sizeof(optval);
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ optval = bufinfo.buf;
+ optlen = bufinfo.len;
+ }
+
+ int _errno;
+ if (self->nic_protocol->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+
+STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return args[0];
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
+
+// method socket.settimeout(value)
+// timeout=0 means non-blocking
+// timeout=None means blocking
+// otherwise, timeout is in seconds
+STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_uint_t timeout;
+ if (timeout_in == mp_const_none) {
+ timeout = -1;
+ } else {
+ #if MICROPY_PY_BUILTINS_FLOAT
+ timeout = (mp_uint_t)(MICROPY_FLOAT_CONST(1000.0) * mp_obj_get_float(timeout_in));
+ #else
+ timeout = 1000 * mp_obj_get_int(timeout_in);
+ #endif
+ }
+ if (self->nic == MP_OBJ_NULL) {
+ #if MICROPY_PY_SOCKET_EXTENDED_STATE
+ // store the timeout in the socket state until a NIC is bound
+ self->timeout = timeout;
+ #else
+ // not connected
+ mp_raise_OSError(MP_ENOTCONN);
+ #endif
+ } else {
+ int _errno;
+ if (self->nic_protocol->settimeout(self, timeout, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
+
+// method socket.setblocking(flag)
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ if (mp_obj_is_true(blocking)) {
+ return socket_settimeout(self_in, mp_const_none);
+ } else {
+ return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
+STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
+ { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
+
+mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ return MP_STREAM_ERROR;
+ }
+ mp_int_t ret = self->nic_protocol->recv(self, (byte *)buf, size, errcode);
+ if (ret < 0) {
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->nic == MP_OBJ_NULL) {
+ return MP_STREAM_ERROR;
+ }
+ mp_int_t ret = self->nic_protocol->send(self, buf, size, errcode);
+ if (ret < 0) {
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (request == MP_STREAM_CLOSE) {
+ if (self->nic != MP_OBJ_NULL) {
+ self->nic_protocol->close(self);
+ self->nic = MP_OBJ_NULL;
+ }
+ self->state = MOD_NETWORK_SS_CLOSED;
+ return 0;
+ }
+ if (self->nic == MP_OBJ_NULL) {
+ if (request == MP_STREAM_POLL) {
+ if (self->state == MOD_NETWORK_SS_NEW) {
+ // New sockets are writable and not connected.
+ return MP_STREAM_POLL_HUP | MP_STREAM_POLL_WR;
+ } else if (self->state == MOD_NETWORK_SS_CLOSED) {
+ // Closed socket, return invalid.
+ return MP_STREAM_POLL_NVAL;
+ }
+ }
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ return self->nic_protocol->ioctl(self, request, arg, errcode);
+}
+
+STATIC const mp_stream_p_t socket_stream_p = {
+ .read = socket_read,
+ .write = socket_write,
+ .ioctl = socket_ioctl,
+ .is_text = false,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ socket_type,
+ MP_QSTR_socket,
+ MP_TYPE_FLAG_NONE,
+ make_new, socket_make_new,
+ protocol, &socket_stream_p,
+ locals_dict, &socket_locals_dict,
+ print, socket_print
+ );
+
+/******************************************************************************/
+// socket module
+
+// function socket.getaddrinfo(host, port)
+STATIC mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
+ size_t hlen;
+ const char *host = mp_obj_str_get_data(args[0], &hlen);
+ mp_int_t port = mp_obj_get_int(args[1]);
+ uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ bool have_ip = false;
+
+ // if constraints were passed then check they are compatible with the supported params
+ if (n_args > 2) {
+ mp_int_t family = mp_obj_get_int(args[2]);
+ mp_int_t type = 0;
+ mp_int_t proto = 0;
+ mp_int_t flags = 0;
+ if (n_args > 3) {
+ type = mp_obj_get_int(args[3]);
+ if (n_args > 4) {
+ proto = mp_obj_get_int(args[4]);
+ if (n_args > 5) {
+ flags = mp_obj_get_int(args[5]);
+ }
+ }
+ }
+ if (!((family == 0 || family == MOD_NETWORK_AF_INET)
+ && (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
+ && proto == 0
+ && flags == 0)) {
+ mp_warning(MP_WARN_CAT(RuntimeWarning), "unsupported getaddrinfo constraints");
+ }
+ }
+
+ if (hlen > 0) {
+ // check if host is already in IP form
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ netutils_parse_ipv4_addr(args[0], out_ip, NETUTILS_BIG);
+ have_ip = true;
+ nlr_pop();
+ } else {
+ // swallow exception: host was not in IP form so need to do DNS lookup
+ }
+ }
+
+ if (!have_ip) {
+ // find a NIC that can do a name lookup
+ for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
+ mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
+ mod_network_nic_protocol_t *nic_protocol = (mod_network_nic_protocol_t *)MP_OBJ_TYPE_GET_SLOT(mp_obj_get_type(nic), protocol);
+ if (nic_protocol->gethostbyname != NULL) {
+ int ret = nic_protocol->gethostbyname(nic, host, hlen, out_ip);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+ have_ip = true;
+ break;
+ }
+ }
+ }
+
+ if (!have_ip) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("no available NIC"));
+ }
+
+ mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
+ tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
+ tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
+ return mp_obj_new_list(1, (mp_obj_t *)&tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod_socket_getaddrinfo);
+
+STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_socket) },
+
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
+ { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_socket_getaddrinfo_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) },
+ { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) },
+
+ { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) },
+
+ { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(MOD_NETWORK_SOL_SOCKET) },
+ { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(MOD_NETWORK_SO_REUSEADDR) },
+ { MP_ROM_QSTR(MP_QSTR_SO_KEEPALIVE), MP_ROM_INT(MOD_NETWORK_SO_KEEPALIVE) },
+ { MP_ROM_QSTR(MP_QSTR_SO_SNDTIMEO), MP_ROM_INT(MOD_NETWORK_SO_SNDTIMEO) },
+ { MP_ROM_QSTR(MP_QSTR_SO_RCVTIMEO), MP_ROM_INT(MOD_NETWORK_SO_RCVTIMEO) },
+
+ /*
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(MOD_NETWORK_IPPROTO_IP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_ICMP), MP_ROM_INT(MOD_NETWORK_IPPROTO_ICMP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV4), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV4) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(MOD_NETWORK_IPPROTO_TCP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(MOD_NETWORK_IPPROTO_UDP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV6), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV6) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_RAW), MP_ROM_INT(MOD_NETWORK_IPPROTO_RAW) },
+ */
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
+
+const mp_obj_module_t mp_module_socket = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_socket_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_socket);
+
+#endif // MICROPY_PY_NETWORK && MICROPY_PY_SOCKET && !MICROPY_PY_LWIP
diff --git a/extmod/modssl_axtls.c b/extmod/modssl_axtls.c
new file mode 100644
index 000000000000..d169d89a2cfe
--- /dev/null
+++ b/extmod/modssl_axtls.c
@@ -0,0 +1,461 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2019 Paul Sokolovsky
+ * Copyright (c) 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+
+#if MICROPY_PY_SSL && MICROPY_SSL_AXTLS
+
+#include "ssl.h"
+
+#define PROTOCOL_TLS_CLIENT (0)
+#define PROTOCOL_TLS_SERVER (1)
+
+// This corresponds to an SSLContext object.
+typedef struct _mp_obj_ssl_context_t {
+ mp_obj_base_t base;
+ mp_obj_t key;
+ mp_obj_t cert;
+} mp_obj_ssl_context_t;
+
+// This corresponds to an SSLSocket object.
+typedef struct _mp_obj_ssl_socket_t {
+ mp_obj_base_t base;
+ mp_obj_t sock;
+ SSL_CTX *ssl_ctx;
+ SSL *ssl_sock;
+ byte *buf;
+ uint32_t bytes_left;
+ bool blocking;
+} mp_obj_ssl_socket_t;
+
+struct ssl_args {
+ mp_arg_val_t key;
+ mp_arg_val_t cert;
+ mp_arg_val_t server_side;
+ mp_arg_val_t server_hostname;
+ mp_arg_val_t do_handshake;
+};
+
+STATIC const mp_obj_type_t ssl_context_type;
+STATIC const mp_obj_type_t ssl_socket_type;
+
+STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
+ bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname);
+
+/******************************************************************************/
+// Helper functions.
+
+// Table of error strings corresponding to SSL_xxx error codes.
+STATIC const char *const ssl_error_tab1[] = {
+ "NOT_OK",
+ "DEAD",
+ "CLOSE_NOTIFY",
+ "EAGAIN",
+};
+STATIC const char *const ssl_error_tab2[] = {
+ "CONN_LOST",
+ "RECORD_OVERFLOW",
+ "SOCK_SETUP_FAILURE",
+ NULL,
+ "INVALID_HANDSHAKE",
+ "INVALID_PROT_MSG",
+ "INVALID_HMAC",
+ "INVALID_VERSION",
+ "UNSUPPORTED_EXTENSION",
+ "INVALID_SESSION",
+ "NO_CIPHER",
+ "INVALID_CERT_HASH_ALG",
+ "BAD_CERTIFICATE",
+ "INVALID_KEY",
+ NULL,
+ "FINISHED_INVALID",
+ "NO_CERT_DEFINED",
+ "NO_CLIENT_RENOG",
+ "NOT_SUPPORTED",
+};
+
+STATIC NORETURN void ssl_raise_error(int err) {
+ MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN);
+ MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED);
+
+ // Check if err corresponds to something in one of the error string tables.
+ const char *errstr = NULL;
+ if (SSL_NOT_OK >= err && err >= SSL_EAGAIN) {
+ errstr = ssl_error_tab1[SSL_NOT_OK - err];
+ } else if (SSL_ERROR_CONN_LOST >= err && err >= SSL_ERROR_NOT_SUPPORTED) {
+ errstr = ssl_error_tab2[SSL_ERROR_CONN_LOST - err];
+ }
+
+ // Unknown error, just raise the error code.
+ if (errstr == NULL) {
+ mp_raise_OSError(err);
+ }
+
+ // Construct string object.
+ mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
+ if (o_str == NULL) {
+ mp_raise_OSError(err);
+ }
+ o_str->base.type = &mp_type_str;
+ o_str->data = (const byte *)errstr;
+ o_str->len = strlen((char *)o_str->data);
+ o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+
+ // Raise OSError(err, str).
+ mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
+ nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
+}
+
+/******************************************************************************/
+// SSLContext type.
+
+STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // The "protocol" argument is ignored in this implementation.
+
+ // Create SSLContext object.
+ #if MICROPY_PY_SSL_FINALISER
+ mp_obj_ssl_context_t *self = m_new_obj_with_finaliser(mp_obj_ssl_context_t);
+ #else
+ mp_obj_ssl_context_t *self = m_new_obj(mp_obj_ssl_context_t);
+ #endif
+ self->base.type = type_in;
+ self->key = mp_const_none;
+ self->cert = mp_const_none;
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void ssl_context_load_key(mp_obj_ssl_context_t *self, mp_obj_t key_obj, mp_obj_t cert_obj) {
+ self->key = key_obj;
+ self->cert = cert_obj;
+}
+
+STATIC mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_do_handshake_on_connect, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ };
+
+ // Parse arguments.
+ mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_obj_t sock = pos_args[1];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Create and return the new SSLSocket object.
+ return ssl_socket_make_new(self, sock, args[ARG_server_side].u_bool,
+ args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_wrap_socket_obj, 2, ssl_context_wrap_socket);
+
+STATIC const mp_rom_map_elem_t ssl_context_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&ssl_context_wrap_socket_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(ssl_context_locals_dict, ssl_context_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ ssl_context_type,
+ MP_QSTR_SSLContext,
+ MP_TYPE_FLAG_NONE,
+ make_new, ssl_context_make_new,
+ locals_dict, &ssl_context_locals_dict
+ );
+
+/******************************************************************************/
+// SSLSocket type.
+
+STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
+ bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname) {
+
+ #if MICROPY_PY_SSL_FINALISER
+ mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
+ #else
+ mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
+ #endif
+ o->base.type = &ssl_socket_type;
+ o->buf = NULL;
+ o->bytes_left = 0;
+ o->sock = sock;
+ o->blocking = true;
+
+ uint32_t options = SSL_SERVER_VERIFY_LATER;
+ if (!do_handshake_on_connect) {
+ options |= SSL_CONNECT_IN_PARTS;
+ }
+ if (ssl_context->key != mp_const_none) {
+ options |= SSL_NO_DEFAULT_KEY;
+ }
+ if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
+ mp_raise_OSError(MP_EINVAL);
+ }
+
+ if (ssl_context->key != mp_const_none) {
+ size_t len;
+ const byte *data = (const byte *)mp_obj_str_get_data(ssl_context->key, &len);
+ int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL);
+ if (res != SSL_OK) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid key"));
+ }
+
+ data = (const byte *)mp_obj_str_get_data(ssl_context->cert, &len);
+ res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL);
+ if (res != SSL_OK) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid cert"));
+ }
+ }
+
+ if (server_side) {
+ o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock);
+ } else {
+ SSL_EXTENSIONS *ext = ssl_ext_new();
+
+ if (server_hostname != mp_const_none) {
+ ext->host_name = (char *)mp_obj_str_get_str(server_hostname);
+ }
+
+ o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext);
+
+ if (do_handshake_on_connect) {
+ int r = ssl_handshake_status(o->ssl_sock);
+
+ if (r != SSL_OK) {
+ if (r == SSL_CLOSE_NOTIFY) { // EOF
+ r = MP_ENOTCONN;
+ } else if (r == SSL_EAGAIN) {
+ r = MP_EAGAIN;
+ }
+ ssl_raise_error(r);
+ }
+ }
+ }
+
+ return o;
+}
+
+STATIC mp_uint_t ssl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
+
+ if (o->ssl_sock == NULL) {
+ *errcode = EBADF;
+ return MP_STREAM_ERROR;
+ }
+
+ while (o->bytes_left == 0) {
+ mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
+ if (r == SSL_OK) {
+ // SSL_OK from ssl_read() means "everything is ok, but there's
+ // no user data yet". It may happen e.g. if handshake is not
+ // finished yet. The best way we can treat it is by returning
+ // EAGAIN. This may be a bit unexpected in blocking mode, but
+ // default is to perform complete handshake in constructor, so
+ // this should not happen in blocking mode. On the other hand,
+ // in nonblocking mode EAGAIN (comparing to the alternative of
+ // looping) is really preferable.
+ if (o->blocking) {
+ continue;
+ } else {
+ goto eagain;
+ }
+ }
+ if (r < 0) {
+ if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
+ // EOF
+ return 0;
+ }
+ if (r == SSL_EAGAIN) {
+ eagain:
+ r = MP_EAGAIN;
+ }
+ *errcode = r;
+ return MP_STREAM_ERROR;
+ }
+ o->bytes_left = r;
+ }
+
+ if (size > o->bytes_left) {
+ size = o->bytes_left;
+ }
+ memcpy(buf, o->buf, size);
+ o->buf += size;
+ o->bytes_left -= size;
+ return size;
+}
+
+STATIC mp_uint_t ssl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
+
+ if (o->ssl_sock == NULL) {
+ *errcode = EBADF;
+ return MP_STREAM_ERROR;
+ }
+
+ mp_int_t r;
+eagain:
+ r = ssl_write(o->ssl_sock, buf, size);
+ if (r == 0) {
+ // see comment in ssl_socket_read above
+ if (o->blocking) {
+ goto eagain;
+ } else {
+ r = SSL_EAGAIN;
+ }
+ }
+ if (r < 0) {
+ if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
+ return 0; // EOF
+ }
+ if (r == SSL_EAGAIN) {
+ r = MP_EAGAIN;
+ }
+ *errcode = r;
+ return MP_STREAM_ERROR;
+ }
+ return r;
+}
+
+STATIC mp_uint_t ssl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
+ if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {
+ ssl_free(self->ssl_sock);
+ ssl_ctx_free(self->ssl_ctx);
+ self->ssl_sock = NULL;
+ }
+ // Pass all requests down to the underlying socket
+ return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
+}
+
+STATIC mp_obj_t ssl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t sock = o->sock;
+ mp_obj_t dest[3];
+ mp_load_method(sock, MP_QSTR_setblocking, dest);
+ dest[2] = flag_in;
+ mp_obj_t res = mp_call_method_n_kw(1, 0, dest);
+ o->blocking = mp_obj_is_true(flag_in);
+ return res;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(ssl_socket_setblocking_obj, ssl_socket_setblocking);
+
+STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ssl_socket_setblocking_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ #if MICROPY_PY_SSL_FINALISER
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ #endif
+};
+STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table);
+
+STATIC const mp_stream_p_t ssl_socket_stream_p = {
+ .read = ssl_socket_read,
+ .write = ssl_socket_write,
+ .ioctl = ssl_socket_ioctl,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ ssl_socket_type,
+ MP_QSTR_SSLSocket,
+ MP_TYPE_FLAG_NONE,
+ protocol, &ssl_socket_stream_p,
+ locals_dict, &ssl_socket_locals_dict
+ );
+
+/******************************************************************************/
+// ssl module.
+
+STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {
+ ARG_key,
+ ARG_cert,
+ ARG_server_side,
+ ARG_server_hostname,
+ ARG_do_handshake,
+ };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ // Parse arguments.
+ mp_obj_t sock = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Create SSLContext.
+ mp_int_t protocol = args[ARG_server_side].u_bool ? PROTOCOL_TLS_SERVER : PROTOCOL_TLS_CLIENT;
+ mp_obj_t ssl_context_args[1] = { MP_OBJ_NEW_SMALL_INT(protocol) };
+ mp_obj_ssl_context_t *ssl_context = MP_OBJ_TO_PTR(ssl_context_make_new(&ssl_context_type, 1, 0, ssl_context_args));
+
+ // Load key and cert if given.
+ if (args[ARG_key].u_obj != mp_const_none) {
+ ssl_context_load_key(ssl_context, args[ARG_key].u_obj, args[ARG_cert].u_obj);
+ }
+
+ // Create and return the new SSLSocket object.
+ return ssl_socket_make_new(ssl_context, sock, args[ARG_server_side].u_bool,
+ args[ARG_do_handshake].u_bool, args[ARG_server_hostname].u_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
+
+STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) },
+
+ // Functions.
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
+
+ // Classes.
+ { MP_ROM_QSTR(MP_QSTR_SSLContext), MP_ROM_PTR(&ssl_context_type) },
+
+ // Constants.
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(PROTOCOL_TLS_CLIENT) },
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(PROTOCOL_TLS_SERVER) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
+
+const mp_obj_module_t mp_module_ssl = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_ssl, mp_module_ssl);
+
+#endif // MICROPY_PY_SSL && MICROPY_SSL_AXTLS
diff --git a/extmod/modssl_mbedtls.c b/extmod/modssl_mbedtls.c
new file mode 100644
index 000000000000..83f6f907f4cc
--- /dev/null
+++ b/extmod/modssl_mbedtls.c
@@ -0,0 +1,640 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Linaro Ltd.
+ * Copyright (c) 2019 Paul Sokolovsky
+ * Copyright (c) 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpconfig.h"
+#if MICROPY_PY_SSL && MICROPY_SSL_MBEDTLS
+
+#include
+#include
+#include // needed because mp_is_nonblocking_error uses system error codes
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+
+// mbedtls_time_t
+#include "mbedtls/platform.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/error.h"
+
+#define MP_STREAM_POLL_RDWR (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)
+
+// This corresponds to an SSLContext object.
+typedef struct _mp_obj_ssl_context_t {
+ mp_obj_base_t base;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_ssl_config conf;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt cert;
+ mbedtls_pk_context pkey;
+ int authmode;
+} mp_obj_ssl_context_t;
+
+// This corresponds to an SSLSocket object.
+typedef struct _mp_obj_ssl_socket_t {
+ mp_obj_base_t base;
+ mp_obj_ssl_context_t *ssl_context;
+ mp_obj_t sock;
+ mbedtls_ssl_context ssl;
+
+ uintptr_t poll_mask; // Indicates which read or write operations the protocol needs next
+ int last_error; // The last error code, if any
+} mp_obj_ssl_socket_t;
+
+STATIC const mp_obj_type_t ssl_context_type;
+STATIC const mp_obj_type_t ssl_socket_type;
+
+STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
+ bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname);
+
+/******************************************************************************/
+// Helper functions.
+
+#ifdef MBEDTLS_DEBUG_C
+STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
+ (void)ctx;
+ (void)level;
+ mp_printf(&mp_plat_print, "DBG:%s:%04d: %s\n", file, line, str);
+}
+#endif
+
+STATIC NORETURN void mbedtls_raise_error(int err) {
+ // Handle special cases.
+ if (err == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
+ mp_raise_OSError(MP_ENOMEM);
+ } else if (err == MBEDTLS_ERR_PK_BAD_INPUT_DATA) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid key"));
+ } else if (err == MBEDTLS_ERR_X509_BAD_INPUT_DATA) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid cert"));
+ }
+
+ // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the
+ // underlying socket into negative codes to pass them through mbedtls. Here we turn them
+ // positive again so they get interpreted as the OSError they really are. The
+ // cut-off of -256 is a bit hacky, sigh.
+ if (err < 0 && err > -256) {
+ mp_raise_OSError(-err);
+ }
+
+ #if defined(MBEDTLS_ERROR_C)
+ // Including mbedtls_strerror takes about 1.5KB due to the error strings.
+ // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror.
+ // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.
+
+ // Try to allocate memory for the message
+ #define ERR_STR_MAX 80 // mbedtls_strerror truncates if it doesn't fit
+ mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
+ byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX);
+ if (o_str == NULL || o_str_buf == NULL) {
+ mp_raise_OSError(err);
+ }
+
+ // print the error message into the allocated buffer
+ mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX);
+ size_t len = strlen((char *)o_str_buf);
+
+ // Put the exception object together
+ o_str->base.type = &mp_type_str;
+ o_str->data = o_str_buf;
+ o_str->len = len;
+ o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
+ // raise
+ mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
+ nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
+ #else
+ // mbedtls is compiled without error strings so we simply return the err number
+ mp_raise_OSError(err); // err is typically a large negative number
+ #endif
+}
+
+/******************************************************************************/
+// SSLContext type.
+
+STATIC mp_obj_t ssl_context_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 1, false);
+
+ // This is the "protocol" argument.
+ mp_int_t endpoint = mp_obj_get_int(args[0]);
+
+ // Create SSLContext object.
+ #if MICROPY_PY_SSL_FINALISER
+ mp_obj_ssl_context_t *self = m_new_obj_with_finaliser(mp_obj_ssl_context_t);
+ #else
+ mp_obj_ssl_context_t *self = m_new_obj(mp_obj_ssl_context_t);
+ #endif
+ self->base.type = type_in;
+
+ // Initialise mbedTLS state.
+ mbedtls_ssl_config_init(&self->conf);
+ mbedtls_entropy_init(&self->entropy);
+ mbedtls_ctr_drbg_init(&self->ctr_drbg);
+ mbedtls_x509_crt_init(&self->cacert);
+ mbedtls_x509_crt_init(&self->cert);
+ mbedtls_pk_init(&self->pkey);
+
+ #ifdef MBEDTLS_DEBUG_C
+ // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose
+ mbedtls_debug_set_threshold(3);
+ #endif
+
+ const byte seed[] = "upy";
+ int ret = mbedtls_ctr_drbg_seed(&self->ctr_drbg, mbedtls_entropy_func, &self->entropy, seed, sizeof(seed));
+ if (ret != 0) {
+ mbedtls_raise_error(ret);
+ }
+
+ ret = mbedtls_ssl_config_defaults(&self->conf, endpoint,
+ MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
+ if (ret != 0) {
+ mbedtls_raise_error(ret);
+ }
+
+ if (endpoint == MBEDTLS_SSL_IS_CLIENT) {
+ // The CPython default is MBEDTLS_SSL_VERIFY_REQUIRED, but to maintain
+ // backwards compatibility we use MBEDTLS_SSL_VERIFY_NONE for now.
+ self->authmode = MBEDTLS_SSL_VERIFY_NONE;
+ } else {
+ self->authmode = MBEDTLS_SSL_VERIFY_NONE;
+ }
+ mbedtls_ssl_conf_authmode(&self->conf, self->authmode);
+ mbedtls_ssl_conf_rng(&self->conf, mbedtls_ctr_drbg_random, &self->ctr_drbg);
+ #ifdef MBEDTLS_DEBUG_C
+ mbedtls_ssl_conf_dbg(&self->conf, mbedtls_debug, NULL);
+ #endif
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void ssl_context_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(self_in);
+ if (dest[0] == MP_OBJ_NULL) {
+ // Load attribute.
+ if (attr == MP_QSTR_verify_mode) {
+ dest[0] = MP_OBJ_NEW_SMALL_INT(self->authmode);
+ } else {
+ // Continue lookup in locals_dict.
+ dest[1] = MP_OBJ_SENTINEL;
+ }
+ } else if (dest[1] != MP_OBJ_NULL) {
+ // Store attribute.
+ if (attr == MP_QSTR_verify_mode) {
+ self->authmode = mp_obj_get_int(dest[1]);
+ dest[0] = MP_OBJ_NULL;
+ mbedtls_ssl_conf_authmode(&self->conf, self->authmode);
+ }
+ }
+}
+
+#if MICROPY_PY_SSL_FINALISER
+STATIC mp_obj_t ssl_context___del__(mp_obj_t self_in) {
+ mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(self_in);
+ mbedtls_pk_free(&self->pkey);
+ mbedtls_x509_crt_free(&self->cert);
+ mbedtls_x509_crt_free(&self->cacert);
+ mbedtls_ctr_drbg_free(&self->ctr_drbg);
+ mbedtls_entropy_free(&self->entropy);
+ mbedtls_ssl_config_free(&self->conf);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(ssl_context___del___obj, ssl_context___del__);
+#endif
+
+STATIC void ssl_context_load_key(mp_obj_ssl_context_t *self, mp_obj_t key_obj, mp_obj_t cert_obj) {
+ size_t key_len;
+ const byte *key = (const byte *)mp_obj_str_get_data(key_obj, &key_len);
+ // len should include terminating null
+ int ret;
+ #if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_pk_parse_key(&self->pkey, key, key_len + 1, NULL, 0, mbedtls_ctr_drbg_random, &self->ctr_drbg);
+ #else
+ ret = mbedtls_pk_parse_key(&self->pkey, key, key_len + 1, NULL, 0);
+ #endif
+ if (ret != 0) {
+ mbedtls_raise_error(MBEDTLS_ERR_PK_BAD_INPUT_DATA); // use general error for all key errors
+ }
+
+ size_t cert_len;
+ const byte *cert = (const byte *)mp_obj_str_get_data(cert_obj, &cert_len);
+ // len should include terminating null
+ ret = mbedtls_x509_crt_parse(&self->cert, cert, cert_len + 1);
+ if (ret != 0) {
+ mbedtls_raise_error(MBEDTLS_ERR_X509_BAD_INPUT_DATA); // use general error for all cert errors
+ }
+
+ ret = mbedtls_ssl_conf_own_cert(&self->conf, &self->cert, &self->pkey);
+ if (ret != 0) {
+ mbedtls_raise_error(ret);
+ }
+}
+
+STATIC void ssl_context_load_cadata(mp_obj_ssl_context_t *self, mp_obj_t cadata_obj) {
+ size_t cacert_len;
+ const byte *cacert = (const byte *)mp_obj_str_get_data(cadata_obj, &cacert_len);
+ // len should include terminating null
+ int ret = mbedtls_x509_crt_parse(&self->cacert, cacert, cacert_len + 1);
+ if (ret != 0) {
+ mbedtls_raise_error(MBEDTLS_ERR_X509_BAD_INPUT_DATA); // use general error for all cert errors
+ }
+
+ mbedtls_ssl_conf_ca_chain(&self->conf, &self->cacert, NULL);
+}
+
+STATIC mp_obj_t ssl_context_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_server_side, ARG_do_handshake_on_connect, ARG_server_hostname };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_do_handshake_on_connect, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ };
+
+ // Parse arguments.
+ mp_obj_ssl_context_t *self = MP_OBJ_TO_PTR(pos_args[0]);
+ mp_obj_t sock = pos_args[1];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Create and return the new SSLSocket object.
+ return ssl_socket_make_new(self, sock, args[ARG_server_side].u_bool,
+ args[ARG_do_handshake_on_connect].u_bool, args[ARG_server_hostname].u_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ssl_context_wrap_socket_obj, 2, ssl_context_wrap_socket);
+
+STATIC const mp_rom_map_elem_t ssl_context_locals_dict_table[] = {
+ #if MICROPY_PY_SSL_FINALISER
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&ssl_context___del___obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&ssl_context_wrap_socket_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(ssl_context_locals_dict, ssl_context_locals_dict_table);
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ ssl_context_type,
+ MP_QSTR_SSLContext,
+ MP_TYPE_FLAG_NONE,
+ make_new, ssl_context_make_new,
+ attr, ssl_context_attr,
+ locals_dict, &ssl_context_locals_dict
+ );
+
+/******************************************************************************/
+// SSLSocket type.
+
+STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
+ mp_obj_t sock = *(mp_obj_t *)ctx;
+
+ const mp_stream_p_t *sock_stream = mp_get_stream(sock);
+ int err;
+
+ mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
+ if (out_sz == MP_STREAM_ERROR) {
+ if (mp_is_nonblocking_error(err)) {
+ return MBEDTLS_ERR_SSL_WANT_WRITE;
+ }
+ return -err; // convert an MP_ERRNO to something mbedtls passes through as error
+ } else {
+ return out_sz;
+ }
+}
+
+// _mbedtls_ssl_recv is called by mbedtls to receive bytes from the underlying socket
+STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
+ mp_obj_t sock = *(mp_obj_t *)ctx;
+
+ const mp_stream_p_t *sock_stream = mp_get_stream(sock);
+ int err;
+
+ mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
+ if (out_sz == MP_STREAM_ERROR) {
+ if (mp_is_nonblocking_error(err)) {
+ return MBEDTLS_ERR_SSL_WANT_READ;
+ }
+ return -err;
+ } else {
+ return out_sz;
+ }
+}
+
+STATIC mp_obj_t ssl_socket_make_new(mp_obj_ssl_context_t *ssl_context, mp_obj_t sock,
+ bool server_side, bool do_handshake_on_connect, mp_obj_t server_hostname) {
+
+ // Verify the socket object has the full stream protocol
+ mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+
+ #if MICROPY_PY_SSL_FINALISER
+ mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
+ #else
+ mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
+ #endif
+ o->base.type = &ssl_socket_type;
+ o->sock = sock;
+ o->poll_mask = 0;
+ o->last_error = 0;
+
+ int ret;
+ mbedtls_ssl_init(&o->ssl);
+
+ ret = mbedtls_ssl_setup(&o->ssl, &ssl_context->conf);
+ if (ret != 0) {
+ goto cleanup;
+ }
+
+ if (server_hostname != mp_const_none) {
+ const char *sni = mp_obj_str_get_str(server_hostname);
+ ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
+ if (ret != 0) {
+ goto cleanup;
+ }
+ }
+
+ mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
+
+ if (do_handshake_on_connect) {
+ while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
+ if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
+ goto cleanup;
+ }
+ #ifdef MICROPY_EVENT_POLL_HOOK
+ MICROPY_EVENT_POLL_HOOK
+ #endif
+ }
+ }
+
+ return MP_OBJ_FROM_PTR(o);
+
+cleanup:
+ mbedtls_ssl_free(&o->ssl);
+ mbedtls_raise_error(ret);
+}
+
+STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
+ if (!mp_obj_is_true(binary_form)) {
+ mp_raise_NotImplementedError(NULL);
+ }
+ const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);
+ if (peer_cert == NULL) {
+ return mp_const_none;
+ }
+ return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
+
+STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
+ o->poll_mask = 0;
+
+ if (o->last_error) {
+ *errcode = o->last_error;
+ return MP_STREAM_ERROR;
+ }
+
+ int ret = mbedtls_ssl_read(&o->ssl, buf, size);
+ if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+ // end of stream
+ return 0;
+ }
+ if (ret >= 0) {
+ return ret;
+ }
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
+ ret = MP_EWOULDBLOCK;
+ } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ // If handshake is not finished, read attempt may end up in protocol
+ // wanting to write next handshake message. The same may happen with
+ // renegotiation.
+ ret = MP_EWOULDBLOCK;
+ o->poll_mask = MP_STREAM_POLL_WR;
+ } else {
+ o->last_error = ret;
+ }
+ *errcode = ret;
+ return MP_STREAM_ERROR;
+}
+
+STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
+ o->poll_mask = 0;
+
+ if (o->last_error) {
+ *errcode = o->last_error;
+ return MP_STREAM_ERROR;
+ }
+
+ int ret = mbedtls_ssl_write(&o->ssl, buf, size);
+ if (ret >= 0) {
+ return ret;
+ }
+ if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ ret = MP_EWOULDBLOCK;
+ } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
+ // If handshake is not finished, write attempt may end up in protocol
+ // wanting to read next handshake message. The same may happen with
+ // renegotiation.
+ ret = MP_EWOULDBLOCK;
+ o->poll_mask = MP_STREAM_POLL_RD;
+ } else {
+ o->last_error = ret;
+ }
+ *errcode = ret;
+ return MP_STREAM_ERROR;
+}
+
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
+ mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
+ mp_obj_t sock = o->sock;
+ mp_obj_t dest[3];
+ mp_load_method(sock, MP_QSTR_setblocking, dest);
+ dest[2] = flag_in;
+ return mp_call_method_n_kw(1, 0, dest);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
+STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
+ mp_uint_t ret = 0;
+ uintptr_t saved_arg = 0;
+ mp_obj_t sock = self->sock;
+ if (sock == MP_OBJ_NULL || (request != MP_STREAM_CLOSE && self->last_error != 0)) {
+ // Closed or error socket:
+ return MP_STREAM_POLL_NVAL;
+ }
+
+ if (request == MP_STREAM_CLOSE) {
+ self->sock = MP_OBJ_NULL;
+ mbedtls_ssl_free(&self->ssl);
+ } else if (request == MP_STREAM_POLL) {
+ // If the library signaled us that it needs reading or writing, only check that direction,
+ // but save what the caller asked because we need to restore it later
+ if (self->poll_mask && (arg & MP_STREAM_POLL_RDWR)) {
+ saved_arg = arg & MP_STREAM_POLL_RDWR;
+ arg = (arg & ~saved_arg) | self->poll_mask;
+ }
+
+ // Take into account that the library might have buffered data already
+ int has_pending = 0;
+ if (arg & MP_STREAM_POLL_RD) {
+ has_pending = mbedtls_ssl_check_pending(&self->ssl);
+ if (has_pending) {
+ ret |= MP_STREAM_POLL_RD;
+ if (arg == MP_STREAM_POLL_RD) {
+ // Shortcut if we only need to read and we have buffered data, no need to go to the underlying socket
+ return MP_STREAM_POLL_RD;
+ }
+ }
+ }
+ }
+
+ // Pass all requests down to the underlying socket
+ ret |= mp_get_stream(sock)->ioctl(sock, request, arg, errcode);
+
+ if (request == MP_STREAM_POLL) {
+ // The direction the library needed is available, return a fake result to the caller so that
+ // it reenters a read or a write to allow the handshake to progress
+ if (ret & self->poll_mask) {
+ ret |= saved_arg;
+ }
+ }
+ return ret;
+}
+
+STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ #if MICROPY_PY_SSL_FINALISER
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ #endif
+ #if MICROPY_UNIX_COVERAGE
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table);
+
+STATIC const mp_stream_p_t ssl_socket_stream_p = {
+ .read = socket_read,
+ .write = socket_write,
+ .ioctl = socket_ioctl,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ ssl_socket_type,
+ MP_QSTR_SSLSocket,
+ MP_TYPE_FLAG_NONE,
+ protocol, &ssl_socket_stream_p,
+ locals_dict, &ssl_socket_locals_dict
+ );
+
+/******************************************************************************/
+// ssl module.
+
+STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum {
+ ARG_key,
+ ARG_cert,
+ ARG_server_side,
+ ARG_server_hostname,
+ ARG_cert_reqs,
+ ARG_cadata,
+ ARG_do_handshake,
+ };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MBEDTLS_SSL_VERIFY_NONE}},
+ { MP_QSTR_cadata, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ };
+
+ // Parse arguments.
+ mp_obj_t sock = pos_args[0];
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Create SSLContext.
+ mp_int_t protocol = args[ARG_server_side].u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT;
+ mp_obj_t ssl_context_args[1] = { MP_OBJ_NEW_SMALL_INT(protocol) };
+ mp_obj_ssl_context_t *ssl_context = MP_OBJ_TO_PTR(ssl_context_make_new(&ssl_context_type, 1, 0, ssl_context_args));
+
+ // Load key and cert if given.
+ if (args[ARG_key].u_obj != mp_const_none) {
+ ssl_context_load_key(ssl_context, args[ARG_key].u_obj, args[ARG_cert].u_obj);
+ }
+
+ // Set the verify_mode.
+ mp_obj_t dest[2] = { MP_OBJ_SENTINEL, MP_OBJ_NEW_SMALL_INT(args[ARG_cert_reqs].u_int) };
+ ssl_context_attr(MP_OBJ_FROM_PTR(ssl_context), MP_QSTR_verify_mode, dest);
+
+ // Load cadata if given.
+ if (args[ARG_cadata].u_obj != mp_const_none) {
+ ssl_context_load_cadata(ssl_context, args[ARG_cadata].u_obj);
+ }
+
+ // Create and return the new SSLSocket object.
+ return ssl_socket_make_new(ssl_context, sock, args[ARG_server_side].u_bool,
+ args[ARG_do_handshake].u_bool, args[ARG_server_hostname].u_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
+
+STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) },
+
+ // Functions.
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
+
+ // Classes.
+ { MP_ROM_QSTR(MP_QSTR_SSLContext), MP_ROM_PTR(&ssl_context_type) },
+
+ // Constants.
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_CLIENT), MP_ROM_INT(MBEDTLS_SSL_IS_CLIENT) },
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLS_SERVER), MP_ROM_INT(MBEDTLS_SSL_IS_SERVER) },
+ { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(MBEDTLS_SSL_VERIFY_NONE) },
+ { MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(MBEDTLS_SSL_VERIFY_OPTIONAL) },
+ { MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(MBEDTLS_SSL_VERIFY_REQUIRED) },
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
+
+const mp_obj_module_t mp_module_ssl = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_ssl, mp_module_ssl);
+
+#endif // MICROPY_PY_SSL && MICROPY_SSL_MBEDTLS
diff --git a/extmod/modtime.c b/extmod/modtime.c
new file mode 100644
index 000000000000..805c2621c0b6
--- /dev/null
+++ b/extmod/modtime.c
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2023 Damien P. George
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mphal.h"
+#include "py/runtime.h"
+#include "py/smallint.h"
+#include "extmod/modtime.h"
+
+#if MICROPY_PY_TIME
+
+#ifdef MICROPY_PY_TIME_INCLUDEFILE
+#include MICROPY_PY_TIME_INCLUDEFILE
+#endif
+
+#if MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME
+
+#include "shared/timeutils/timeutils.h"
+
+// localtime([secs])
+// Convert a time expressed in seconds since the Epoch into an 8-tuple which
+// contains: (year, month, mday, hour, minute, second, weekday, yearday)
+// If secs is not provided or None, then the current time is used.
+// - year is the full year, eg 2000
+// - month is 1-12
+// - mday is 1-31
+// - hour is 0-23
+// - minute is 0-59
+// - second is 0-59
+// - weekday is 0-6 for Mon-Sun
+// - yearday is 1-366
+STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0 || args[0] == mp_const_none) {
+ // Get current date and time.
+ return mp_time_localtime_get();
+ } else {
+ // Convert given seconds to tuple.
+ mp_int_t seconds = mp_obj_get_int(args[0]);
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
+ mp_obj_t tuple[8] = {
+ tuple[0] = mp_obj_new_int(tm.tm_year),
+ tuple[1] = mp_obj_new_int(tm.tm_mon),
+ tuple[2] = mp_obj_new_int(tm.tm_mday),
+ tuple[3] = mp_obj_new_int(tm.tm_hour),
+ tuple[4] = mp_obj_new_int(tm.tm_min),
+ tuple[5] = mp_obj_new_int(tm.tm_sec),
+ tuple[6] = mp_obj_new_int(tm.tm_wday),
+ tuple[7] = mp_obj_new_int(tm.tm_yday),
+ };
+ return mp_obj_new_tuple(8, tuple);
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_time_localtime_obj, 0, 1, time_localtime);
+
+// mktime()
+// This is the inverse function of localtime. Its argument is a full 8-tuple
+// which expresses a time as per localtime. It returns an integer which is
+// the number of seconds since the Epoch (eg 1st Jan 1970, or 1st Jan 2000).
+STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
+ size_t len;
+ mp_obj_t *elem;
+ mp_obj_get_array(tuple, &len, &elem);
+
+ // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
+ if (len < 8 || len > 9) {
+ mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
+ }
+
+ return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
+ mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
+ mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_time_mktime_obj, time_mktime);
+
+#endif // MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME
+
+#if MICROPY_PY_TIME_TIME_TIME_NS
+
+// time()
+// Return the number of seconds since the Epoch.
+STATIC mp_obj_t time_time(void) {
+ return mp_time_time_get();
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_time_time_obj, time_time);
+
+// time_ns()
+// Returns the number of nanoseconds since the Epoch, as an integer.
+STATIC mp_obj_t time_time_ns(void) {
+ return mp_obj_new_int_from_ull(mp_hal_time_ns());
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_time_time_ns_obj, time_time_ns);
+
+#endif // MICROPY_PY_TIME_TIME_TIME_NS
+
+STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
+ #ifdef MICROPY_PY_TIME_CUSTOM_SLEEP
+ mp_time_sleep(seconds_o);
+ #else
+ #if MICROPY_PY_BUILTINS_FLOAT
+ mp_hal_delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o)));
+ #else
+ mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));
+ #endif
+ #endif
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_time_sleep_obj, time_sleep);
+
+STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
+ mp_int_t ms = mp_obj_get_int(arg);
+ if (ms >= 0) {
+ mp_hal_delay_ms(ms);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_time_sleep_ms_obj, time_sleep_ms);
+
+STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
+ mp_int_t us = mp_obj_get_int(arg);
+ if (us > 0) {
+ mp_hal_delay_us(us);
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(mp_time_sleep_us_obj, time_sleep_us);
+
+STATIC mp_obj_t time_ticks_ms(void) {
+ return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_TIME_TICKS_PERIOD - 1));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_time_ticks_ms_obj, time_ticks_ms);
+
+STATIC mp_obj_t time_ticks_us(void) {
+ return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_TIME_TICKS_PERIOD - 1));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_time_ticks_us_obj, time_ticks_us);
+
+STATIC mp_obj_t time_ticks_cpu(void) {
+ return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_TIME_TICKS_PERIOD - 1));
+}
+MP_DEFINE_CONST_FUN_OBJ_0(mp_time_ticks_cpu_obj, time_ticks_cpu);
+
+STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) {
+ // we assume that the arguments come from ticks_xx so are small ints
+ mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
+ mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
+ // Optimized formula avoiding if conditions. We adjust difference "forward",
+ // wrap it around and adjust back.
+ mp_int_t diff = ((end - start + MICROPY_PY_TIME_TICKS_PERIOD / 2) & (MICROPY_PY_TIME_TICKS_PERIOD - 1))
+ - MICROPY_PY_TIME_TICKS_PERIOD / 2;
+ return MP_OBJ_NEW_SMALL_INT(diff);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mp_time_ticks_diff_obj, time_ticks_diff);
+
+STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {
+ // we assume that first argument come from ticks_xx so is small int
+ mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in);
+ mp_uint_t delta = mp_obj_get_int(delta_in);
+
+ // Check that delta does not overflow the range that ticks_diff can handle.
+ // This ensures the following:
+ // - ticks_diff(ticks_add(T, delta), T) == delta
+ // - ticks_diff(T, ticks_add(T, delta)) == -delta
+ // The latter requires excluding delta=-TICKS_PERIOD/2.
+ //
+ // This unsigned comparison is equivalent to a signed comparison of:
+ // delta <= -TICKS_PERIOD/2 || delta >= TICKS_PERIOD/2
+ if (delta + MICROPY_PY_TIME_TICKS_PERIOD / 2 - 1 >= MICROPY_PY_TIME_TICKS_PERIOD - 1) {
+ mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ticks interval overflow"));
+ }
+
+ return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_TIME_TICKS_PERIOD - 1));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(mp_time_ticks_add_obj, time_ticks_add);
+
+STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) },
+
+ #if MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME
+ { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&mp_time_localtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mp_time_localtime_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mp_time_mktime_obj) },
+ #endif
+
+ #if MICROPY_PY_TIME_TIME_TIME_NS
+ { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_time_time_obj) },
+ { MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_time_time_ns_obj) },
+ #endif
+
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_time_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_time_sleep_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_time_sleep_us_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_time_ticks_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_time_ticks_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_time_ticks_cpu_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_time_ticks_add_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_time_ticks_diff_obj) },
+
+ #ifdef MICROPY_PY_TIME_EXTRA_GLOBALS
+ MICROPY_PY_TIME_EXTRA_GLOBALS
+ #endif
+};
+STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table);
+
+const mp_obj_module_t mp_module_time = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&mp_module_time_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_time, mp_module_time);
+
+#endif // MICROPY_PY_TIME
diff --git a/extmod/modtime.h b/extmod/modtime.h
new file mode 100644
index 000000000000..f5ea6b55bf30
--- /dev/null
+++ b/extmod/modtime.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2016 Damien P. George
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_EXTMOD_MODUTIME_H
+#define MICROPY_INCLUDED_EXTMOD_MODUTIME_H
+
+#include "py/obj.h"
+
+MP_DECLARE_CONST_FUN_OBJ_1(mp_time_mktime_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mp_time_sleep_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mp_time_sleep_ms_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(mp_time_sleep_us_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(mp_time_ticks_ms_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(mp_time_ticks_us_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(mp_time_ticks_cpu_obj);
+MP_DECLARE_CONST_FUN_OBJ_2(mp_time_ticks_diff_obj);
+MP_DECLARE_CONST_FUN_OBJ_2(mp_time_ticks_add_obj);
+MP_DECLARE_CONST_FUN_OBJ_0(mp_time_time_ns_obj);
+
+#endif // MICROPY_INCLUDED_EXTMOD_MODUTIME_H
diff --git a/extmod/moduasyncio.c b/extmod/moduasyncio.c
deleted file mode 100644
index 021e0da1be2c..000000000000
--- a/extmod/moduasyncio.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2020 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/runtime.h"
-#include "py/smallint.h"
-#include "py/pairheap.h"
-#include "py/mphal.h"
-
-#if MICROPY_PY_UASYNCIO
-
-// Used when task cannot be guaranteed to be non-NULL.
-#define TASK_PAIRHEAP(task) ((task) ? &(task)->pairheap : NULL)
-
-#define TASK_STATE_RUNNING_NOT_WAITED_ON (mp_const_true)
-#define TASK_STATE_DONE_NOT_WAITED_ON (mp_const_none)
-#define TASK_STATE_DONE_WAS_WAITED_ON (mp_const_false)
-
-#define TASK_IS_DONE(task) ( \
- (task)->state == TASK_STATE_DONE_NOT_WAITED_ON \
- || (task)->state == TASK_STATE_DONE_WAS_WAITED_ON)
-
-typedef struct _mp_obj_task_t {
- mp_pairheap_t pairheap;
- mp_obj_t coro;
- mp_obj_t data;
- mp_obj_t state;
- mp_obj_t ph_key;
-} mp_obj_task_t;
-
-typedef struct _mp_obj_task_queue_t {
- mp_obj_base_t base;
- mp_obj_task_t *heap;
-} mp_obj_task_queue_t;
-
-STATIC const mp_obj_type_t task_queue_type;
-STATIC const mp_obj_type_t task_type;
-
-STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
-
-/******************************************************************************/
-// Ticks for task ordering in pairing heap
-
-STATIC mp_obj_t ticks(void) {
- return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
-
-STATIC mp_int_t ticks_diff(mp_obj_t t1_in, mp_obj_t t0_in) {
- mp_uint_t t0 = MP_OBJ_SMALL_INT_VALUE(t0_in);
- mp_uint_t t1 = MP_OBJ_SMALL_INT_VALUE(t1_in);
- mp_int_t diff = ((t1 - t0 + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))
- - MICROPY_PY_UTIME_TICKS_PERIOD / 2;
- return diff;
-}
-
-STATIC int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) {
- mp_obj_task_t *t1 = (mp_obj_task_t *)n1;
- mp_obj_task_t *t2 = (mp_obj_task_t *)n2;
- return MP_OBJ_SMALL_INT_VALUE(ticks_diff(t1->ph_key, t2->ph_key)) < 0;
-}
-
-/******************************************************************************/
-// TaskQueue class
-
-STATIC mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- (void)args;
- mp_arg_check_num(n_args, n_kw, 0, 0, false);
- mp_obj_task_queue_t *self = mp_obj_malloc(mp_obj_task_queue_t, type);
- self->heap = (mp_obj_task_t *)mp_pairheap_new(task_lt);
- return MP_OBJ_FROM_PTR(self);
-}
-
-STATIC mp_obj_t task_queue_peek(mp_obj_t self_in) {
- mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->heap == NULL) {
- return mp_const_none;
- } else {
- return MP_OBJ_FROM_PTR(self->heap);
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_peek_obj, task_queue_peek);
-
-STATIC mp_obj_t task_queue_push(size_t n_args, const mp_obj_t *args) {
- mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(args[0]);
- mp_obj_task_t *task = MP_OBJ_TO_PTR(args[1]);
- task->data = mp_const_none;
- if (n_args == 2) {
- task->ph_key = ticks();
- } else {
- assert(mp_obj_is_small_int(args[2]));
- task->ph_key = args[2];
- }
- self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, TASK_PAIRHEAP(self->heap), TASK_PAIRHEAP(task));
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_obj, 2, 3, task_queue_push);
-
-STATIC mp_obj_t task_queue_pop(mp_obj_t self_in) {
- mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_task_t *head = (mp_obj_task_t *)mp_pairheap_peek(task_lt, &self->heap->pairheap);
- if (head == NULL) {
- mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
- }
- self->heap = (mp_obj_task_t *)mp_pairheap_pop(task_lt, &self->heap->pairheap);
- return MP_OBJ_FROM_PTR(head);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_queue_pop_obj, task_queue_pop);
-
-STATIC mp_obj_t task_queue_remove(mp_obj_t self_in, mp_obj_t task_in) {
- mp_obj_task_queue_t *self = MP_OBJ_TO_PTR(self_in);
- mp_obj_task_t *task = MP_OBJ_TO_PTR(task_in);
- self->heap = (mp_obj_task_t *)mp_pairheap_delete(task_lt, &self->heap->pairheap, &task->pairheap);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(task_queue_remove_obj, task_queue_remove);
-
-STATIC const mp_rom_map_elem_t task_queue_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_peek), MP_ROM_PTR(&task_queue_peek_obj) },
- { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&task_queue_push_obj) },
- { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&task_queue_pop_obj) },
- { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&task_queue_remove_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(task_queue_locals_dict, task_queue_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- task_queue_type,
- MP_QSTR_TaskQueue,
- MP_TYPE_FLAG_NONE,
- make_new, task_queue_make_new,
- locals_dict, &task_queue_locals_dict
- );
-
-/******************************************************************************/
-// Task class
-
-// This is the core uasyncio context with cur_task, _task_queue and CancelledError.
-STATIC mp_obj_t uasyncio_context = MP_OBJ_NULL;
-
-STATIC mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 2, false);
- mp_obj_task_t *self = m_new_obj(mp_obj_task_t);
- self->pairheap.base.type = type;
- mp_pairheap_init_node(task_lt, &self->pairheap);
- self->coro = args[0];
- self->data = mp_const_none;
- self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
- self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
- if (n_args == 2) {
- uasyncio_context = args[1];
- }
- return MP_OBJ_FROM_PTR(self);
-}
-
-STATIC mp_obj_t task_done(mp_obj_t self_in) {
- mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
- return mp_obj_new_bool(TASK_IS_DONE(self));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_done_obj, task_done);
-
-STATIC mp_obj_t task_cancel(mp_obj_t self_in) {
- mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
- // Check if task is already finished.
- if (TASK_IS_DONE(self)) {
- return mp_const_false;
- }
- // Can't cancel self (not supported yet).
- mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
- if (self_in == cur_task) {
- mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
- }
- // If Task waits on another task then forward the cancel to the one it's waiting on.
- while (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(self->data)), MP_OBJ_FROM_PTR(&task_type))) {
- self = MP_OBJ_TO_PTR(self->data);
- }
-
- mp_obj_t _task_queue = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
-
- // Reschedule Task as a cancelled task.
- mp_obj_t dest[3];
- mp_load_method_maybe(self->data, MP_QSTR_remove, dest);
- if (dest[0] != MP_OBJ_NULL) {
- // Not on the main running queue, remove the task from the queue it's on.
- dest[2] = MP_OBJ_FROM_PTR(self);
- mp_call_method_n_kw(1, 0, dest);
- // _task_queue.push(self)
- dest[0] = _task_queue;
- dest[1] = MP_OBJ_FROM_PTR(self);
- task_queue_push(2, dest);
- } else if (ticks_diff(self->ph_key, ticks()) > 0) {
- // On the main running queue but scheduled in the future, so bring it forward to now.
- // _task_queue.remove(self)
- task_queue_remove(_task_queue, MP_OBJ_FROM_PTR(self));
- // _task_queue.push(self)
- dest[0] = _task_queue;
- dest[1] = MP_OBJ_FROM_PTR(self);
- task_queue_push(2, dest);
- }
-
- self->data = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
-
- return mp_const_true;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(task_cancel_obj, task_cancel);
-
-STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
- mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
- if (dest[0] == MP_OBJ_NULL) {
- // Load
- if (attr == MP_QSTR_coro) {
- dest[0] = self->coro;
- } else if (attr == MP_QSTR_data) {
- dest[0] = self->data;
- } else if (attr == MP_QSTR_state) {
- dest[0] = self->state;
- } else if (attr == MP_QSTR_done) {
- dest[0] = MP_OBJ_FROM_PTR(&task_done_obj);
- dest[1] = self_in;
- } else if (attr == MP_QSTR_cancel) {
- dest[0] = MP_OBJ_FROM_PTR(&task_cancel_obj);
- dest[1] = self_in;
- } else if (attr == MP_QSTR_ph_key) {
- dest[0] = self->ph_key;
- }
- } else if (dest[1] != MP_OBJ_NULL) {
- // Store
- if (attr == MP_QSTR_data) {
- self->data = dest[1];
- dest[0] = MP_OBJ_NULL;
- } else if (attr == MP_QSTR_state) {
- self->state = dest[1];
- dest[0] = MP_OBJ_NULL;
- }
- }
-}
-
-STATIC mp_obj_t task_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
- (void)iter_buf;
- mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
- if (TASK_IS_DONE(self)) {
- // Signal that the completed-task has been await'ed on.
- self->state = TASK_STATE_DONE_WAS_WAITED_ON;
- } else if (self->state == TASK_STATE_RUNNING_NOT_WAITED_ON) {
- // Allocate the waiting queue.
- self->state = task_queue_make_new(&task_queue_type, 0, 0, NULL);
- } else if (mp_obj_get_type(self->state) != &task_queue_type) {
- // Task has state used for another purpose, so can't also wait on it.
- mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't wait"));
- }
- return self_in;
-}
-
-STATIC mp_obj_t task_iternext(mp_obj_t self_in) {
- mp_obj_task_t *self = MP_OBJ_TO_PTR(self_in);
- if (TASK_IS_DONE(self)) {
- // Task finished, raise return value to caller so it can continue.
- nlr_raise(self->data);
- } else {
- // Put calling task on waiting queue.
- mp_obj_t cur_task = mp_obj_dict_get(uasyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
- mp_obj_t args[2] = { self->state, cur_task };
- task_queue_push(2, args);
- // Set calling task's data to this task that it waits on, to double-link it.
- ((mp_obj_task_t *)MP_OBJ_TO_PTR(cur_task))->data = self_in;
- }
- return mp_const_none;
-}
-
-STATIC const mp_getiter_iternext_custom_t task_getiter_iternext = {
- .getiter = task_getiter,
- .iternext = task_iternext,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- task_type,
- MP_QSTR_Task,
- MP_TYPE_FLAG_ITER_IS_CUSTOM,
- make_new, task_make_new,
- attr, task_attr,
- iter, &task_getiter_iternext
- );
-
-/******************************************************************************/
-// C-level uasyncio module
-
-STATIC const mp_rom_map_elem_t mp_module_uasyncio_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__uasyncio) },
- { MP_ROM_QSTR(MP_QSTR_TaskQueue), MP_ROM_PTR(&task_queue_type) },
- { MP_ROM_QSTR(MP_QSTR_Task), MP_ROM_PTR(&task_type) },
-};
-STATIC MP_DEFINE_CONST_DICT(mp_module_uasyncio_globals, mp_module_uasyncio_globals_table);
-
-const mp_obj_module_t mp_module_uasyncio = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_uasyncio_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR__uasyncio, mp_module_uasyncio);
-
-#endif // MICROPY_PY_UASYNCIO
diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c
deleted file mode 100644
index 45a39c58d443..000000000000
--- a/extmod/modubinascii.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/runtime.h"
-#include "py/binary.h"
-#include "py/objstr.h"
-
-#if MICROPY_PY_UBINASCII
-
-#if MICROPY_PY_BUILTINS_BYTES_HEX
-STATIC mp_obj_t bytes_hex_as_bytes(size_t n_args, const mp_obj_t *args) {
- return mp_obj_bytes_hex(n_args, args, &mp_type_bytes);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bytes_hex_as_bytes_obj, 1, 2, bytes_hex_as_bytes);
-
-STATIC mp_obj_t bytes_fromhex_bytes(mp_obj_t data) {
- return mp_obj_bytes_fromhex(MP_OBJ_FROM_PTR(&mp_type_bytes), data);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(bytes_fromhex_obj, bytes_fromhex_bytes);
-#endif
-
-// If ch is a character in the base64 alphabet, and is not a pad character, then
-// the corresponding integer between 0 and 63, inclusively, is returned.
-// Otherwise, -1 is returned.
-static int mod_binascii_sextet(byte ch) {
- if (ch >= 'A' && ch <= 'Z') {
- return ch - 'A';
- } else if (ch >= 'a' && ch <= 'z') {
- return ch - 'a' + 26;
- } else if (ch >= '0' && ch <= '9') {
- return ch - '0' + 52;
- } else if (ch == '+') {
- return 62;
- } else if (ch == '/') {
- return 63;
- } else {
- return -1;
- }
-}
-
-STATIC mp_obj_t mod_binascii_a2b_base64(mp_obj_t data) {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
- byte *in = bufinfo.buf;
-
- vstr_t vstr;
- vstr_init(&vstr, (bufinfo.len / 4) * 3 + 1); // Potentially over-allocate
- byte *out = (byte *)vstr.buf;
-
- uint shift = 0;
- int nbits = 0; // Number of meaningful bits in shift
- bool hadpad = false; // Had a pad character since last valid character
- for (size_t i = 0; i < bufinfo.len; i++) {
- if (in[i] == '=') {
- if ((nbits == 2) || ((nbits == 4) && hadpad)) {
- nbits = 0;
- break;
- }
- hadpad = true;
- }
-
- int sextet = mod_binascii_sextet(in[i]);
- if (sextet == -1) {
- continue;
- }
- hadpad = false;
- shift = (shift << 6) | sextet;
- nbits += 6;
-
- if (nbits >= 8) {
- nbits -= 8;
- out[vstr.len++] = (shift >> nbits) & 0xFF;
- }
- }
-
- if (nbits) {
- mp_raise_ValueError(MP_ERROR_TEXT("incorrect padding"));
- }
-
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj, mod_binascii_a2b_base64);
-
-STATIC mp_obj_t mod_binascii_b2a_base64(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_newline };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_newline, MP_ARG_BOOL, {.u_bool = true} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- uint8_t newline = args[ARG_newline].u_bool;
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(pos_args[0], &bufinfo, MP_BUFFER_READ);
-
- vstr_t vstr;
- vstr_init_len(&vstr, ((bufinfo.len != 0) ? (((bufinfo.len - 1) / 3) + 1) * 4 : 0) + newline);
-
- // First pass, we convert input buffer to numeric base 64 values
- byte *in = bufinfo.buf, *out = (byte *)vstr.buf;
- mp_uint_t i;
- for (i = bufinfo.len; i >= 3; i -= 3) {
- *out++ = (in[0] & 0xFC) >> 2;
- *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
- *out++ = (in[1] & 0x0F) << 2 | (in[2] & 0xC0) >> 6;
- *out++ = in[2] & 0x3F;
- in += 3;
- }
- if (i != 0) {
- *out++ = (in[0] & 0xFC) >> 2;
- if (i == 2) {
- *out++ = (in[0] & 0x03) << 4 | (in[1] & 0xF0) >> 4;
- *out++ = (in[1] & 0x0F) << 2;
- } else {
- *out++ = (in[0] & 0x03) << 4;
- *out++ = 64;
- }
- *out = 64;
- }
-
- // Second pass, we convert number base 64 values to actual base64 ascii encoding
- out = (byte *)vstr.buf;
- for (mp_uint_t j = vstr.len - newline; j--;) {
- if (*out < 26) {
- *out += 'A';
- } else if (*out < 52) {
- *out += 'a' - 26;
- } else if (*out < 62) {
- *out += '0' - 52;
- } else if (*out == 62) {
- *out = '+';
- } else if (*out == 63) {
- *out = '/';
- } else {
- *out = '=';
- }
- out++;
- }
- if (newline) {
- *out = '\n';
- }
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_binascii_b2a_base64_obj, 1, mod_binascii_b2a_base64);
-
-#if MICROPY_PY_UBINASCII_CRC32
-#include "lib/uzlib/tinf.h"
-
-STATIC mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
- uint32_t crc = (n_args > 1) ? mp_obj_get_int_truncated(args[1]) : 0;
- crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff);
- return mp_obj_new_int_from_uint(crc ^ 0xffffffff);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32);
-#endif
-
-STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ubinascii) },
- #if MICROPY_PY_BUILTINS_BYTES_HEX
- { MP_ROM_QSTR(MP_QSTR_hexlify), MP_ROM_PTR(&bytes_hex_as_bytes_obj) },
- { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&bytes_fromhex_obj) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) },
- { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) },
- #if MICROPY_PY_UBINASCII_CRC32
- { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table);
-
-const mp_obj_module_t mp_module_ubinascii = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_binascii_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ubinascii, mp_module_ubinascii);
-
-#endif // MICROPY_PY_UBINASCII
diff --git a/extmod/moducryptolib.c b/extmod/moducryptolib.c
deleted file mode 100644
index fc3fcfd90d90..000000000000
--- a/extmod/moducryptolib.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017-2018 Paul Sokolovsky
- * Copyright (c) 2018 Yonatan Goldschmidt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-
-#if MICROPY_PY_UCRYPTOLIB
-
-#include
-#include
-
-#include "py/runtime.h"
-
-// This module implements crypto ciphers API, roughly following
-// https://www.python.org/dev/peps/pep-0272/ . Exact implementation
-// of PEP 272 can be made with a simple wrapper which adds all the
-// needed boilerplate.
-
-// values follow PEP 272
-enum {
- UCRYPTOLIB_MODE_ECB = 1,
- UCRYPTOLIB_MODE_CBC = 2,
- UCRYPTOLIB_MODE_CTR = 6,
-};
-
-struct ctr_params {
- // counter is the IV of the AES context.
-
- size_t offset; // in encrypted_counter
- // encrypted counter
- uint8_t encrypted_counter[16];
-};
-
-#if MICROPY_SSL_AXTLS
-#include "lib/axtls/crypto/crypto.h"
-
-#define AES_CTX_IMPL AES_CTX
-#endif
-
-#if MICROPY_SSL_MBEDTLS
-#include
-
-// we can't run mbedtls AES key schedule until we know whether we're used for encrypt or decrypt.
-// therefore, we store the key & keysize and on the first call to encrypt/decrypt we override them
-// with the mbedtls_aes_context, as they are not longer required. (this is done to save space)
-struct mbedtls_aes_ctx_with_key {
- union {
- mbedtls_aes_context mbedtls_ctx;
- struct {
- uint8_t key[32];
- uint8_t keysize;
- } init_data;
- } u;
- unsigned char iv[16];
-};
-#define AES_CTX_IMPL struct mbedtls_aes_ctx_with_key
-#endif
-
-typedef struct _mp_obj_aes_t {
- mp_obj_base_t base;
- AES_CTX_IMPL ctx;
- uint8_t block_mode : 6;
-#define AES_KEYTYPE_NONE 0
-#define AES_KEYTYPE_ENC 1
-#define AES_KEYTYPE_DEC 2
- uint8_t key_type : 2;
-} mp_obj_aes_t;
-
-static inline bool is_ctr_mode(int block_mode) {
- #if MICROPY_PY_UCRYPTOLIB_CTR
- return block_mode == UCRYPTOLIB_MODE_CTR;
- #else
- return false;
- #endif
-}
-
-static inline struct ctr_params *ctr_params_from_aes(mp_obj_aes_t *o) {
- // ctr_params follows aes object struct
- return (struct ctr_params *)&o[1];
-}
-
-#if MICROPY_SSL_AXTLS
-STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
- assert(16 == keysize || 32 == keysize);
- AES_set_key(ctx, key, iv, (16 == keysize) ? AES_MODE_128 : AES_MODE_256);
-}
-
-STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
- if (!encrypt) {
- AES_convert_key(ctx);
- }
-}
-
-STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
- memcpy(out, in, 16);
- // We assume that out (vstr.buf or given output buffer) is uint32_t aligned
- uint32_t *p = (uint32_t *)out;
- // axTLS likes it weird and complicated with byteswaps
- for (int i = 0; i < 4; i++) {
- p[i] = MP_HTOBE32(p[i]);
- }
- if (encrypt) {
- AES_encrypt(ctx, p);
- } else {
- AES_decrypt(ctx, p);
- }
- for (int i = 0; i < 4; i++) {
- p[i] = MP_BE32TOH(p[i]);
- }
-}
-
-STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
- if (encrypt) {
- AES_cbc_encrypt(ctx, in, out, in_len);
- } else {
- AES_cbc_decrypt(ctx, in, out, in_len);
- }
-}
-
-#if MICROPY_PY_UCRYPTOLIB_CTR
-// axTLS doesn't have CTR support out of the box. This implements the counter part using the ECB primitive.
-STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
- size_t n = ctr_params->offset;
- uint8_t *const counter = ctx->iv;
-
- while (in_len--) {
- if (n == 0) {
- aes_process_ecb_impl(ctx, counter, ctr_params->encrypted_counter, true);
-
- // increment the 128-bit counter
- for (int i = 15; i >= 0; --i) {
- if (++counter[i] != 0) {
- break;
- }
- }
- }
-
- *out++ = *in++ ^ ctr_params->encrypted_counter[n];
- n = (n + 1) & 0xf;
- }
-
- ctr_params->offset = n;
-}
-#endif
-
-#endif
-
-#if MICROPY_SSL_MBEDTLS
-STATIC void aes_initial_set_key_impl(AES_CTX_IMPL *ctx, const uint8_t *key, size_t keysize, const uint8_t iv[16]) {
- ctx->u.init_data.keysize = keysize;
- memcpy(ctx->u.init_data.key, key, keysize);
-
- if (NULL != iv) {
- memcpy(ctx->iv, iv, sizeof(ctx->iv));
- }
-}
-
-STATIC void aes_final_set_key_impl(AES_CTX_IMPL *ctx, bool encrypt) {
- // first, copy key aside
- uint8_t key[32];
- uint8_t keysize = ctx->u.init_data.keysize;
- memcpy(key, ctx->u.init_data.key, keysize);
- // now, override key with the mbedtls context object
- mbedtls_aes_init(&ctx->u.mbedtls_ctx);
-
- // setkey call will succeed, we've already checked the keysize earlier.
- assert(16 == keysize || 32 == keysize);
- if (encrypt) {
- mbedtls_aes_setkey_enc(&ctx->u.mbedtls_ctx, key, keysize * 8);
- } else {
- mbedtls_aes_setkey_dec(&ctx->u.mbedtls_ctx, key, keysize * 8);
- }
-}
-
-STATIC void aes_process_ecb_impl(AES_CTX_IMPL *ctx, const uint8_t in[16], uint8_t out[16], bool encrypt) {
- mbedtls_aes_crypt_ecb(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in, out);
-}
-
-STATIC void aes_process_cbc_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, bool encrypt) {
- mbedtls_aes_crypt_cbc(&ctx->u.mbedtls_ctx, encrypt ? MBEDTLS_AES_ENCRYPT : MBEDTLS_AES_DECRYPT, in_len, ctx->iv, in, out);
-}
-
-#if MICROPY_PY_UCRYPTOLIB_CTR
-STATIC void aes_process_ctr_impl(AES_CTX_IMPL *ctx, const uint8_t *in, uint8_t *out, size_t in_len, struct ctr_params *ctr_params) {
- mbedtls_aes_crypt_ctr(&ctx->u.mbedtls_ctx, in_len, &ctr_params->offset, ctx->iv, ctr_params->encrypted_counter, in, out);
-}
-#endif
-
-#endif
-
-STATIC mp_obj_t ucryptolib_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 2, 3, false);
-
- const mp_int_t block_mode = mp_obj_get_int(args[1]);
-
- switch (block_mode) {
- case UCRYPTOLIB_MODE_ECB:
- case UCRYPTOLIB_MODE_CBC:
- #if MICROPY_PY_UCRYPTOLIB_CTR
- case UCRYPTOLIB_MODE_CTR:
- #endif
- break;
-
- default:
- mp_raise_ValueError(MP_ERROR_TEXT("mode"));
- }
-
- mp_obj_aes_t *o = mp_obj_malloc_var(mp_obj_aes_t, struct ctr_params, !!is_ctr_mode(block_mode), type);
-
- o->block_mode = block_mode;
- o->key_type = AES_KEYTYPE_NONE;
-
- mp_buffer_info_t keyinfo;
- mp_get_buffer_raise(args[0], &keyinfo, MP_BUFFER_READ);
- if (32 != keyinfo.len && 16 != keyinfo.len) {
- mp_raise_ValueError(MP_ERROR_TEXT("key"));
- }
-
- mp_buffer_info_t ivinfo;
- ivinfo.buf = NULL;
- if (n_args > 2 && args[2] != mp_const_none) {
- mp_get_buffer_raise(args[2], &ivinfo, MP_BUFFER_READ);
-
- if (16 != ivinfo.len) {
- mp_raise_ValueError(MP_ERROR_TEXT("IV"));
- }
- } else if (o->block_mode == UCRYPTOLIB_MODE_CBC || is_ctr_mode(o->block_mode)) {
- mp_raise_ValueError(MP_ERROR_TEXT("IV"));
- }
-
- if (is_ctr_mode(block_mode)) {
- ctr_params_from_aes(o)->offset = 0;
- }
-
- aes_initial_set_key_impl(&o->ctx, keyinfo.buf, keyinfo.len, ivinfo.buf);
-
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t aes_process(size_t n_args, const mp_obj_t *args, bool encrypt) {
- mp_obj_aes_t *self = MP_OBJ_TO_PTR(args[0]);
-
- mp_obj_t in_buf = args[1];
- mp_obj_t out_buf = MP_OBJ_NULL;
- if (n_args > 2) {
- out_buf = args[2];
- }
-
- mp_buffer_info_t in_bufinfo;
- mp_get_buffer_raise(in_buf, &in_bufinfo, MP_BUFFER_READ);
-
- if (!is_ctr_mode(self->block_mode) && in_bufinfo.len % 16 != 0) {
- mp_raise_ValueError(MP_ERROR_TEXT("blksize % 16"));
- }
-
- vstr_t vstr;
- mp_buffer_info_t out_bufinfo;
- uint8_t *out_buf_ptr;
-
- if (out_buf != MP_OBJ_NULL) {
- mp_get_buffer_raise(out_buf, &out_bufinfo, MP_BUFFER_WRITE);
- if (out_bufinfo.len < in_bufinfo.len) {
- mp_raise_ValueError(MP_ERROR_TEXT("output too small"));
- }
- out_buf_ptr = out_bufinfo.buf;
- } else {
- vstr_init_len(&vstr, in_bufinfo.len);
- out_buf_ptr = (uint8_t *)vstr.buf;
- }
-
- if (AES_KEYTYPE_NONE == self->key_type) {
- // always set key for encryption if CTR mode.
- const bool encrypt_mode = encrypt || is_ctr_mode(self->block_mode);
- aes_final_set_key_impl(&self->ctx, encrypt_mode);
- self->key_type = encrypt ? AES_KEYTYPE_ENC : AES_KEYTYPE_DEC;
- } else {
- if ((encrypt && self->key_type == AES_KEYTYPE_DEC) ||
- (!encrypt && self->key_type == AES_KEYTYPE_ENC)) {
-
- mp_raise_ValueError(MP_ERROR_TEXT("can't encrypt & decrypt"));
- }
- }
-
- switch (self->block_mode) {
- case UCRYPTOLIB_MODE_ECB: {
- uint8_t *in = in_bufinfo.buf, *out = out_buf_ptr;
- uint8_t *top = in + in_bufinfo.len;
- for (; in < top; in += 16, out += 16) {
- aes_process_ecb_impl(&self->ctx, in, out, encrypt);
- }
- break;
- }
-
- case UCRYPTOLIB_MODE_CBC:
- aes_process_cbc_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len, encrypt);
- break;
-
- #if MICROPY_PY_UCRYPTOLIB_CTR
- case UCRYPTOLIB_MODE_CTR:
- aes_process_ctr_impl(&self->ctx, in_bufinfo.buf, out_buf_ptr, in_bufinfo.len,
- ctr_params_from_aes(self));
- break;
- #endif
- }
-
- if (out_buf != MP_OBJ_NULL) {
- return out_buf;
- }
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-
-STATIC mp_obj_t ucryptolib_aes_encrypt(size_t n_args, const mp_obj_t *args) {
- return aes_process(n_args, args, true);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_encrypt_obj, 2, 3, ucryptolib_aes_encrypt);
-
-STATIC mp_obj_t ucryptolib_aes_decrypt(size_t n_args, const mp_obj_t *args) {
- return aes_process(n_args, args, false);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ucryptolib_aes_decrypt_obj, 2, 3, ucryptolib_aes_decrypt);
-
-STATIC const mp_rom_map_elem_t ucryptolib_aes_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&ucryptolib_aes_encrypt_obj) },
- { MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&ucryptolib_aes_decrypt_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(ucryptolib_aes_locals_dict, ucryptolib_aes_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- ucryptolib_aes_type,
- MP_QSTR_aes,
- MP_TYPE_FLAG_NONE,
- make_new, ucryptolib_aes_make_new,
- locals_dict, &ucryptolib_aes_locals_dict
- );
-
-STATIC const mp_rom_map_elem_t mp_module_ucryptolib_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ucryptolib) },
- { MP_ROM_QSTR(MP_QSTR_aes), MP_ROM_PTR(&ucryptolib_aes_type) },
- #if MICROPY_PY_UCRYPTOLIB_CONSTS
- { MP_ROM_QSTR(MP_QSTR_MODE_ECB), MP_ROM_INT(UCRYPTOLIB_MODE_ECB) },
- { MP_ROM_QSTR(MP_QSTR_MODE_CBC), MP_ROM_INT(UCRYPTOLIB_MODE_CBC) },
- #if MICROPY_PY_UCRYPTOLIB_CTR
- { MP_ROM_QSTR(MP_QSTR_MODE_CTR), MP_ROM_INT(UCRYPTOLIB_MODE_CTR) },
- #endif
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_ucryptolib_globals, mp_module_ucryptolib_globals_table);
-
-const mp_obj_module_t mp_module_ucryptolib = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_ucryptolib_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ucryptolib, mp_module_ucryptolib);
-
-#endif // MICROPY_PY_UCRYPTOLIB
diff --git a/extmod/moductypes.c b/extmod/moductypes.c
index 15c36290a9f0..63be621fbcbe 100644
--- a/extmod/moductypes.c
+++ b/extmod/moductypes.c
@@ -582,7 +582,7 @@ STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_ob
STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in);
switch (op) {
- case MP_UNARY_OP_INT:
+ case MP_UNARY_OP_INT_MAYBE:
if (mp_obj_is_type(self->desc, &mp_type_tuple)) {
mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc);
mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]);
@@ -718,6 +718,8 @@ const mp_obj_module_t mp_module_uctypes = {
.globals = (mp_obj_dict_t *)&mp_module_uctypes_globals,
};
+// uctypes is not a Python standard library module (hence "uctypes"
+// not "ctypes") and therefore shouldn't be extensible.
MP_REGISTER_MODULE(MP_QSTR_uctypes, mp_module_uctypes);
#endif
diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c
deleted file mode 100644
index 64e15c444df8..000000000000
--- a/extmod/moduhashlib.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/runtime.h"
-
-#if MICROPY_PY_UHASHLIB
-
-#if MICROPY_SSL_MBEDTLS
-#include "mbedtls/version.h"
-#endif
-
-#if MICROPY_PY_UHASHLIB_SHA256
-
-#if MICROPY_SSL_MBEDTLS
-#include "mbedtls/sha256.h"
-#else
-#include "lib/crypto-algorithms/sha256.h"
-#endif
-
-#endif
-
-#if MICROPY_PY_UHASHLIB_SHA1 || MICROPY_PY_UHASHLIB_MD5
-
-#if MICROPY_SSL_AXTLS
-#include "lib/axtls/crypto/crypto.h"
-#endif
-
-#if MICROPY_SSL_MBEDTLS
-#include "mbedtls/md5.h"
-#include "mbedtls/sha1.h"
-#endif
-
-#endif
-
-typedef struct _mp_obj_hash_t {
- mp_obj_base_t base;
- bool final; // if set, update and digest raise an exception
- uintptr_t state[0]; // must be aligned to a machine word
-} mp_obj_hash_t;
-
-static void uhashlib_ensure_not_final(mp_obj_hash_t *self) {
- if (self->final) {
- mp_raise_ValueError(MP_ERROR_TEXT("hash is final"));
- }
-}
-
-#if MICROPY_PY_UHASHLIB_SHA256
-STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
-
-#if MICROPY_SSL_MBEDTLS
-
-#if MBEDTLS_VERSION_NUMBER < 0x02070000
-#define mbedtls_sha256_starts_ret mbedtls_sha256_starts
-#define mbedtls_sha256_update_ret mbedtls_sha256_update
-#define mbedtls_sha256_finish_ret mbedtls_sha256_finish
-#endif
-
-STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context), type);
- o->final = false;
- mbedtls_sha256_init((mbedtls_sha256_context *)&o->state);
- mbedtls_sha256_starts_ret((mbedtls_sha256_context *)&o->state, 0);
- if (n_args == 1) {
- uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- mbedtls_sha256_update_ret((mbedtls_sha256_context *)&self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, 32);
- mbedtls_sha256_finish_ret((mbedtls_sha256_context *)&self->state, (unsigned char *)vstr.buf);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-
-#else
-
-#include "lib/crypto-algorithms/sha256.c"
-
-STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX), type);
- o->final = false;
- sha256_init((CRYAL_SHA256_CTX *)o->state);
- if (n_args == 1) {
- uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- sha256_update((CRYAL_SHA256_CTX *)self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
- sha256_final((CRYAL_SHA256_CTX *)self->state, (byte *)vstr.buf);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-#endif
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest);
-
-STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- uhashlib_sha256_type,
- MP_QSTR_sha256,
- MP_TYPE_FLAG_NONE,
- make_new, uhashlib_sha256_make_new,
- locals_dict, &uhashlib_sha256_locals_dict
- );
-#endif
-
-#if MICROPY_PY_UHASHLIB_SHA1
-STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);
-
-#if MICROPY_SSL_AXTLS
-STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(SHA1_CTX), type);
- o->final = false;
- SHA1_Init((SHA1_CTX *)o->state);
- if (n_args == 1) {
- uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- SHA1_Update((SHA1_CTX *)self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, SHA1_SIZE);
- SHA1_Final((byte *)vstr.buf, (SHA1_CTX *)self->state);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-#endif
-
-#if MICROPY_SSL_MBEDTLS
-
-#if MBEDTLS_VERSION_NUMBER < 0x02070000
-#define mbedtls_sha1_starts_ret mbedtls_sha1_starts
-#define mbedtls_sha1_update_ret mbedtls_sha1_update
-#define mbedtls_sha1_finish_ret mbedtls_sha1_finish
-#endif
-
-STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context), type);
- o->final = false;
- mbedtls_sha1_init((mbedtls_sha1_context *)o->state);
- mbedtls_sha1_starts_ret((mbedtls_sha1_context *)o->state);
- if (n_args == 1) {
- uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- mbedtls_sha1_update_ret((mbedtls_sha1_context *)self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, 20);
- mbedtls_sha1_finish_ret((mbedtls_sha1_context *)self->state, (byte *)vstr.buf);
- mbedtls_sha1_free((mbedtls_sha1_context *)self->state);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-#endif
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest);
-
-STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- uhashlib_sha1_type,
- MP_QSTR_sha1,
- MP_TYPE_FLAG_NONE,
- make_new, uhashlib_sha1_make_new,
- locals_dict, &uhashlib_sha1_locals_dict
- );
-#endif
-
-#if MICROPY_PY_UHASHLIB_MD5
-STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg);
-
-#if MICROPY_SSL_AXTLS
-STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(MD5_CTX), type);
- o->final = false;
- MD5_Init((MD5_CTX *)o->state);
- if (n_args == 1) {
- uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- MD5_Update((MD5_CTX *)self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, MD5_SIZE);
- MD5_Final((byte *)vstr.buf, (MD5_CTX *)self->state);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-#endif // MICROPY_SSL_AXTLS
-
-#if MICROPY_SSL_MBEDTLS
-
-#if MBEDTLS_VERSION_NUMBER < 0x02070000
-#define mbedtls_md5_starts_ret mbedtls_md5_starts
-#define mbedtls_md5_update_ret mbedtls_md5_update
-#define mbedtls_md5_finish_ret mbedtls_md5_finish
-#endif
-
-STATIC mp_obj_t uhashlib_md5_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = mp_obj_malloc_var(mp_obj_hash_t, char, sizeof(mbedtls_md5_context), type);
- o->final = false;
- mbedtls_md5_init((mbedtls_md5_context *)o->state);
- mbedtls_md5_starts_ret((mbedtls_md5_context *)o->state);
- if (n_args == 1) {
- uhashlib_md5_update(MP_OBJ_FROM_PTR(o), args[0]);
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_obj_t uhashlib_md5_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
- mbedtls_md5_update_ret((mbedtls_md5_context *)self->state, bufinfo.buf, bufinfo.len);
- return mp_const_none;
-}
-
-STATIC mp_obj_t uhashlib_md5_digest(mp_obj_t self_in) {
- mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
- uhashlib_ensure_not_final(self);
- self->final = true;
- vstr_t vstr;
- vstr_init_len(&vstr, 16);
- mbedtls_md5_finish_ret((mbedtls_md5_context *)self->state, (byte *)vstr.buf);
- mbedtls_md5_free((mbedtls_md5_context *)self->state);
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-#endif // MICROPY_SSL_MBEDTLS
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_md5_update_obj, uhashlib_md5_update);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_md5_digest_obj, uhashlib_md5_digest);
-
-STATIC const mp_rom_map_elem_t uhashlib_md5_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_md5_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_md5_digest_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(uhashlib_md5_locals_dict, uhashlib_md5_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- uhashlib_md5_type,
- MP_QSTR_md5,
- MP_TYPE_FLAG_NONE,
- make_new, uhashlib_md5_make_new,
- locals_dict, &uhashlib_md5_locals_dict
- );
-#endif // MICROPY_PY_UHASHLIB_MD5
-
-STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) },
- #if MICROPY_PY_UHASHLIB_SHA256
- { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) },
- #endif
- #if MICROPY_PY_UHASHLIB_SHA1
- { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) },
- #endif
- #if MICROPY_PY_UHASHLIB_MD5
- { MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&uhashlib_md5_type) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table);
-
-const mp_obj_module_t mp_module_uhashlib = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_uhashlib_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uhashlib, mp_module_uhashlib);
-
-#endif // MICROPY_PY_UHASHLIB
diff --git a/extmod/moduheapq.c b/extmod/moduheapq.c
deleted file mode 100644
index bfa6ba608d33..000000000000
--- a/extmod/moduheapq.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/objlist.h"
-#include "py/runtime.h"
-
-#if MICROPY_PY_UHEAPQ
-
-// the algorithm here is modelled on CPython's heapq.py
-
-STATIC mp_obj_list_t *uheapq_get_heap(mp_obj_t heap_in) {
- if (!mp_obj_is_type(heap_in, &mp_type_list)) {
- mp_raise_TypeError(MP_ERROR_TEXT("heap must be a list"));
- }
- return MP_OBJ_TO_PTR(heap_in);
-}
-
-STATIC void uheapq_heap_siftdown(mp_obj_list_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
- mp_obj_t item = heap->items[pos];
- while (pos > start_pos) {
- mp_uint_t parent_pos = (pos - 1) >> 1;
- mp_obj_t parent = heap->items[parent_pos];
- if (mp_binary_op(MP_BINARY_OP_LESS, item, parent) == mp_const_true) {
- heap->items[pos] = parent;
- pos = parent_pos;
- } else {
- break;
- }
- }
- heap->items[pos] = item;
-}
-
-STATIC void uheapq_heap_siftup(mp_obj_list_t *heap, mp_uint_t pos) {
- mp_uint_t start_pos = pos;
- mp_uint_t end_pos = heap->len;
- mp_obj_t item = heap->items[pos];
- for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
- // choose right child if it's <= left child
- if (child_pos + 1 < end_pos && mp_binary_op(MP_BINARY_OP_LESS, heap->items[child_pos], heap->items[child_pos + 1]) == mp_const_false) {
- child_pos += 1;
- }
- // bubble up the smaller child
- heap->items[pos] = heap->items[child_pos];
- pos = child_pos;
- }
- heap->items[pos] = item;
- uheapq_heap_siftdown(heap, start_pos, pos);
-}
-
-STATIC mp_obj_t mod_uheapq_heappush(mp_obj_t heap_in, mp_obj_t item) {
- mp_obj_list_t *heap = uheapq_get_heap(heap_in);
- mp_obj_list_append(heap_in, item);
- uheapq_heap_siftdown(heap, 0, heap->len - 1);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_uheapq_heappush_obj, mod_uheapq_heappush);
-
-STATIC mp_obj_t mod_uheapq_heappop(mp_obj_t heap_in) {
- mp_obj_list_t *heap = uheapq_get_heap(heap_in);
- if (heap->len == 0) {
- mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
- }
- mp_obj_t item = heap->items[0];
- heap->len -= 1;
- heap->items[0] = heap->items[heap->len];
- heap->items[heap->len] = MP_OBJ_NULL; // so we don't retain a pointer
- if (heap->len) {
- uheapq_heap_siftup(heap, 0);
- }
- return item;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heappop_obj, mod_uheapq_heappop);
-
-STATIC mp_obj_t mod_uheapq_heapify(mp_obj_t heap_in) {
- mp_obj_list_t *heap = uheapq_get_heap(heap_in);
- for (mp_uint_t i = heap->len / 2; i > 0;) {
- uheapq_heap_siftup(heap, --i);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_uheapq_heapify_obj, mod_uheapq_heapify);
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t mp_module_uheapq_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheapq) },
- { MP_ROM_QSTR(MP_QSTR_heappush), MP_ROM_PTR(&mod_uheapq_heappush_obj) },
- { MP_ROM_QSTR(MP_QSTR_heappop), MP_ROM_PTR(&mod_uheapq_heappop_obj) },
- { MP_ROM_QSTR(MP_QSTR_heapify), MP_ROM_PTR(&mod_uheapq_heapify_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_uheapq_globals, mp_module_uheapq_globals_table);
-
-const mp_obj_module_t mp_module_uheapq = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_uheapq_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uheapq, mp_module_uheapq);
-#endif
-
-#endif // MICROPY_PY_UHEAPQ
diff --git a/extmod/modujson.c b/extmod/modujson.c
deleted file mode 100644
index 4e992e2245d1..000000000000
--- a/extmod/modujson.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-
-#include "py/objlist.h"
-#include "py/objstringio.h"
-#include "py/parsenum.h"
-#include "py/runtime.h"
-#include "py/stream.h"
-
-#if MICROPY_PY_UJSON
-
-#if MICROPY_PY_UJSON_SEPARATORS
-
-enum {
- DUMP_MODE_TO_STRING = 1,
- DUMP_MODE_TO_STREAM = 2,
-};
-
-STATIC mp_obj_t mod_ujson_dump_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, unsigned int mode) {
- enum { ARG_separators };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_separators, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- };
-
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - mode, pos_args + mode, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- mp_print_ext_t print_ext;
-
- if (args[ARG_separators].u_obj == mp_const_none) {
- print_ext.item_separator = ", ";
- print_ext.key_separator = ": ";
- } else {
- mp_obj_t *items;
- mp_obj_get_array_fixed_n(args[ARG_separators].u_obj, 2, &items);
- print_ext.item_separator = mp_obj_str_get_str(items[0]);
- print_ext.key_separator = mp_obj_str_get_str(items[1]);
- }
-
- if (mode == DUMP_MODE_TO_STRING) {
- // dumps(obj)
- vstr_t vstr;
- vstr_init_print(&vstr, 8, &print_ext.base);
- mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
- return mp_obj_new_str_from_utf8_vstr(&vstr);
- } else {
- // dump(obj, stream)
- print_ext.base.data = MP_OBJ_TO_PTR(pos_args[1]);
- print_ext.base.print_strn = mp_stream_write_adaptor;
- mp_get_stream_raise(pos_args[1], MP_STREAM_OP_WRITE);
- mp_obj_print_helper(&print_ext.base, pos_args[0], PRINT_JSON);
- return mp_const_none;
- }
-}
-
-STATIC mp_obj_t mod_ujson_dump(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- return mod_ujson_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STREAM);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dump_obj, 2, mod_ujson_dump);
-
-STATIC mp_obj_t mod_ujson_dumps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- return mod_ujson_dump_helper(n_args, pos_args, kw_args, DUMP_MODE_TO_STRING);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ujson_dumps_obj, 1, mod_ujson_dumps);
-
-#else
-
-STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
- mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
- mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
- mp_obj_print_helper(&print, obj, PRINT_JSON);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);
-
-STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
- vstr_t vstr;
- mp_print_t print;
- vstr_init_print(&vstr, 8, &print);
- mp_obj_print_helper(&print, obj, PRINT_JSON);
- return mp_obj_new_str_from_utf8_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps);
-
-#endif
-
-// The function below implements a simple non-recursive JSON parser.
-//
-// The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt
-// The parser here will parse any valid JSON and return the correct
-// corresponding Python object. It allows through a superset of JSON, since
-// it treats commas and colons as "whitespace", and doesn't care if
-// brackets/braces are correctly paired. It will raise a ValueError if the
-// input is outside it's specs.
-//
-// Most of the work is parsing the primitives (null, false, true, numbers,
-// strings). It does 1 pass over the input stream. It tries to be fast and
-// small in code size, while not using more RAM than necessary.
-
-typedef struct _ujson_stream_t {
- mp_obj_t stream_obj;
- mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode);
- int errcode;
- byte cur;
-} ujson_stream_t;
-
-#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker
-#define S_END(s) ((s).cur == S_EOF)
-#define S_CUR(s) ((s).cur)
-#define S_NEXT(s) (ujson_stream_next(&(s)))
-
-STATIC byte ujson_stream_next(ujson_stream_t *s) {
- mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode);
- if (s->errcode != 0) {
- mp_raise_OSError(s->errcode);
- }
- if (ret == 0) {
- s->cur = S_EOF;
- }
- return s->cur;
-}
-
-STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
- const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ);
- ujson_stream_t s = {stream_obj, stream_p->read, 0, 0};
- vstr_t vstr;
- vstr_init(&vstr, 8);
- mp_obj_list_t stack; // we use a list as a simple stack for nested JSON
- stack.len = 0;
- stack.items = NULL;
- mp_obj_t stack_top = MP_OBJ_NULL;
- const mp_obj_type_t *stack_top_type = NULL;
- mp_obj_t stack_key = MP_OBJ_NULL;
- S_NEXT(s);
- for (;;) {
- cont:
- if (S_END(s)) {
- break;
- }
- mp_obj_t next = MP_OBJ_NULL;
- bool enter = false;
- byte cur = S_CUR(s);
- S_NEXT(s);
- switch (cur) {
- case ',':
- case ':':
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- goto cont;
- case 'n':
- if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') {
- S_NEXT(s);
- next = mp_const_none;
- } else {
- goto fail;
- }
- break;
- case 'f':
- if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') {
- S_NEXT(s);
- next = mp_const_false;
- } else {
- goto fail;
- }
- break;
- case 't':
- if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') {
- S_NEXT(s);
- next = mp_const_true;
- } else {
- goto fail;
- }
- break;
- case '"':
- vstr_reset(&vstr);
- for (; !S_END(s) && S_CUR(s) != '"';) {
- byte c = S_CUR(s);
- if (c == '\\') {
- c = S_NEXT(s);
- switch (c) {
- case 'b':
- c = 0x08;
- break;
- case 'f':
- c = 0x0c;
- break;
- case 'n':
- c = 0x0a;
- break;
- case 'r':
- c = 0x0d;
- break;
- case 't':
- c = 0x09;
- break;
- case 'u': {
- mp_uint_t num = 0;
- for (int i = 0; i < 4; i++) {
- c = (S_NEXT(s) | 0x20) - '0';
- if (c > 9) {
- c -= ('a' - ('9' + 1));
- }
- num = (num << 4) | c;
- }
- vstr_add_char(&vstr, num);
- goto str_cont;
- }
- }
- }
- vstr_add_byte(&vstr, c);
- str_cont:
- S_NEXT(s);
- }
- if (S_END(s)) {
- goto fail;
- }
- S_NEXT(s);
- next = mp_obj_new_str(vstr.buf, vstr.len);
- break;
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- bool flt = false;
- vstr_reset(&vstr);
- for (;;) {
- vstr_add_byte(&vstr, cur);
- cur = S_CUR(s);
- if (cur == '.' || cur == 'E' || cur == 'e') {
- flt = true;
- } else if (cur == '+' || cur == '-' || unichar_isdigit(cur)) {
- // pass
- } else {
- break;
- }
- S_NEXT(s);
- }
- if (flt) {
- next = mp_parse_num_float(vstr.buf, vstr.len, false, NULL);
- } else {
- next = mp_parse_num_integer(vstr.buf, vstr.len, 10, NULL);
- }
- break;
- }
- case '[':
- next = mp_obj_new_list(0, NULL);
- enter = true;
- break;
- case '{':
- next = mp_obj_new_dict(0);
- enter = true;
- break;
- case '}':
- case ']': {
- if (stack_top == MP_OBJ_NULL) {
- // no object at all
- goto fail;
- }
- if (stack.len == 0) {
- // finished; compound object
- goto success;
- }
- stack.len -= 1;
- stack_top = stack.items[stack.len];
- stack_top_type = mp_obj_get_type(stack_top);
- goto cont;
- }
- default:
- goto fail;
- }
- if (stack_top == MP_OBJ_NULL) {
- stack_top = next;
- stack_top_type = mp_obj_get_type(stack_top);
- if (!enter) {
- // finished; single primitive only
- goto success;
- }
- } else {
- // append to list or dict
- if (stack_top_type == &mp_type_list) {
- mp_obj_list_append(stack_top, next);
- } else {
- if (stack_key == MP_OBJ_NULL) {
- stack_key = next;
- if (enter) {
- goto fail;
- }
- } else {
- mp_obj_dict_store(stack_top, stack_key, next);
- stack_key = MP_OBJ_NULL;
- }
- }
- if (enter) {
- if (stack.items == NULL) {
- mp_obj_list_init(&stack, 1);
- stack.items[0] = stack_top;
- } else {
- mp_obj_list_append(MP_OBJ_FROM_PTR(&stack), stack_top);
- }
- stack_top = next;
- stack_top_type = mp_obj_get_type(stack_top);
- }
- }
- }
-success:
- // eat trailing whitespace
- while (unichar_isspace(S_CUR(s))) {
- S_NEXT(s);
- }
- if (!S_END(s)) {
- // unexpected chars
- goto fail;
- }
- if (stack_top == MP_OBJ_NULL || stack.len != 0) {
- // not exactly 1 object
- goto fail;
- }
- vstr_clear(&vstr);
- return stack_top;
-
-fail:
- mp_raise_ValueError(MP_ERROR_TEXT("syntax error in JSON"));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load);
-
-STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(obj, &bufinfo, MP_BUFFER_READ);
- vstr_t vstr = {bufinfo.len, bufinfo.len, (char *)bufinfo.buf, true};
- mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0, MP_OBJ_NULL};
- return mod_ujson_load(MP_OBJ_FROM_PTR(&sio));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
-
-STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },
- { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) },
- { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },
- { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },
- { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_ujson_globals, mp_module_ujson_globals_table);
-
-const mp_obj_module_t mp_module_ujson = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_ujson_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ujson, mp_module_ujson);
-
-#endif // MICROPY_PY_UJSON
diff --git a/extmod/moduos.c b/extmod/moduos.c
deleted file mode 100644
index 87a611148d1c..000000000000
--- a/extmod/moduos.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016-2022 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/objstr.h"
-#include "py/runtime.h"
-
-#if MICROPY_PY_UOS
-
-#include "extmod/misc.h"
-#include "extmod/vfs.h"
-
-#if MICROPY_VFS_FAT
-#include "extmod/vfs_fat.h"
-#endif
-
-#if MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2
-#include "extmod/vfs_lfs.h"
-#endif
-
-#if MICROPY_VFS_POSIX
-#include "extmod/vfs_posix.h"
-#endif
-
-#if MICROPY_PY_UOS_UNAME
-#include "genhdr/mpversion.h"
-#endif
-
-#ifdef MICROPY_PY_UOS_INCLUDEFILE
-#include MICROPY_PY_UOS_INCLUDEFILE
-#endif
-
-#ifdef MICROPY_BUILD_TYPE
-#define MICROPY_BUILD_TYPE_PAREN " (" MICROPY_BUILD_TYPE ")"
-#else
-#define MICROPY_BUILD_TYPE_PAREN
-#endif
-
-#if MICROPY_PY_UOS_UNAME
-
-#if MICROPY_PY_UOS_UNAME_RELEASE_DYNAMIC
-#define CONST_RELEASE
-#else
-#define CONST_RELEASE const
-#endif
-
-STATIC const qstr mp_uos_uname_info_fields[] = {
- MP_QSTR_sysname,
- MP_QSTR_nodename,
- MP_QSTR_release,
- MP_QSTR_version,
- MP_QSTR_machine
-};
-STATIC const MP_DEFINE_STR_OBJ(mp_uos_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
-STATIC const MP_DEFINE_STR_OBJ(mp_uos_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
-STATIC CONST_RELEASE MP_DEFINE_STR_OBJ(mp_uos_uname_info_release_obj, MICROPY_VERSION_STRING);
-STATIC const MP_DEFINE_STR_OBJ(mp_uos_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE MICROPY_BUILD_TYPE_PAREN);
-STATIC const MP_DEFINE_STR_OBJ(mp_uos_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
-
-STATIC MP_DEFINE_ATTRTUPLE(
- mp_uos_uname_info_obj,
- mp_uos_uname_info_fields,
- 5,
- MP_ROM_PTR(&mp_uos_uname_info_sysname_obj),
- MP_ROM_PTR(&mp_uos_uname_info_nodename_obj),
- MP_ROM_PTR(&mp_uos_uname_info_release_obj),
- MP_ROM_PTR(&mp_uos_uname_info_version_obj),
- MP_ROM_PTR(&mp_uos_uname_info_machine_obj)
- );
-
-STATIC mp_obj_t mp_uos_uname(void) {
- #if MICROPY_PY_UOS_UNAME_RELEASE_DYNAMIC
- const char *release = mp_uos_uname_release();
- mp_uos_uname_info_release_obj.len = strlen(release);
- mp_uos_uname_info_release_obj.data = (const byte *)release;
- #endif
- return MP_OBJ_FROM_PTR(&mp_uos_uname_info_obj);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_uos_uname_obj, mp_uos_uname);
-
-#endif
-
-STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
-
- #if MICROPY_PY_UOS_GETENV_PUTENV_UNSETENV
- { MP_ROM_QSTR(MP_QSTR_getenv), MP_ROM_PTR(&mp_uos_getenv_obj) },
- { MP_ROM_QSTR(MP_QSTR_putenv), MP_ROM_PTR(&mp_uos_putenv_obj) },
- { MP_ROM_QSTR(MP_QSTR_unsetenv), MP_ROM_PTR(&mp_uos_unsetenv_obj) },
- #endif
- #if MICROPY_PY_UOS_SEP
- { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) },
- #endif
- #if MICROPY_PY_UOS_SYNC
- { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mp_uos_sync_obj) },
- #endif
- #if MICROPY_PY_UOS_SYSTEM
- { MP_ROM_QSTR(MP_QSTR_system), MP_ROM_PTR(&mp_uos_system_obj) },
- #endif
- #if MICROPY_PY_UOS_UNAME
- { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&mp_uos_uname_obj) },
- #endif
- #if MICROPY_PY_UOS_URANDOM
- { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&mp_uos_urandom_obj) },
- #endif
-
- #if MICROPY_VFS
- { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
- { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
- { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
- { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
- { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&mp_vfs_statvfs_obj) },
- { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
- #endif
-
- // The following are MicroPython extensions.
-
- #if MICROPY_PY_OS_DUPTERM
- { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) },
- #endif
- #if MICROPY_PY_UOS_DUPTERM_NOTIFY
- { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&mp_uos_dupterm_notify_obj) },
- #endif
- #if MICROPY_PY_UOS_ERRNO
- { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_uos_errno_obj) },
- #endif
-
- #if MICROPY_VFS
- { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
- { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
- #if MICROPY_VFS_FAT
- { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
- #endif
- #if MICROPY_VFS_LFS1
- { MP_ROM_QSTR(MP_QSTR_VfsLfs1), MP_ROM_PTR(&mp_type_vfs_lfs1) },
- #endif
- #if MICROPY_VFS_LFS2
- { MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
- #endif
- #if MICROPY_VFS_POSIX
- { MP_ROM_QSTR(MP_QSTR_VfsPosix), MP_ROM_PTR(&mp_type_vfs_posix) },
- #endif
- #endif
-};
-STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
-
-const mp_obj_module_t mp_module_uos = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&os_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uos, mp_module_uos);
-
-#endif // MICROPY_PY_UOS
diff --git a/extmod/moduplatform.c b/extmod/moduplatform.c
deleted file mode 100644
index 1b35b08aa721..000000000000
--- a/extmod/moduplatform.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013-2021 Ibrahim Abdelkader
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#include "py/runtime.h"
-#include "py/objtuple.h"
-#include "py/objstr.h"
-#include "py/mphal.h"
-#include "extmod/moduplatform.h"
-#include "genhdr/mpversion.h"
-
-#if MICROPY_PY_UPLATFORM
-
-// platform - Access to underlying platform's identifying data
-
-STATIC const MP_DEFINE_STR_OBJ(info_platform_obj, MICROPY_PLATFORM_SYSTEM "-" \
- MICROPY_VERSION_STRING "-" MICROPY_PLATFORM_ARCH "-" MICROPY_PLATFORM_VERSION "-with-" \
- MICROPY_PLATFORM_LIBC_LIB "" MICROPY_PLATFORM_LIBC_VER);
-STATIC const MP_DEFINE_STR_OBJ(info_python_compiler_obj, MICROPY_PLATFORM_COMPILER);
-STATIC const MP_DEFINE_STR_OBJ(info_libc_lib_obj, MICROPY_PLATFORM_LIBC_LIB);
-STATIC const MP_DEFINE_STR_OBJ(info_libc_ver_obj, MICROPY_PLATFORM_LIBC_VER);
-STATIC const mp_rom_obj_tuple_t info_libc_tuple_obj = {
- {&mp_type_tuple}, 2, {MP_ROM_PTR(&info_libc_lib_obj), MP_ROM_PTR(&info_libc_ver_obj)}
-};
-
-STATIC mp_obj_t platform_platform(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- return MP_OBJ_FROM_PTR(&info_platform_obj);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_platform_obj, 0, platform_platform);
-
-STATIC mp_obj_t platform_python_compiler(void) {
- return MP_OBJ_FROM_PTR(&info_python_compiler_obj);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(platform_python_compiler_obj, platform_python_compiler);
-
-STATIC mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- return MP_OBJ_FROM_PTR(&info_libc_tuple_obj);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver);
-
-STATIC const mp_rom_map_elem_t modplatform_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uplatform) },
- { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) },
- { MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) },
- { MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table);
-
-const mp_obj_module_t mp_module_uplatform = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&modplatform_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uplatform, mp_module_uplatform);
-
-#endif // MICROPY_PY_UPLATFORM
diff --git a/extmod/moduplatform.h b/extmod/moduplatform.h
deleted file mode 100644
index 2b9ad3ae49b7..000000000000
--- a/extmod/moduplatform.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013-2021 Ibrahim Abdelkader
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_MODUPLATFORM_H
-#define MICROPY_INCLUDED_MODUPLATFORM_H
-
-#include "py/misc.h" // For MP_STRINGIFY.
-#include "py/mpconfig.h"
-
-// Preprocessor directives indentifying the platform.
-// The (u)platform module itself is guarded by MICROPY_PY_UPLATFORM, see the
-// .c file, but these are made available because they're generally usable.
-// TODO: Add more architectures, compilers and libraries.
-// See: https://sourceforge.net/p/predef/wiki/Home/
-
-#if defined(__ARM_ARCH)
-#define MICROPY_PLATFORM_ARCH "arm"
-#elif defined(__x86_64__) || defined(_WIN64)
-#define MICROPY_PLATFORM_ARCH "x86_64"
-#elif defined(__i386__) || defined(_M_IX86)
-#define MICROPY_PLATFORM_ARCH "x86"
-#elif defined(__xtensa__) || defined(_M_IX86)
-#define MICROPY_PLATFORM_ARCH "xtensa"
-#else
-#define MICROPY_PLATFORM_ARCH ""
-#endif
-
-#if defined(__GNUC__)
-#define MICROPY_PLATFORM_COMPILER \
- "GCC " \
- MP_STRINGIFY(__GNUC__) "." \
- MP_STRINGIFY(__GNUC_MINOR__) "." \
- MP_STRINGIFY(__GNUC_PATCHLEVEL__)
-#elif defined(__ARMCC_VERSION)
-#define MICROPY_PLATFORM_COMPILER \
- "ARMCC " \
- MP_STRINGIFY((__ARMCC_VERSION / 1000000)) "." \
- MP_STRINGIFY((__ARMCC_VERSION / 10000 % 100)) "." \
- MP_STRINGIFY((__ARMCC_VERSION % 10000))
-#elif defined(_MSC_VER)
-#if defined(_WIN64)
-#define MICROPY_PLATFORM_COMPILER_BITS "64 bit"
-#elif defined(_M_IX86)
-#define MICROPY_PLATFORM_COMPILER_BITS "32 bit"
-#else
-#define MICROPY_PLATFORM_COMPILER_BITS ""
-#endif
-#define MICROPY_PLATFORM_COMPILER \
- "MSC v." MP_STRINGIFY(_MSC_VER) " " MICROPY_PLATFORM_COMPILER_BITS
-#else
-#define MICROPY_PLATFORM_COMPILER ""
-#endif
-
-#if defined(__GLIBC__)
-#define MICROPY_PLATFORM_LIBC_LIB "glibc"
-#define MICROPY_PLATFORM_LIBC_VER \
- MP_STRINGIFY(__GLIBC__) "." \
- MP_STRINGIFY(__GLIBC_MINOR__)
-#elif defined(__NEWLIB__)
-#define MICROPY_PLATFORM_LIBC_LIB "newlib"
-#define MICROPY_PLATFORM_LIBC_VER _NEWLIB_VERSION
-#else
-#define MICROPY_PLATFORM_LIBC_LIB ""
-#define MICROPY_PLATFORM_LIBC_VER ""
-#endif
-
-#if defined(__linux)
-#define MICROPY_PLATFORM_SYSTEM "Linux"
-#elif defined(__unix__)
-#define MICROPY_PLATFORM_SYSTEM "Unix"
-#elif defined(__CYGWIN__)
-#define MICROPY_PLATFORM_SYSTEM "Cygwin"
-#elif defined(_WIN32)
-#define MICROPY_PLATFORM_SYSTEM "Windows"
-#else
-#define MICROPY_PLATFORM_SYSTEM "MicroPython"
-#endif
-
-#ifndef MICROPY_PLATFORM_VERSION
-#define MICROPY_PLATFORM_VERSION ""
-#endif
-
-#endif // MICROPY_INCLUDED_MODUPLATFORM_H
diff --git a/extmod/modurandom.c b/extmod/modurandom.c
deleted file mode 100644
index b66162719034..000000000000
--- a/extmod/modurandom.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/runtime.h"
-
-#if MICROPY_PY_URANDOM
-
-// Work out if the seed will be set on import or not.
-#if MICROPY_MODULE_BUILTIN_INIT && defined(MICROPY_PY_URANDOM_SEED_INIT_FUNC)
-#define SEED_ON_IMPORT (1)
-#else
-#define SEED_ON_IMPORT (0)
-#endif
-
-// Yasmarang random number generator
-// by Ilya Levin
-// http://www.literatecode.com/yasmarang
-// Public Domain
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-#if SEED_ON_IMPORT
-// If the state is seeded on import then keep these variables in the BSS.
-STATIC uint32_t yasmarang_pad, yasmarang_n, yasmarang_d;
-STATIC uint8_t yasmarang_dat;
-#else
-// Without seed-on-import these variables must be initialised via the data section.
-STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
-STATIC uint8_t yasmarang_dat = 0;
-#endif
-#endif
-
-STATIC uint32_t yasmarang(void) {
- yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;
- yasmarang_pad = (yasmarang_pad << 3) + (yasmarang_pad >> 29);
- yasmarang_n = yasmarang_pad | 2;
- yasmarang_d ^= (yasmarang_pad << 31) + (yasmarang_pad >> 1);
- yasmarang_dat ^= (char)yasmarang_pad ^ (yasmarang_d >> 8) ^ 1;
-
- return yasmarang_pad ^ (yasmarang_d << 5) ^ (yasmarang_pad >> 18) ^ (yasmarang_dat << 1);
-} /* yasmarang */
-
-// End of Yasmarang
-
-#if MICROPY_PY_URANDOM_EXTRA_FUNCS
-
-// returns an unsigned integer below the given argument
-// n must not be zero
-STATIC uint32_t yasmarang_randbelow(uint32_t n) {
- uint32_t mask = 1;
- while ((n & mask) < n) {
- mask = (mask << 1) | 1;
- }
- uint32_t r;
- do {
- r = yasmarang() & mask;
- } while (r >= n);
- return r;
-}
-
-#endif
-
-STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
- int n = mp_obj_get_int(num_in);
- if (n > 32 || n < 0) {
- mp_raise_ValueError(MP_ERROR_TEXT("bits must be 32 or less"));
- }
- if (n == 0) {
- return MP_OBJ_NEW_SMALL_INT(0);
- }
- uint32_t mask = ~0;
- // Beware of C undefined behavior when shifting by >= than bit size
- mask >>= (32 - n);
- return mp_obj_new_int_from_uint(yasmarang() & mask);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits);
-
-STATIC mp_obj_t mod_urandom_seed(size_t n_args, const mp_obj_t *args) {
- mp_uint_t seed;
- if (n_args == 0 || args[0] == mp_const_none) {
- #ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
- seed = MICROPY_PY_URANDOM_SEED_INIT_FUNC;
- #else
- mp_raise_ValueError(MP_ERROR_TEXT("no default seed"));
- #endif
- } else {
- seed = mp_obj_get_int_truncated(args[0]);
- }
- yasmarang_pad = seed;
- yasmarang_n = 69;
- yasmarang_d = 233;
- yasmarang_dat = 0;
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_seed_obj, 0, 1, mod_urandom_seed);
-
-#if MICROPY_PY_URANDOM_EXTRA_FUNCS
-
-STATIC mp_obj_t mod_urandom_randrange(size_t n_args, const mp_obj_t *args) {
- mp_int_t start = mp_obj_get_int(args[0]);
- if (n_args == 1) {
- // range(stop)
- if (start > 0) {
- return mp_obj_new_int(yasmarang_randbelow(start));
- } else {
- goto error;
- }
- } else {
- mp_int_t stop = mp_obj_get_int(args[1]);
- if (n_args == 2) {
- // range(start, stop)
- if (start < stop) {
- return mp_obj_new_int(start + yasmarang_randbelow(stop - start));
- } else {
- goto error;
- }
- } else {
- // range(start, stop, step)
- mp_int_t step = mp_obj_get_int(args[2]);
- mp_int_t n;
- if (step > 0) {
- n = (stop - start + step - 1) / step;
- } else if (step < 0) {
- n = (stop - start + step + 1) / step;
- } else {
- goto error;
- }
- if (n > 0) {
- return mp_obj_new_int(start + step * yasmarang_randbelow(n));
- } else {
- goto error;
- }
- }
- }
-
-error:
- mp_raise_ValueError(NULL);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_randrange_obj, 1, 3, mod_urandom_randrange);
-
-STATIC mp_obj_t mod_urandom_randint(mp_obj_t a_in, mp_obj_t b_in) {
- mp_int_t a = mp_obj_get_int(a_in);
- mp_int_t b = mp_obj_get_int(b_in);
- if (a <= b) {
- return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1));
- } else {
- mp_raise_ValueError(NULL);
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_randint_obj, mod_urandom_randint);
-
-STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {
- mp_int_t len = mp_obj_get_int(mp_obj_len(seq));
- if (len > 0) {
- return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
- } else {
- mp_raise_type(&mp_type_IndexError);
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
-
-#if MICROPY_PY_BUILTINS_FLOAT
-
-// returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
-STATIC mp_float_t yasmarang_float(void) {
- mp_float_union_t u;
- u.p.sgn = 0;
- u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
- if (MP_FLOAT_FRAC_BITS <= 32) {
- u.p.frc = yasmarang();
- } else {
- u.p.frc = ((uint64_t)yasmarang() << 32) | (uint64_t)yasmarang();
- }
- return u.f - 1;
-}
-
-STATIC mp_obj_t mod_urandom_random(void) {
- return mp_obj_new_float(yasmarang_float());
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom_random_obj, mod_urandom_random);
-
-STATIC mp_obj_t mod_urandom_uniform(mp_obj_t a_in, mp_obj_t b_in) {
- mp_float_t a = mp_obj_get_float(a_in);
- mp_float_t b = mp_obj_get_float(b_in);
- return mp_obj_new_float(a + (b - a) * yasmarang_float());
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
-
-#endif
-
-#endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
-
-#if SEED_ON_IMPORT
-STATIC mp_obj_t mod_urandom___init__(void) {
- // This module may be imported by more than one name so need to ensure
- // that it's only ever seeded once.
- static bool seeded = false;
- if (!seeded) {
- seeded = true;
- mod_urandom_seed(0, NULL);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom___init___obj, mod_urandom___init__);
-#endif
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
- #if SEED_ON_IMPORT
- { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&mod_urandom___init___obj) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },
- { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) },
- #if MICROPY_PY_URANDOM_EXTRA_FUNCS
- { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_urandom_randrange_obj) },
- { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_urandom_randint_obj) },
- { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_urandom_choice_obj) },
- #if MICROPY_PY_BUILTINS_FLOAT
- { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_urandom_random_obj) },
- { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_urandom_uniform_obj) },
- #endif
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals_table);
-
-const mp_obj_module_t mp_module_urandom = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_urandom_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_urandom, mp_module_urandom);
-#endif
-
-#endif // MICROPY_PY_URANDOM
diff --git a/extmod/modure.c b/extmod/modure.c
deleted file mode 100644
index 801e5df89779..000000000000
--- a/extmod/modure.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/runtime.h"
-#include "py/binary.h"
-#include "py/objstr.h"
-#include "py/stackctrl.h"
-
-#if MICROPY_PY_BUILTINS_STR_UNICODE
-#include "py/unicode.h"
-#endif
-
-#if MICROPY_PY_URE
-
-#define re1_5_stack_chk() MP_STACK_CHECK()
-
-#include "lib/re1.5/re1.5.h"
-
-#define FLAG_DEBUG 0x1000
-
-typedef struct _mp_obj_re_t {
- mp_obj_base_t base;
- ByteProg re;
-} mp_obj_re_t;
-
-typedef struct _mp_obj_match_t {
- mp_obj_base_t base;
- int num_matches;
- mp_obj_t str;
- const char *caps[0];
-} mp_obj_match_t;
-
-STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args);
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_obj_type_t re_type;
-#endif
-
-STATIC void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- (void)kind;
- mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "", self->num_matches);
-}
-
-STATIC mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
- mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
- mp_int_t no = mp_obj_get_int(no_in);
- if (no < 0 || no >= self->num_matches) {
- mp_raise_type_arg(&mp_type_IndexError, no_in);
- }
-
- const char *start = self->caps[no * 2];
- if (start == NULL) {
- // no match for this group
- return mp_const_none;
- }
- return mp_obj_new_str_of_type(mp_obj_get_type(self->str),
- (const byte *)start, self->caps[no * 2 + 1] - start);
-}
-MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);
-
-#if MICROPY_PY_URE_MATCH_GROUPS
-
-STATIC mp_obj_t match_groups(mp_obj_t self_in) {
- mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->num_matches <= 1) {
- return mp_const_empty_tuple;
- }
- mp_obj_tuple_t *groups = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->num_matches - 1, NULL));
- for (int i = 1; i < self->num_matches; ++i) {
- groups->items[i - 1] = match_group(self_in, MP_OBJ_NEW_SMALL_INT(i));
- }
- return MP_OBJ_FROM_PTR(groups);
-}
-MP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups);
-
-#endif
-
-#if MICROPY_PY_URE_MATCH_SPAN_START_END
-
-STATIC void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) {
- mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]);
-
- mp_int_t no = 0;
- if (n_args == 2) {
- no = mp_obj_get_int(args[1]);
- if (no < 0 || no >= self->num_matches) {
- mp_raise_type_arg(&mp_type_IndexError, args[1]);
- }
- }
-
- mp_int_t s = -1;
- mp_int_t e = -1;
- const char *start = self->caps[no * 2];
- if (start != NULL) {
- // have a match for this group
- const char *begin = mp_obj_str_get_str(self->str);
- s = start - begin;
- e = self->caps[no * 2 + 1] - begin;
- }
-
- #if MICROPY_PY_BUILTINS_STR_UNICODE
- if (mp_obj_get_type(self->str) == &mp_type_str) {
- const byte *begin = (const byte *)mp_obj_str_get_str(self->str);
- if (s != -1) {
- s = utf8_ptr_to_index(begin, begin + s);
- }
- if (e != -1) {
- e = utf8_ptr_to_index(begin, begin + e);
- }
- }
- #endif
-
- span[0] = mp_obj_new_int(s);
- span[1] = mp_obj_new_int(e);
-}
-
-STATIC mp_obj_t match_span(size_t n_args, const mp_obj_t *args) {
- mp_obj_t span[2];
- match_span_helper(n_args, args, span);
- return mp_obj_new_tuple(2, span);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span);
-
-STATIC mp_obj_t match_start(size_t n_args, const mp_obj_t *args) {
- mp_obj_t span[2];
- match_span_helper(n_args, args, span);
- return span[0];
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start);
-
-STATIC mp_obj_t match_end(size_t n_args, const mp_obj_t *args) {
- mp_obj_t span[2];
- match_span_helper(n_args, args, span);
- return span[1];
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end);
-
-#endif
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t match_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },
- #if MICROPY_PY_URE_MATCH_GROUPS
- { MP_ROM_QSTR(MP_QSTR_groups), MP_ROM_PTR(&match_groups_obj) },
- #endif
- #if MICROPY_PY_URE_MATCH_SPAN_START_END
- { MP_ROM_QSTR(MP_QSTR_span), MP_ROM_PTR(&match_span_obj) },
- { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&match_start_obj) },
- { MP_ROM_QSTR(MP_QSTR_end), MP_ROM_PTR(&match_end_obj) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- match_type,
- MP_QSTR_match,
- MP_TYPE_FLAG_NONE,
- print, match_print,
- locals_dict, &match_locals_dict
- );
-#endif
-
-STATIC void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- (void)kind;
- mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "", self);
-}
-
-STATIC mp_obj_t ure_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
- (void)n_args;
- mp_obj_re_t *self;
- if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
- self = MP_OBJ_TO_PTR(args[0]);
- } else {
- self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
- }
- Subject subj;
- size_t len;
- subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
- subj.end = subj.begin + len;
- int caps_num = (self->re.sub + 1) * 2;
- mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, char *, caps_num);
- // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
- memset((char *)match->caps, 0, caps_num * sizeof(char *));
- int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
- if (res == 0) {
- m_del_var(mp_obj_match_t, char *, caps_num, match);
- return mp_const_none;
- }
-
- match->base.type = (mp_obj_type_t *)&match_type;
- match->num_matches = caps_num / 2; // caps_num counts start and end pointers
- match->str = args[1];
- return MP_OBJ_FROM_PTR(match);
-}
-
-STATIC mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {
- return ure_exec(true, n_args, args);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
-
-STATIC mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {
- return ure_exec(false, n_args, args);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
-
-STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
- mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
- Subject subj;
- size_t len;
- const mp_obj_type_t *str_type = mp_obj_get_type(args[1]);
- subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
- subj.end = subj.begin + len;
- int caps_num = (self->re.sub + 1) * 2;
-
- int maxsplit = 0;
- if (n_args > 2) {
- maxsplit = mp_obj_get_int(args[2]);
- }
-
- mp_obj_t retval = mp_obj_new_list(0, NULL);
- const char **caps = mp_local_alloc(caps_num * sizeof(char *));
- while (true) {
- // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
- memset((char **)caps, 0, caps_num * sizeof(char *));
- int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
-
- // if we didn't have a match, or had an empty match, it's time to stop
- if (!res || caps[0] == caps[1]) {
- break;
- }
-
- mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
- mp_obj_list_append(retval, s);
- if (self->re.sub > 0) {
- mp_raise_NotImplementedError(MP_ERROR_TEXT("splitting with sub-captures"));
- }
- subj.begin = caps[1];
- if (maxsplit > 0 && --maxsplit == 0) {
- break;
- }
- }
- // cast is a workaround for a bug in msvc (see above)
- mp_local_free((char **)caps);
-
- mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, subj.end - subj.begin);
- mp_obj_list_append(retval, s);
- return retval;
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
-
-#if MICROPY_PY_URE_SUB
-
-STATIC mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
- mp_obj_re_t *self;
- if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
- self = MP_OBJ_TO_PTR(args[0]);
- } else {
- self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
- }
- mp_obj_t replace = args[1];
- mp_obj_t where = args[2];
- mp_int_t count = 0;
- if (n_args > 3) {
- count = mp_obj_get_int(args[3]);
- // Note: flags are currently ignored
- }
-
- size_t where_len;
- const char *where_str = mp_obj_str_get_data(where, &where_len);
- Subject subj;
- subj.begin_line = subj.begin = where_str;
- subj.end = subj.begin + where_len;
- int caps_num = (self->re.sub + 1) * 2;
-
- vstr_t vstr_return;
- vstr_return.buf = NULL; // We'll init the vstr after the first match
- mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char *));
- match->base.type = (mp_obj_type_t *)&match_type;
- match->num_matches = caps_num / 2; // caps_num counts start and end pointers
- match->str = where;
-
- for (;;) {
- // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
- memset((char *)match->caps, 0, caps_num * sizeof(char *));
- int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false);
-
- // If we didn't have a match, or had an empty match, it's time to stop
- if (!res || match->caps[0] == match->caps[1]) {
- break;
- }
-
- // Initialise the vstr if it's not already
- if (vstr_return.buf == NULL) {
- vstr_init(&vstr_return, match->caps[0] - subj.begin);
- }
-
- // Add pre-match string
- vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin);
-
- // Get replacement string
- const char *repl = mp_obj_str_get_str((mp_obj_is_callable(replace) ? mp_call_function_1(replace, MP_OBJ_FROM_PTR(match)) : replace));
-
- // Append replacement string to result, substituting any regex groups
- while (*repl != '\0') {
- if (*repl == '\\') {
- ++repl;
- bool is_g_format = false;
- if (*repl == 'g' && repl[1] == '<') {
- // Group specified with syntax "\g"
- repl += 2;
- is_g_format = true;
- }
-
- if ('0' <= *repl && *repl <= '9') {
- // Group specified with syntax "\g" or "\number"
- unsigned int match_no = 0;
- do {
- match_no = match_no * 10 + (*repl++ - '0');
- } while ('0' <= *repl && *repl <= '9');
- if (is_g_format && *repl == '>') {
- ++repl;
- }
-
- if (match_no >= (unsigned int)match->num_matches) {
- mp_raise_type_arg(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
- }
-
- const char *start_match = match->caps[match_no * 2];
- if (start_match != NULL) {
- // Add the substring matched by group
- const char *end_match = match->caps[match_no * 2 + 1];
- vstr_add_strn(&vstr_return, start_match, end_match - start_match);
- }
- } else if (*repl == '\\') {
- // Add the \ character
- vstr_add_byte(&vstr_return, *repl++);
- }
- } else {
- // Just add the current byte from the replacement string
- vstr_add_byte(&vstr_return, *repl++);
- }
- }
-
- // Move start pointer to end of last match
- subj.begin = match->caps[1];
-
- // Stop substitutions if count was given and gets to 0
- if (count > 0 && --count == 0) {
- break;
- }
- }
-
- mp_local_free(match);
-
- if (vstr_return.buf == NULL) {
- // Optimisation for case of no substitutions
- return where;
- }
-
- // Add post-match string
- vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin);
-
- if (mp_obj_get_type(where) == &mp_type_str) {
- return mp_obj_new_str_from_utf8_vstr(&vstr_return);
- } else {
- return mp_obj_new_bytes_from_vstr(&vstr_return);
- }
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
-
-#endif
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t re_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
- { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
- { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },
- #if MICROPY_PY_URE_SUB
- { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- re_type,
- MP_QSTR_ure,
- MP_TYPE_FLAG_NONE,
- print, re_print,
- locals_dict, &re_locals_dict
- );
-#endif
-
-STATIC mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- const char *re_str = mp_obj_str_get_str(args[0]);
- int size = re1_5_sizecode(re_str);
- if (size == -1) {
- goto error;
- }
- mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, char, size, (mp_obj_type_t *)&re_type);
- #if MICROPY_PY_URE_DEBUG
- int flags = 0;
- if (n_args > 1) {
- flags = mp_obj_get_int(args[1]);
- }
- #endif
- int error = re1_5_compilecode(&o->re, re_str);
- if (error != 0) {
- error:
- mp_raise_ValueError(MP_ERROR_TEXT("error in regex"));
- }
- #if MICROPY_PY_URE_DEBUG
- if (flags & FLAG_DEBUG) {
- re1_5_dumpcode(&o->re);
- }
- #endif
- return MP_OBJ_FROM_PTR(o);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t mp_module_re_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ure) },
- { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
- { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
- { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
- #if MICROPY_PY_URE_SUB
- { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
- #endif
- #if MICROPY_PY_URE_DEBUG
- { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
-
-const mp_obj_module_t mp_module_ure = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_re_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ure, mp_module_ure);
-#endif
-
-// Source files #include'd here to make sure they're compiled in
-// only if module is enabled by config setting.
-
-#define re1_5_fatal(x) assert(!x)
-
-#include "lib/re1.5/compilecode.c"
-#include "lib/re1.5/recursiveloop.c"
-#include "lib/re1.5/charclass.c"
-
-#if MICROPY_PY_URE_DEBUG
-// Make sure the output print statements go to the same output as other Python output.
-#define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
-#include "lib/re1.5/dumpcode.c"
-#undef printf
-#endif
-
-#endif // MICROPY_PY_URE
diff --git a/extmod/moduselect.c b/extmod/moduselect.c
deleted file mode 100644
index 128154a4b6d9..000000000000
--- a/extmod/moduselect.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Damien P. George
- * Copyright (c) 2015-2017 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-#if MICROPY_PY_USELECT
-
-#include
-
-#include "py/runtime.h"
-#include "py/obj.h"
-#include "py/objlist.h"
-#include "py/stream.h"
-#include "py/mperrno.h"
-#include "py/mphal.h"
-
-// Flags for poll()
-#define FLAG_ONESHOT (1)
-
-typedef struct _poll_obj_t {
- mp_obj_t obj;
- mp_uint_t (*ioctl)(mp_obj_t obj, mp_uint_t request, uintptr_t arg, int *errcode);
- mp_uint_t flags;
- mp_uint_t flags_ret;
-} poll_obj_t;
-
-STATIC void poll_map_add(mp_map_t *poll_map, const mp_obj_t *obj, mp_uint_t obj_len, mp_uint_t flags, bool or_flags) {
- for (mp_uint_t i = 0; i < obj_len; i++) {
- mp_map_elem_t *elem = mp_map_lookup(poll_map, mp_obj_id(obj[i]), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
- if (elem->value == MP_OBJ_NULL) {
- // object not found; get its ioctl and add it to the poll list
- const mp_stream_p_t *stream_p = mp_get_stream_raise(obj[i], MP_STREAM_OP_IOCTL);
- poll_obj_t *poll_obj = m_new_obj(poll_obj_t);
- poll_obj->obj = obj[i];
- poll_obj->ioctl = stream_p->ioctl;
- poll_obj->flags = flags;
- poll_obj->flags_ret = 0;
- elem->value = MP_OBJ_FROM_PTR(poll_obj);
- } else {
- // object exists; update its flags
- if (or_flags) {
- ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags |= flags;
- } else {
- ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = flags;
- }
- }
- }
-}
-
-// poll each object in the map
-STATIC mp_uint_t poll_map_poll(mp_map_t *poll_map, size_t *rwx_num) {
- mp_uint_t n_ready = 0;
- for (mp_uint_t i = 0; i < poll_map->alloc; ++i) {
- if (!mp_map_slot_is_filled(poll_map, i)) {
- continue;
- }
-
- poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map->table[i].value);
- int errcode;
- mp_int_t ret = poll_obj->ioctl(poll_obj->obj, MP_STREAM_POLL, poll_obj->flags, &errcode);
- poll_obj->flags_ret = ret;
-
- if (ret == -1) {
- // error doing ioctl
- mp_raise_OSError(errcode);
- }
-
- if (ret != 0) {
- // object is ready
- n_ready += 1;
- if (rwx_num != NULL) {
- if (ret & MP_STREAM_POLL_RD) {
- rwx_num[0] += 1;
- }
- if (ret & MP_STREAM_POLL_WR) {
- rwx_num[1] += 1;
- }
- if ((ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
- rwx_num[2] += 1;
- }
- }
- }
- }
- return n_ready;
-}
-
-#if MICROPY_PY_USELECT_SELECT
-// select(rlist, wlist, xlist[, timeout])
-STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
- // get array data from tuple/list arguments
- size_t rwx_len[3];
- mp_obj_t *r_array, *w_array, *x_array;
- mp_obj_get_array(args[0], &rwx_len[0], &r_array);
- mp_obj_get_array(args[1], &rwx_len[1], &w_array);
- mp_obj_get_array(args[2], &rwx_len[2], &x_array);
-
- // get timeout
- mp_uint_t timeout = -1;
- if (n_args == 4) {
- if (args[3] != mp_const_none) {
- #if MICROPY_PY_BUILTINS_FLOAT
- float timeout_f = mp_obj_get_float_to_f(args[3]);
- if (timeout_f >= 0) {
- timeout = (mp_uint_t)(timeout_f * 1000);
- }
- #else
- timeout = mp_obj_get_int(args[3]) * 1000;
- #endif
- }
- }
-
- // merge separate lists and get the ioctl function for each object
- mp_map_t poll_map;
- mp_map_init(&poll_map, rwx_len[0] + rwx_len[1] + rwx_len[2]);
- poll_map_add(&poll_map, r_array, rwx_len[0], MP_STREAM_POLL_RD, true);
- poll_map_add(&poll_map, w_array, rwx_len[1], MP_STREAM_POLL_WR, true);
- poll_map_add(&poll_map, x_array, rwx_len[2], MP_STREAM_POLL_ERR | MP_STREAM_POLL_HUP, true);
-
- mp_uint_t start_tick = mp_hal_ticks_ms();
- rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
- for (;;) {
- // poll the objects
- mp_uint_t n_ready = poll_map_poll(&poll_map, rwx_len);
-
- if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
- // one or more objects are ready, or we had a timeout
- mp_obj_t list_array[3];
- list_array[0] = mp_obj_new_list(rwx_len[0], NULL);
- list_array[1] = mp_obj_new_list(rwx_len[1], NULL);
- list_array[2] = mp_obj_new_list(rwx_len[2], NULL);
- rwx_len[0] = rwx_len[1] = rwx_len[2] = 0;
- for (mp_uint_t i = 0; i < poll_map.alloc; ++i) {
- if (!mp_map_slot_is_filled(&poll_map, i)) {
- continue;
- }
- poll_obj_t *poll_obj = MP_OBJ_TO_PTR(poll_map.table[i].value);
- if (poll_obj->flags_ret & MP_STREAM_POLL_RD) {
- ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[0]))->items[rwx_len[0]++] = poll_obj->obj;
- }
- if (poll_obj->flags_ret & MP_STREAM_POLL_WR) {
- ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[1]))->items[rwx_len[1]++] = poll_obj->obj;
- }
- if ((poll_obj->flags_ret & ~(MP_STREAM_POLL_RD | MP_STREAM_POLL_WR)) != 0) {
- ((mp_obj_list_t *)MP_OBJ_TO_PTR(list_array[2]))->items[rwx_len[2]++] = poll_obj->obj;
- }
- }
- mp_map_deinit(&poll_map);
- return mp_obj_new_tuple(3, list_array);
- }
- MICROPY_EVENT_POLL_HOOK
- }
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_select_select_obj, 3, 4, select_select);
-#endif // MICROPY_PY_USELECT_SELECT
-
-typedef struct _mp_obj_poll_t {
- mp_obj_base_t base;
- mp_map_t poll_map;
- short iter_cnt;
- short iter_idx;
- int flags;
- // callee-owned tuple
- mp_obj_t ret_tuple;
-} mp_obj_poll_t;
-
-// register(obj[, eventmask])
-STATIC mp_obj_t poll_register(size_t n_args, const mp_obj_t *args) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
- mp_uint_t flags;
- if (n_args == 3) {
- flags = mp_obj_get_int(args[2]);
- } else {
- flags = MP_STREAM_POLL_RD | MP_STREAM_POLL_WR;
- }
- poll_map_add(&self->poll_map, &args[1], 1, flags, false);
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_register_obj, 2, 3, poll_register);
-
-// unregister(obj)
-STATIC mp_obj_t poll_unregister(mp_obj_t self_in, mp_obj_t obj_in) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
- mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
- // TODO raise KeyError if obj didn't exist in map
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_2(poll_unregister_obj, poll_unregister);
-
-// modify(obj, eventmask)
-STATIC mp_obj_t poll_modify(mp_obj_t self_in, mp_obj_t obj_in, mp_obj_t eventmask_in) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
- mp_map_elem_t *elem = mp_map_lookup(&self->poll_map, mp_obj_id(obj_in), MP_MAP_LOOKUP);
- if (elem == NULL) {
- mp_raise_OSError(MP_ENOENT);
- }
- ((poll_obj_t *)MP_OBJ_TO_PTR(elem->value))->flags = mp_obj_get_int(eventmask_in);
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_3(poll_modify_obj, poll_modify);
-
-STATIC mp_uint_t poll_poll_internal(uint n_args, const mp_obj_t *args) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
-
- // work out timeout (its given already in ms)
- mp_uint_t timeout = -1;
- int flags = 0;
- if (n_args >= 2) {
- if (args[1] != mp_const_none) {
- mp_int_t timeout_i = mp_obj_get_int(args[1]);
- if (timeout_i >= 0) {
- timeout = timeout_i;
- }
- }
- if (n_args >= 3) {
- flags = mp_obj_get_int(args[2]);
- }
- }
-
- self->flags = flags;
-
- mp_uint_t start_tick = mp_hal_ticks_ms();
- mp_uint_t n_ready;
- for (;;) {
- // poll the objects
- n_ready = poll_map_poll(&self->poll_map, NULL);
- if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
- break;
- }
- MICROPY_EVENT_POLL_HOOK
- }
-
- return n_ready;
-}
-
-STATIC mp_obj_t poll_poll(size_t n_args, const mp_obj_t *args) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
- mp_uint_t n_ready = poll_poll_internal(n_args, args);
-
- // one or more objects are ready, or we had a timeout
- mp_obj_list_t *ret_list = MP_OBJ_TO_PTR(mp_obj_new_list(n_ready, NULL));
- n_ready = 0;
- for (mp_uint_t i = 0; i < self->poll_map.alloc; ++i) {
- if (!mp_map_slot_is_filled(&self->poll_map, i)) {
- continue;
- }
- poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
- if (poll_obj->flags_ret != 0) {
- mp_obj_t tuple[2] = {poll_obj->obj, MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret)};
- ret_list->items[n_ready++] = mp_obj_new_tuple(2, tuple);
- if (self->flags & FLAG_ONESHOT) {
- // Don't poll next time, until new event flags will be set explicitly
- poll_obj->flags = 0;
- }
- }
- }
- return MP_OBJ_FROM_PTR(ret_list);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_poll_obj, 1, 3, poll_poll);
-
-STATIC mp_obj_t poll_ipoll(size_t n_args, const mp_obj_t *args) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(args[0]);
-
- if (self->ret_tuple == MP_OBJ_NULL) {
- self->ret_tuple = mp_obj_new_tuple(2, NULL);
- }
-
- int n_ready = poll_poll_internal(n_args, args);
- self->iter_cnt = n_ready;
- self->iter_idx = 0;
-
- return args[0];
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poll_ipoll_obj, 1, 3, poll_ipoll);
-
-STATIC mp_obj_t poll_iternext(mp_obj_t self_in) {
- mp_obj_poll_t *self = MP_OBJ_TO_PTR(self_in);
-
- if (self->iter_cnt == 0) {
- return MP_OBJ_STOP_ITERATION;
- }
-
- self->iter_cnt--;
-
- for (mp_uint_t i = self->iter_idx; i < self->poll_map.alloc; ++i) {
- self->iter_idx++;
- if (!mp_map_slot_is_filled(&self->poll_map, i)) {
- continue;
- }
- poll_obj_t *poll_obj = MP_OBJ_TO_PTR(self->poll_map.table[i].value);
- if (poll_obj->flags_ret != 0) {
- mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->ret_tuple);
- t->items[0] = poll_obj->obj;
- t->items[1] = MP_OBJ_NEW_SMALL_INT(poll_obj->flags_ret);
- if (self->flags & FLAG_ONESHOT) {
- // Don't poll next time, until new event flags will be set explicitly
- poll_obj->flags = 0;
- }
- return MP_OBJ_FROM_PTR(t);
- }
- }
-
- assert(!"inconsistent number of poll active entries");
- self->iter_cnt = 0;
- return MP_OBJ_STOP_ITERATION;
-}
-
-STATIC const mp_rom_map_elem_t poll_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_register), MP_ROM_PTR(&poll_register_obj) },
- { MP_ROM_QSTR(MP_QSTR_unregister), MP_ROM_PTR(&poll_unregister_obj) },
- { MP_ROM_QSTR(MP_QSTR_modify), MP_ROM_PTR(&poll_modify_obj) },
- { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&poll_poll_obj) },
- { MP_ROM_QSTR(MP_QSTR_ipoll), MP_ROM_PTR(&poll_ipoll_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(poll_locals_dict, poll_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- mp_type_poll,
- MP_QSTR_poll,
- MP_TYPE_FLAG_ITER_IS_ITERNEXT,
- iter, poll_iternext,
- locals_dict, &poll_locals_dict
- );
-
-// poll()
-STATIC mp_obj_t select_poll(void) {
- mp_obj_poll_t *poll = mp_obj_malloc(mp_obj_poll_t, &mp_type_poll);
- mp_map_init(&poll->poll_map, 0);
- poll->iter_cnt = 0;
- poll->ret_tuple = MP_OBJ_NULL;
- return MP_OBJ_FROM_PTR(poll);
-}
-MP_DEFINE_CONST_FUN_OBJ_0(mp_select_poll_obj, select_poll);
-
-STATIC const mp_rom_map_elem_t mp_module_select_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uselect) },
- #if MICROPY_PY_USELECT_SELECT
- { MP_ROM_QSTR(MP_QSTR_select), MP_ROM_PTR(&mp_select_select_obj) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mp_select_poll_obj) },
- { MP_ROM_QSTR(MP_QSTR_POLLIN), MP_ROM_INT(MP_STREAM_POLL_RD) },
- { MP_ROM_QSTR(MP_QSTR_POLLOUT), MP_ROM_INT(MP_STREAM_POLL_WR) },
- { MP_ROM_QSTR(MP_QSTR_POLLERR), MP_ROM_INT(MP_STREAM_POLL_ERR) },
- { MP_ROM_QSTR(MP_QSTR_POLLHUP), MP_ROM_INT(MP_STREAM_POLL_HUP) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_select_globals, mp_module_select_globals_table);
-
-const mp_obj_module_t mp_module_uselect = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_select_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uselect, mp_module_uselect);
-
-#endif // MICROPY_PY_USELECT
diff --git a/extmod/modusocket.c b/extmod/modusocket.c
deleted file mode 100644
index 194ee6899ede..000000000000
--- a/extmod/modusocket.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/objtuple.h"
-#include "py/objlist.h"
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "py/mperrno.h"
-#include "shared/netutils/netutils.h"
-#include "modnetwork.h"
-
-#if MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
-
-/******************************************************************************/
-// socket class
-
-STATIC const mp_obj_type_t socket_type;
-
-STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "",
- self->fileno, self->timeout, self->domain, self->type, self->proto, self->bound);
-}
-
-// constructor socket(domain=AF_INET, type=SOCK_STREAM, proto=0)
-STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 3, false);
-
- // create socket object (not bound to any NIC yet)
- mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
- s->base.type = &socket_type;
- s->nic = MP_OBJ_NULL;
- s->nic_type = NULL;
- s->domain = MOD_NETWORK_AF_INET;
- s->type = MOD_NETWORK_SOCK_STREAM;
- s->proto = 0;
- s->bound = false;
- s->fileno = -1;
- if (n_args > 0) {
- s->domain = mp_obj_get_int(args[0]);
- if (n_args > 1) {
- s->type = mp_obj_get_int(args[1]);
- if (n_args > 2) {
- s->proto = mp_obj_get_int(args[2]);
- }
- }
- }
- s->timeout = -1;
- s->callback = MP_OBJ_NULL;
- s->state = MOD_NETWORK_SS_NEW;
- #if MICROPY_PY_USOCKET_EXTENDED_STATE
- s->_private = NULL;
- #endif
-
- return MP_OBJ_FROM_PTR(s);
-}
-
-STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
- if (self->nic == MP_OBJ_NULL) {
- // select NIC based on IP
- self->nic = mod_network_find_nic(ip);
- self->nic_type = (mod_network_nic_type_t *)mp_obj_get_type(self->nic);
-
- // call the NIC to open the socket
- int _errno;
- if (self->nic_type->socket(self, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- #if MICROPY_PY_USOCKET_EXTENDED_STATE
- // if a timeout was set before binding a NIC, call settimeout to reset it
- if (self->timeout != -1 && self->nic_type->settimeout(self, self->timeout, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
- #endif
- }
-}
-
-// method socket.bind(address)
-STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- // get address
- uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
-
- // check if we need to select a NIC
- socket_select_nic(self, ip);
-
- // call the NIC to bind the socket
- int _errno;
- if (self->nic_type->bind(self, ip, port, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
-
-// method socket.listen([backlog])
-STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-
- if (self->nic == MP_OBJ_NULL) {
- // not connected
- // TODO I think we can listen even if not bound...
- mp_raise_OSError(MP_ENOTCONN);
- }
-
- mp_int_t backlog = MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT;
- if (n_args > 1) {
- backlog = mp_obj_get_int(args[1]);
- backlog = (backlog < 0) ? 0 : backlog;
- }
-
- int _errno;
- if (self->nic_type->listen(self, backlog, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- // set socket state
- self->state = MOD_NETWORK_SS_LISTENING;
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
-
-// method socket.accept()
-STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- if (self->nic == MP_OBJ_NULL) {
- // not bound
- mp_raise_OSError(MP_EINVAL);
- }
-
- // create new socket object
- // starts with empty NIC so that finaliser doesn't run close() method if accept() fails
- mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
- socket2->base.type = &socket_type;
- socket2->nic = MP_OBJ_NULL;
- socket2->nic_type = NULL;
-
- // set the same address family, socket type and protocol as parent
- socket2->domain = self->domain;
- socket2->type = self->type;
- socket2->proto = self->proto;
- socket2->bound = false;
- socket2->fileno = -1;
- socket2->timeout = -1;
- socket2->callback = MP_OBJ_NULL;
- socket2->state = MOD_NETWORK_SS_NEW;
- #if MICROPY_PY_USOCKET_EXTENDED_STATE
- socket2->_private = NULL;
- #endif
-
- // accept incoming connection
- uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- mp_uint_t port;
- int _errno;
- if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- // new socket has valid state, so set the NIC to the same as parent
- socket2->nic = self->nic;
- socket2->nic_type = self->nic_type;
-
- // make the return value
- mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
- client->items[0] = MP_OBJ_FROM_PTR(socket2);
- client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
-
- return MP_OBJ_FROM_PTR(client);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
-
-// method socket.connect(address)
-STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- // get address
- uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
-
- // check if we need to select a NIC
- socket_select_nic(self, ip);
-
- // call the NIC to connect the socket
- int _errno;
- if (self->nic_type->connect(self, ip, port, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- // set socket state
- self->state = MOD_NETWORK_SS_CONNECTED;
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
-
-// method socket.send(bytes)
-STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- // not connected
- mp_raise_OSError(MP_EPIPE);
- }
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
- int _errno;
- mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- }
- return mp_obj_new_int_from_uint(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
-
-STATIC mp_obj_t socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- // not connected
- mp_raise_OSError(MP_EPIPE);
- }
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
-
- int _errno;
- mp_uint_t ret = 0;
- if (self->timeout == 0) {
- ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- } else if (bufinfo.len > ret) {
- mp_raise_OSError(MP_EAGAIN);
- }
- } else {
- // TODO: In CPython3.5, socket timeout should apply to the
- // entire sendall() operation, not to individual send() chunks.
- while (bufinfo.len != 0) {
- ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- }
- bufinfo.len -= ret;
- bufinfo.buf = (char *)bufinfo.buf + ret;
- }
- }
- return mp_obj_new_int_from_uint(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall);
-
-// method socket.recv(bufsize)
-STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- // not connected
- mp_raise_OSError(MP_ENOTCONN);
- }
- mp_int_t len = mp_obj_get_int(len_in);
- vstr_t vstr;
- vstr_init_len(&vstr, len);
- int _errno;
- mp_uint_t ret = self->nic_type->recv(self, (byte *)vstr.buf, len, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- }
- if (ret == 0) {
- return mp_const_empty_bytes;
- }
- vstr.len = ret;
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
-
-// method socket.sendto(bytes, address)
-STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
-
- // get the data
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
-
- // get address
- uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
-
- // check if we need to select a NIC
- socket_select_nic(self, ip);
-
- // call the NIC to sendto
- int _errno;
- mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- }
-
- return mp_obj_new_int(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
-
-// method socket.recvfrom(bufsize)
-STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- // not connected
- mp_raise_OSError(MP_ENOTCONN);
- }
- vstr_t vstr;
- vstr_init_len(&vstr, mp_obj_get_int(len_in));
- byte ip[4];
- mp_uint_t port;
- int _errno;
- mp_int_t ret = self->nic_type->recvfrom(self, (byte *)vstr.buf, vstr.len, ip, &port, &_errno);
- if (ret == -1) {
- mp_raise_OSError(_errno);
- }
- mp_obj_t tuple[2];
- if (ret == 0) {
- tuple[0] = mp_const_empty_bytes;
- } else {
- vstr.len = ret;
- tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
- }
- tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
- return mp_obj_new_tuple(2, tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
-
-// method socket.setsockopt(level, optname, value)
-STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
-
- if (self->nic == MP_OBJ_NULL) {
- // bind to default NIC.
- uint8_t ip[4] = {0, 0, 0, 0};
- socket_select_nic(self, ip);
- }
-
- mp_int_t level = mp_obj_get_int(args[1]);
- mp_int_t opt = mp_obj_get_int(args[2]);
-
- const void *optval;
- mp_uint_t optlen;
- mp_int_t val;
- if (mp_obj_is_integer(args[3])) {
- val = mp_obj_get_int_truncated(args[3]);
- optval = &val;
- optlen = sizeof(val);
- } else if (opt == 20 && args[3] == mp_const_none) {
- optval = MP_OBJ_NULL;
- optlen = 0;
- } else if (opt == 20 && mp_obj_is_callable(args[3])) {
- optval = args[3];
- optlen = sizeof(optval);
- } else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
- optval = bufinfo.buf;
- optlen = bufinfo.len;
- }
-
- int _errno;
- if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
-
-STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- return args[0];
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
-
-// method socket.settimeout(value)
-// timeout=0 means non-blocking
-// timeout=None means blocking
-// otherwise, timeout is in seconds
-STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- mp_uint_t timeout;
- if (timeout_in == mp_const_none) {
- timeout = -1;
- } else {
- #if MICROPY_PY_BUILTINS_FLOAT
- timeout = (mp_uint_t)(MICROPY_FLOAT_CONST(1000.0) * mp_obj_get_float(timeout_in));
- #else
- timeout = 1000 * mp_obj_get_int(timeout_in);
- #endif
- }
- if (self->nic == MP_OBJ_NULL) {
- #if MICROPY_PY_USOCKET_EXTENDED_STATE
- // store the timeout in the socket state until a NIC is bound
- self->timeout = timeout;
- #else
- // not connected
- mp_raise_OSError(MP_ENOTCONN);
- #endif
- } else {
- int _errno;
- if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
-
-// method socket.setblocking(flag)
-STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
- if (mp_obj_is_true(blocking)) {
- return socket_settimeout(self_in, mp_const_none);
- } else {
- return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-
-STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
- { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
- { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
- { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
- { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
- { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) },
- { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
- { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
- { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
- { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
- { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
- { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
- { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
-
-mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- return MP_STREAM_ERROR;
- }
- mp_int_t ret = self->nic_type->recv(self, (byte *)buf, size, errcode);
- if (ret < 0) {
- ret = MP_STREAM_ERROR;
- }
- return ret;
-}
-
-mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->nic == MP_OBJ_NULL) {
- return MP_STREAM_ERROR;
- }
- mp_int_t ret = self->nic_type->send(self, buf, size, errcode);
- if (ret < 0) {
- ret = MP_STREAM_ERROR;
- }
- return ret;
-}
-
-mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
- mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (request == MP_STREAM_CLOSE) {
- if (self->nic != MP_OBJ_NULL) {
- self->nic_type->close(self);
- self->nic = MP_OBJ_NULL;
- }
- self->state = MOD_NETWORK_SS_CLOSED;
- return 0;
- }
- if (self->nic == MP_OBJ_NULL) {
- if (request == MP_STREAM_POLL) {
- if (self->state == MOD_NETWORK_SS_NEW) {
- // New sockets are writable and not connected.
- return MP_STREAM_POLL_HUP | MP_STREAM_POLL_WR;
- } else if (self->state == MOD_NETWORK_SS_CLOSED) {
- // Closed socket, return invalid.
- return MP_STREAM_POLL_NVAL;
- }
- }
- *errcode = MP_EINVAL;
- return MP_STREAM_ERROR;
- }
- return self->nic_type->ioctl(self, request, arg, errcode);
-}
-
-STATIC const mp_stream_p_t socket_stream_p = {
- .read = socket_read,
- .write = socket_write,
- .ioctl = socket_ioctl,
- .is_text = false,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- socket_type,
- MP_QSTR_socket,
- MP_TYPE_FLAG_NONE,
- make_new, socket_make_new,
- protocol, &socket_stream_p,
- locals_dict, &socket_locals_dict,
- print, socket_print
- );
-
-/******************************************************************************/
-// usocket module
-
-// function usocket.getaddrinfo(host, port)
-STATIC mp_obj_t mod_usocket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
- size_t hlen;
- const char *host = mp_obj_str_get_data(args[0], &hlen);
- mp_int_t port = mp_obj_get_int(args[1]);
- uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE];
- bool have_ip = false;
-
- // if constraints were passed then check they are compatible with the supported params
- if (n_args > 2) {
- mp_int_t family = mp_obj_get_int(args[2]);
- mp_int_t type = 0;
- mp_int_t proto = 0;
- mp_int_t flags = 0;
- if (n_args > 3) {
- type = mp_obj_get_int(args[3]);
- if (n_args > 4) {
- proto = mp_obj_get_int(args[4]);
- if (n_args > 5) {
- flags = mp_obj_get_int(args[5]);
- }
- }
- }
- if (!((family == 0 || family == MOD_NETWORK_AF_INET)
- && (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
- && proto == 0
- && flags == 0)) {
- mp_warning(MP_WARN_CAT(RuntimeWarning), "unsupported getaddrinfo constraints");
- }
- }
-
- if (hlen > 0) {
- // check if host is already in IP form
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- netutils_parse_ipv4_addr(args[0], out_ip, NETUTILS_BIG);
- have_ip = true;
- nlr_pop();
- } else {
- // swallow exception: host was not in IP form so need to do DNS lookup
- }
- }
-
- if (!have_ip) {
- // find a NIC that can do a name lookup
- for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) {
- mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i];
- mod_network_nic_type_t *nic_type = (mod_network_nic_type_t *)mp_obj_get_type(nic);
- if (nic_type->gethostbyname != NULL) {
- int ret = nic_type->gethostbyname(nic, host, hlen, out_ip);
- if (ret != 0) {
- mp_raise_OSError(ret);
- }
- have_ip = true;
- break;
- }
- }
- }
-
- if (!have_ip) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("no available NIC"));
- }
-
- mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
- tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
- tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
- tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
- tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
- tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG);
- return mp_obj_new_list(1, (mp_obj_t *)&tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_usocket_getaddrinfo_obj, 2, 6, mod_usocket_getaddrinfo);
-
-STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
-
- { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
- { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) },
-
- // class constants
- { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) },
- { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) },
-
- { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) },
- { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) },
- { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) },
-
- { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(MOD_NETWORK_SOL_SOCKET) },
- { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(MOD_NETWORK_SO_REUSEADDR) },
- { MP_ROM_QSTR(MP_QSTR_SO_KEEPALIVE), MP_ROM_INT(MOD_NETWORK_SO_KEEPALIVE) },
- { MP_ROM_QSTR(MP_QSTR_SO_SNDTIMEO), MP_ROM_INT(MOD_NETWORK_SO_SNDTIMEO) },
- { MP_ROM_QSTR(MP_QSTR_SO_RCVTIMEO), MP_ROM_INT(MOD_NETWORK_SO_RCVTIMEO) },
-
- /*
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(MOD_NETWORK_IPPROTO_IP) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_ICMP), MP_ROM_INT(MOD_NETWORK_IPPROTO_ICMP) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV4), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV4) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(MOD_NETWORK_IPPROTO_TCP) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(MOD_NETWORK_IPPROTO_UDP) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV6), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV6) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_RAW), MP_ROM_INT(MOD_NETWORK_IPPROTO_RAW) },
- */
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
-
-const mp_obj_module_t mp_module_usocket = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_usocket_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_usocket, mp_module_usocket);
-
-#endif // MICROPY_PY_NETWORK && MICROPY_PY_USOCKET && !MICROPY_PY_LWIP
diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c
deleted file mode 100644
index 2eae46504835..000000000000
--- a/extmod/modussl_axtls.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2019 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "py/objstr.h"
-
-#if MICROPY_PY_USSL && MICROPY_SSL_AXTLS
-
-#include "ssl.h"
-
-typedef struct _mp_obj_ssl_socket_t {
- mp_obj_base_t base;
- mp_obj_t sock;
- SSL_CTX *ssl_ctx;
- SSL *ssl_sock;
- byte *buf;
- uint32_t bytes_left;
- bool blocking;
-} mp_obj_ssl_socket_t;
-
-struct ssl_args {
- mp_arg_val_t key;
- mp_arg_val_t cert;
- mp_arg_val_t server_side;
- mp_arg_val_t server_hostname;
- mp_arg_val_t do_handshake;
-};
-
-STATIC const mp_obj_type_t ussl_socket_type;
-
-// Table of error strings corresponding to SSL_xxx error codes.
-STATIC const char *const ssl_error_tab1[] = {
- "NOT_OK",
- "DEAD",
- "CLOSE_NOTIFY",
- "EAGAIN",
-};
-STATIC const char *const ssl_error_tab2[] = {
- "CONN_LOST",
- "RECORD_OVERFLOW",
- "SOCK_SETUP_FAILURE",
- NULL,
- "INVALID_HANDSHAKE",
- "INVALID_PROT_MSG",
- "INVALID_HMAC",
- "INVALID_VERSION",
- "UNSUPPORTED_EXTENSION",
- "INVALID_SESSION",
- "NO_CIPHER",
- "INVALID_CERT_HASH_ALG",
- "BAD_CERTIFICATE",
- "INVALID_KEY",
- NULL,
- "FINISHED_INVALID",
- "NO_CERT_DEFINED",
- "NO_CLIENT_RENOG",
- "NOT_SUPPORTED",
-};
-
-STATIC NORETURN void ussl_raise_error(int err) {
- MP_STATIC_ASSERT(SSL_NOT_OK - 3 == SSL_EAGAIN);
- MP_STATIC_ASSERT(SSL_ERROR_CONN_LOST - 18 == SSL_ERROR_NOT_SUPPORTED);
-
- // Check if err corresponds to something in one of the error string tables.
- const char *errstr = NULL;
- if (SSL_NOT_OK >= err && err >= SSL_EAGAIN) {
- errstr = ssl_error_tab1[SSL_NOT_OK - err];
- } else if (SSL_ERROR_CONN_LOST >= err && err >= SSL_ERROR_NOT_SUPPORTED) {
- errstr = ssl_error_tab2[SSL_ERROR_CONN_LOST - err];
- }
-
- // Unknown error, just raise the error code.
- if (errstr == NULL) {
- mp_raise_OSError(err);
- }
-
- // Construct string object.
- mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
- if (o_str == NULL) {
- mp_raise_OSError(err);
- }
- o_str->base.type = &mp_type_str;
- o_str->data = (const byte *)errstr;
- o_str->len = strlen((char *)o_str->data);
- o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
-
- // Raise OSError(err, str).
- mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
- nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
-}
-
-
-STATIC mp_obj_ssl_socket_t *ussl_socket_new(mp_obj_t sock, struct ssl_args *args) {
- #if MICROPY_PY_USSL_FINALISER
- mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
- #else
- mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
- #endif
- o->base.type = &ussl_socket_type;
- o->buf = NULL;
- o->bytes_left = 0;
- o->sock = sock;
- o->blocking = true;
-
- uint32_t options = SSL_SERVER_VERIFY_LATER;
- if (!args->do_handshake.u_bool) {
- options |= SSL_CONNECT_IN_PARTS;
- }
- if (args->key.u_obj != mp_const_none) {
- options |= SSL_NO_DEFAULT_KEY;
- }
- if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
- mp_raise_OSError(MP_EINVAL);
- }
-
- if (args->key.u_obj != mp_const_none) {
- size_t len;
- const byte *data = (const byte *)mp_obj_str_get_data(args->key.u_obj, &len);
- int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL);
- if (res != SSL_OK) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid key"));
- }
-
- data = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &len);
- res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL);
- if (res != SSL_OK) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid cert"));
- }
- }
-
- if (args->server_side.u_bool) {
- o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock);
- } else {
- SSL_EXTENSIONS *ext = ssl_ext_new();
-
- if (args->server_hostname.u_obj != mp_const_none) {
- ext->host_name = (char *)mp_obj_str_get_str(args->server_hostname.u_obj);
- }
-
- o->ssl_sock = ssl_client_new(o->ssl_ctx, (long)sock, NULL, 0, ext);
-
- if (args->do_handshake.u_bool) {
- int r = ssl_handshake_status(o->ssl_sock);
-
- if (r != SSL_OK) {
- if (r == SSL_CLOSE_NOTIFY) { // EOF
- r = MP_ENOTCONN;
- } else if (r == SSL_EAGAIN) {
- r = MP_EAGAIN;
- }
- ussl_raise_error(r);
- }
- }
-
- }
-
- return o;
-}
-
-STATIC void ussl_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- (void)kind;
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "<_SSLSocket %p>", self->ssl_sock);
-}
-
-STATIC mp_uint_t ussl_socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
-
- if (o->ssl_sock == NULL) {
- *errcode = EBADF;
- return MP_STREAM_ERROR;
- }
-
- while (o->bytes_left == 0) {
- mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
- if (r == SSL_OK) {
- // SSL_OK from ssl_read() means "everything is ok, but there's
- // no user data yet". It may happen e.g. if handshake is not
- // finished yet. The best way we can treat it is by returning
- // EAGAIN. This may be a bit unexpected in blocking mode, but
- // default is to perform complete handshake in constructor, so
- // this should not happen in blocking mode. On the other hand,
- // in nonblocking mode EAGAIN (comparing to the alternative of
- // looping) is really preferrable.
- if (o->blocking) {
- continue;
- } else {
- goto eagain;
- }
- }
- if (r < 0) {
- if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
- // EOF
- return 0;
- }
- if (r == SSL_EAGAIN) {
- eagain:
- r = MP_EAGAIN;
- }
- *errcode = r;
- return MP_STREAM_ERROR;
- }
- o->bytes_left = r;
- }
-
- if (size > o->bytes_left) {
- size = o->bytes_left;
- }
- memcpy(buf, o->buf, size);
- o->buf += size;
- o->bytes_left -= size;
- return size;
-}
-
-STATIC mp_uint_t ussl_socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
-
- if (o->ssl_sock == NULL) {
- *errcode = EBADF;
- return MP_STREAM_ERROR;
- }
-
- mp_int_t r;
-eagain:
- r = ssl_write(o->ssl_sock, buf, size);
- if (r == 0) {
- // see comment in ussl_socket_read above
- if (o->blocking) {
- goto eagain;
- } else {
- r = SSL_EAGAIN;
- }
- }
- if (r < 0) {
- if (r == SSL_CLOSE_NOTIFY || r == SSL_ERROR_CONN_LOST) {
- return 0; // EOF
- }
- if (r == SSL_EAGAIN) {
- r = MP_EAGAIN;
- }
- *errcode = r;
- return MP_STREAM_ERROR;
- }
- return r;
-}
-
-STATIC mp_uint_t ussl_socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
- if (request == MP_STREAM_CLOSE && self->ssl_sock != NULL) {
- ssl_free(self->ssl_sock);
- ssl_ctx_free(self->ssl_ctx);
- self->ssl_sock = NULL;
- }
- // Pass all requests down to the underlying socket
- return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
-}
-
-STATIC mp_obj_t ussl_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
- mp_obj_t sock = o->sock;
- mp_obj_t dest[3];
- mp_load_method(sock, MP_QSTR_setblocking, dest);
- dest[2] = flag_in;
- mp_obj_t res = mp_call_method_n_kw(1, 0, dest);
- o->blocking = mp_obj_is_true(flag_in);
- return res;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(ussl_socket_setblocking_obj, ussl_socket_setblocking);
-
-STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&ussl_socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
- #if MICROPY_PY_USSL_FINALISER
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
-
-STATIC const mp_stream_p_t ussl_socket_stream_p = {
- .read = ussl_socket_read,
- .write = ussl_socket_write,
- .ioctl = ussl_socket_ioctl,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- ussl_socket_type,
- MP_QSTR_ussl,
- MP_TYPE_FLAG_NONE,
- // Save on qstr's, reuse same as for module
- print, ussl_socket_print,
- protocol, &ussl_socket_stream_p,
- locals_dict, &ussl_socket_locals_dict
- );
-
-STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- // TODO: Implement more args
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
- };
-
- // TODO: Check that sock implements stream protocol
- mp_obj_t sock = pos_args[0];
-
- struct ssl_args args;
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
- MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
-
- return MP_OBJ_FROM_PTR(ussl_socket_new(sock, &args));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
-
-STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
- { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
-
-const mp_obj_module_t mp_module_ussl = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ussl, mp_module_ussl);
-
-#endif // MICROPY_PY_USSL && MICROPY_SSL_AXTLS
diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c
deleted file mode 100644
index 95cf12c975af..000000000000
--- a/extmod/modussl_mbedtls.c
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Linaro Ltd.
- * Copyright (c) 2019 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-#if MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS
-
-#include
-#include
-#include // needed because mp_is_nonblocking_error uses system error codes
-
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "py/objstr.h"
-
-// mbedtls_time_t
-#include "mbedtls/platform.h"
-#include "mbedtls/ssl.h"
-#include "mbedtls/x509_crt.h"
-#include "mbedtls/pk.h"
-#include "mbedtls/entropy.h"
-#include "mbedtls/ctr_drbg.h"
-#include "mbedtls/debug.h"
-#include "mbedtls/error.h"
-
-typedef struct _mp_obj_ssl_socket_t {
- mp_obj_base_t base;
- mp_obj_t sock;
- mbedtls_entropy_context entropy;
- mbedtls_ctr_drbg_context ctr_drbg;
- mbedtls_ssl_context ssl;
- mbedtls_ssl_config conf;
- mbedtls_x509_crt cacert;
- mbedtls_x509_crt cert;
- mbedtls_pk_context pkey;
-} mp_obj_ssl_socket_t;
-
-struct ssl_args {
- mp_arg_val_t key;
- mp_arg_val_t cert;
- mp_arg_val_t server_side;
- mp_arg_val_t server_hostname;
- mp_arg_val_t cert_reqs;
- mp_arg_val_t cadata;
- mp_arg_val_t do_handshake;
-};
-
-STATIC const mp_obj_type_t ussl_socket_type;
-
-#ifdef MBEDTLS_DEBUG_C
-STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) {
- (void)ctx;
- (void)level;
- mp_printf(&mp_plat_print, "DBG:%s:%04d: %s\n", file, line, str);
-}
-#endif
-
-STATIC NORETURN void mbedtls_raise_error(int err) {
- // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the
- // underlying socket into negative codes to pass them through mbedtls. Here we turn them
- // positive again so they get interpreted as the OSError they really are. The
- // cut-off of -256 is a bit hacky, sigh.
- if (err < 0 && err > -256) {
- mp_raise_OSError(-err);
- }
-
- #if defined(MBEDTLS_ERROR_C)
- // Including mbedtls_strerror takes about 1.5KB due to the error strings.
- // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror.
- // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.
-
- // Try to allocate memory for the message
- #define ERR_STR_MAX 80 // mbedtls_strerror truncates if it doesn't fit
- mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t);
- byte *o_str_buf = m_new_maybe(byte, ERR_STR_MAX);
- if (o_str == NULL || o_str_buf == NULL) {
- mp_raise_OSError(err);
- }
-
- // print the error message into the allocated buffer
- mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX);
- size_t len = strlen((char *)o_str_buf);
-
- // Put the exception object together
- o_str->base.type = &mp_type_str;
- o_str->data = o_str_buf;
- o_str->len = len;
- o_str->hash = qstr_compute_hash(o_str->data, o_str->len);
- // raise
- mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)};
- nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args));
- #else
- // mbedtls is compiled without error strings so we simply return the err number
- mp_raise_OSError(err); // err is typically a large negative number
- #endif
-}
-
-STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
- mp_obj_t sock = *(mp_obj_t *)ctx;
-
- const mp_stream_p_t *sock_stream = mp_get_stream(sock);
- int err;
-
- mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
- if (out_sz == MP_STREAM_ERROR) {
- if (mp_is_nonblocking_error(err)) {
- return MBEDTLS_ERR_SSL_WANT_WRITE;
- }
- return -err; // convert an MP_ERRNO to something mbedtls passes through as error
- } else {
- return out_sz;
- }
-}
-
-// _mbedtls_ssl_recv is called by mbedtls to receive bytes from the underlying socket
-STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
- mp_obj_t sock = *(mp_obj_t *)ctx;
-
- const mp_stream_p_t *sock_stream = mp_get_stream(sock);
- int err;
-
- mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
- if (out_sz == MP_STREAM_ERROR) {
- if (mp_is_nonblocking_error(err)) {
- return MBEDTLS_ERR_SSL_WANT_READ;
- }
- return -err;
- } else {
- return out_sz;
- }
-}
-
-
-STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
- // Verify the socket object has the full stream protocol
- mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
-
- #if MICROPY_PY_USSL_FINALISER
- mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
- #else
- mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
- #endif
- o->base.type = &ussl_socket_type;
- o->sock = sock;
-
- int ret;
- mbedtls_ssl_init(&o->ssl);
- mbedtls_ssl_config_init(&o->conf);
- mbedtls_x509_crt_init(&o->cacert);
- mbedtls_x509_crt_init(&o->cert);
- mbedtls_pk_init(&o->pkey);
- mbedtls_ctr_drbg_init(&o->ctr_drbg);
- #ifdef MBEDTLS_DEBUG_C
- // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose
- mbedtls_debug_set_threshold(3);
- #endif
-
- mbedtls_entropy_init(&o->entropy);
- const byte seed[] = "upy";
- ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed));
- if (ret != 0) {
- goto cleanup;
- }
-
- ret = mbedtls_ssl_config_defaults(&o->conf,
- args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
- MBEDTLS_SSL_TRANSPORT_STREAM,
- MBEDTLS_SSL_PRESET_DEFAULT);
- if (ret != 0) {
- goto cleanup;
- }
-
- mbedtls_ssl_conf_authmode(&o->conf, args->cert_reqs.u_int);
- mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg);
- #ifdef MBEDTLS_DEBUG_C
- mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL);
- #endif
-
- ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
- if (ret != 0) {
- goto cleanup;
- }
-
- if (args->server_hostname.u_obj != mp_const_none) {
- const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
- ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
- if (ret != 0) {
- goto cleanup;
- }
- }
-
- mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
-
- if (args->key.u_obj != mp_const_none) {
- size_t key_len;
- const byte *key = (const byte *)mp_obj_str_get_data(args->key.u_obj, &key_len);
- // len should include terminating null
- ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0);
- if (ret != 0) {
- ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; // use general error for all key errors
- goto cleanup;
- }
-
- size_t cert_len;
- const byte *cert = (const byte *)mp_obj_str_get_data(args->cert.u_obj, &cert_len);
- // len should include terminating null
- ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1);
- if (ret != 0) {
- ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors
- goto cleanup;
- }
-
- ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey);
- if (ret != 0) {
- goto cleanup;
- }
- }
-
- if (args->cadata.u_obj != mp_const_none) {
- size_t cacert_len;
- const byte *cacert = (const byte *)mp_obj_str_get_data(args->cadata.u_obj, &cacert_len);
- // len should include terminating null
- ret = mbedtls_x509_crt_parse(&o->cacert, cacert, cacert_len + 1);
- if (ret != 0) {
- ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; // use general error for all cert errors
- goto cleanup;
- }
-
- mbedtls_ssl_conf_ca_chain(&o->conf, &o->cacert, NULL);
- }
-
- if (args->do_handshake.u_bool) {
- while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
- if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- goto cleanup;
- }
- #ifdef MICROPY_EVENT_POLL_HOOK
- MICROPY_EVENT_POLL_HOOK
- #endif
- }
- }
-
- return o;
-
-cleanup:
- mbedtls_pk_free(&o->pkey);
- mbedtls_x509_crt_free(&o->cert);
- mbedtls_x509_crt_free(&o->cacert);
- mbedtls_ssl_free(&o->ssl);
- mbedtls_ssl_config_free(&o->conf);
- mbedtls_ctr_drbg_free(&o->ctr_drbg);
- mbedtls_entropy_free(&o->entropy);
-
- if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
- mp_raise_OSError(MP_ENOMEM);
- } else if (ret == MBEDTLS_ERR_PK_BAD_INPUT_DATA) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid key"));
- } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid cert"));
- } else {
- mbedtls_raise_error(ret);
- }
-}
-
-STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
- if (!mp_obj_is_true(binary_form)) {
- mp_raise_NotImplementedError(NULL);
- }
- const mbedtls_x509_crt *peer_cert = mbedtls_ssl_get_peer_cert(&o->ssl);
- if (peer_cert == NULL) {
- return mp_const_none;
- }
- return mp_obj_new_bytes(peer_cert->raw.p, peer_cert->raw.len);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ssl_getpeercert_obj, mod_ssl_getpeercert);
-
-STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- (void)kind;
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
- mp_printf(print, "<_SSLSocket %p>", self);
-}
-
-STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
-
- int ret = mbedtls_ssl_read(&o->ssl, buf, size);
- if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
- // end of stream
- return 0;
- }
- if (ret >= 0) {
- return ret;
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
- ret = MP_EWOULDBLOCK;
- } else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- // If handshake is not finished, read attempt may end up in protocol
- // wanting to write next handshake message. The same may happen with
- // renegotation.
- ret = MP_EWOULDBLOCK;
- }
- *errcode = ret;
- return MP_STREAM_ERROR;
-}
-
-STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(o_in);
-
- int ret = mbedtls_ssl_write(&o->ssl, buf, size);
- if (ret >= 0) {
- return ret;
- }
- if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- ret = MP_EWOULDBLOCK;
- } else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
- // If handshake is not finished, write attempt may end up in protocol
- // wanting to read next handshake message. The same may happen with
- // renegotation.
- ret = MP_EWOULDBLOCK;
- }
- *errcode = ret;
- return MP_STREAM_ERROR;
-}
-
-STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
- mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
- mp_obj_t sock = o->sock;
- mp_obj_t dest[3];
- mp_load_method(sock, MP_QSTR_setblocking, dest);
- dest[2] = flag_in;
- return mp_call_method_n_kw(1, 0, dest);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-
-STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
- if (request == MP_STREAM_CLOSE) {
- mbedtls_pk_free(&self->pkey);
- mbedtls_x509_crt_free(&self->cert);
- mbedtls_x509_crt_free(&self->cacert);
- mbedtls_ssl_free(&self->ssl);
- mbedtls_ssl_config_free(&self->conf);
- mbedtls_ctr_drbg_free(&self->ctr_drbg);
- mbedtls_entropy_free(&self->entropy);
- }
- // Pass all requests down to the underlying socket
- return mp_get_stream(self->sock)->ioctl(self->sock, request, arg, errcode);
-}
-
-STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
- #if MICROPY_PY_USSL_FINALISER
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_table);
-
-STATIC const mp_stream_p_t ussl_socket_stream_p = {
- .read = socket_read,
- .write = socket_write,
- .ioctl = socket_ioctl,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- ussl_socket_type,
- MP_QSTR_ussl,
- MP_TYPE_FLAG_NONE,
- // Save on qstr's, reuse same as for module
- print, socket_print,
- protocol, &ussl_socket_stream_p,
- locals_dict, &ussl_socket_locals_dict
- );
-
-STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- // TODO: Implement more args
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MBEDTLS_SSL_VERIFY_NONE}},
- { MP_QSTR_cadata, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_do_handshake, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
- };
-
- // TODO: Check that sock implements stream protocol
- mp_obj_t sock = pos_args[0];
-
- struct ssl_args args;
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
- MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args);
-
- return MP_OBJ_FROM_PTR(socket_new(sock, &args));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
-
-STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
- { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
- { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(MBEDTLS_SSL_VERIFY_NONE) },
- { MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(MBEDTLS_SSL_VERIFY_OPTIONAL) },
- { MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(MBEDTLS_SSL_VERIFY_REQUIRED) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
-
-const mp_obj_module_t mp_module_ussl = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_ssl_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ussl, mp_module_ussl);
-
-#endif // MICROPY_PY_USSL && MICROPY_SSL_MBEDTLS
diff --git a/extmod/modutimeq.c b/extmod/modutimeq.c
deleted file mode 100644
index 1a38104eafcd..000000000000
--- a/extmod/modutimeq.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Damien P. George
- * Copyright (c) 2016-2017 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-
-#include "py/objlist.h"
-#include "py/runtime.h"
-#include "py/smallint.h"
-
-#if MICROPY_PY_UTIMEQ
-
-#define MODULO MICROPY_PY_UTIME_TICKS_PERIOD
-
-#define DEBUG 0
-
-// the algorithm here is modelled on CPython's heapq.py
-
-struct qentry {
- mp_uint_t time;
- mp_uint_t id;
- mp_obj_t callback;
- mp_obj_t args;
-};
-
-typedef struct _mp_obj_utimeq_t {
- mp_obj_base_t base;
- mp_uint_t alloc;
- mp_uint_t len;
- struct qentry items[];
-} mp_obj_utimeq_t;
-
-STATIC mp_uint_t utimeq_id;
-
-STATIC mp_obj_utimeq_t *utimeq_get_heap(mp_obj_t heap_in) {
- return MP_OBJ_TO_PTR(heap_in);
-}
-
-STATIC bool time_less_than(struct qentry *item, struct qentry *parent) {
- mp_uint_t item_tm = item->time;
- mp_uint_t parent_tm = parent->time;
- mp_uint_t res = parent_tm - item_tm;
- if (res == 0) {
- // TODO: This actually should use the same "ring" logic
- // as for time, to avoid artifacts when id's overflow.
- return item->id < parent->id;
- }
- if ((mp_int_t)res < 0) {
- res += MODULO;
- }
- return res && res < (MODULO / 2);
-}
-
-STATIC mp_obj_t utimeq_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 1, false);
- mp_uint_t alloc = mp_obj_get_int(args[0]);
- mp_obj_utimeq_t *o = mp_obj_malloc_var(mp_obj_utimeq_t, struct qentry, alloc, type);
- memset(o->items, 0, sizeof(*o->items) * alloc);
- o->alloc = alloc;
- o->len = 0;
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC void utimeq_heap_siftdown(mp_obj_utimeq_t *heap, mp_uint_t start_pos, mp_uint_t pos) {
- struct qentry item = heap->items[pos];
- while (pos > start_pos) {
- mp_uint_t parent_pos = (pos - 1) >> 1;
- struct qentry *parent = &heap->items[parent_pos];
- bool lessthan = time_less_than(&item, parent);
- if (lessthan) {
- heap->items[pos] = *parent;
- pos = parent_pos;
- } else {
- break;
- }
- }
- heap->items[pos] = item;
-}
-
-STATIC void utimeq_heap_siftup(mp_obj_utimeq_t *heap, mp_uint_t pos) {
- mp_uint_t start_pos = pos;
- mp_uint_t end_pos = heap->len;
- struct qentry item = heap->items[pos];
- for (mp_uint_t child_pos = 2 * pos + 1; child_pos < end_pos; child_pos = 2 * pos + 1) {
- // choose right child if it's <= left child
- if (child_pos + 1 < end_pos) {
- bool lessthan = time_less_than(&heap->items[child_pos], &heap->items[child_pos + 1]);
- if (!lessthan) {
- child_pos += 1;
- }
- }
- // bubble up the smaller child
- heap->items[pos] = heap->items[child_pos];
- pos = child_pos;
- }
- heap->items[pos] = item;
- utimeq_heap_siftdown(heap, start_pos, pos);
-}
-
-STATIC mp_obj_t mod_utimeq_heappush(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- mp_obj_t heap_in = args[0];
- mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
- if (heap->len == heap->alloc) {
- mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("queue overflow"));
- }
- mp_uint_t l = heap->len;
- heap->items[l].time = MP_OBJ_SMALL_INT_VALUE(args[1]);
- heap->items[l].id = utimeq_id++;
- heap->items[l].callback = args[2];
- heap->items[l].args = args[3];
- utimeq_heap_siftdown(heap, 0, heap->len);
- heap->len++;
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_utimeq_heappush_obj, 4, 4, mod_utimeq_heappush);
-
-STATIC mp_obj_t mod_utimeq_heappop(mp_obj_t heap_in, mp_obj_t list_ref) {
- mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
- if (heap->len == 0) {
- mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
- }
- mp_obj_list_t *ret = MP_OBJ_TO_PTR(list_ref);
- if (!mp_obj_is_type(list_ref, &mp_type_list) || ret->len < 3) {
- mp_raise_TypeError(NULL);
- }
-
- struct qentry *item = &heap->items[0];
- ret->items[0] = MP_OBJ_NEW_SMALL_INT(item->time);
- ret->items[1] = item->callback;
- ret->items[2] = item->args;
- heap->len -= 1;
- heap->items[0] = heap->items[heap->len];
- heap->items[heap->len].callback = MP_OBJ_NULL; // so we don't retain a pointer
- heap->items[heap->len].args = MP_OBJ_NULL;
- if (heap->len) {
- utimeq_heap_siftup(heap, 0);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_utimeq_heappop_obj, mod_utimeq_heappop);
-
-STATIC mp_obj_t mod_utimeq_peektime(mp_obj_t heap_in) {
- mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
- if (heap->len == 0) {
- mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty heap"));
- }
-
- struct qentry *item = &heap->items[0];
- return MP_OBJ_NEW_SMALL_INT(item->time);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_peektime_obj, mod_utimeq_peektime);
-
-#if DEBUG
-STATIC mp_obj_t mod_utimeq_dump(mp_obj_t heap_in) {
- mp_obj_utimeq_t *heap = utimeq_get_heap(heap_in);
- for (int i = 0; i < heap->len; i++) {
- printf(UINT_FMT "\t%p\t%p\n", heap->items[i].time,
- MP_OBJ_TO_PTR(heap->items[i].callback), MP_OBJ_TO_PTR(heap->items[i].args));
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_utimeq_dump_obj, mod_utimeq_dump);
-#endif
-
-STATIC mp_obj_t utimeq_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
- mp_obj_utimeq_t *self = MP_OBJ_TO_PTR(self_in);
- switch (op) {
- case MP_UNARY_OP_BOOL:
- return mp_obj_new_bool(self->len != 0);
- case MP_UNARY_OP_LEN:
- return MP_OBJ_NEW_SMALL_INT(self->len);
- default:
- return MP_OBJ_NULL; // op not supported
- }
-}
-
-STATIC const mp_rom_map_elem_t utimeq_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_push), MP_ROM_PTR(&mod_utimeq_heappush_obj) },
- { MP_ROM_QSTR(MP_QSTR_pop), MP_ROM_PTR(&mod_utimeq_heappop_obj) },
- { MP_ROM_QSTR(MP_QSTR_peektime), MP_ROM_PTR(&mod_utimeq_peektime_obj) },
- #if DEBUG
- { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_utimeq_dump_obj) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(utimeq_locals_dict, utimeq_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- utimeq_type,
- MP_QSTR_utimeq,
- MP_TYPE_FLAG_NONE,
- make_new, utimeq_make_new,
- unary_op, utimeq_unary_op,
- locals_dict, &utimeq_locals_dict
- );
-
-STATIC const mp_rom_map_elem_t mp_module_utimeq_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utimeq) },
- { MP_ROM_QSTR(MP_QSTR_utimeq), MP_ROM_PTR(&utimeq_type) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_utimeq_globals, mp_module_utimeq_globals_table);
-
-const mp_obj_module_t mp_module_utimeq = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_utimeq_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_utimeq, mp_module_utimeq);
-
-#endif // MICROPY_PY_UTIMEQ
diff --git a/extmod/moduwebsocket.c b/extmod/moduwebsocket.c
deleted file mode 100644
index 9b12fc86358c..000000000000
--- a/extmod/moduwebsocket.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "extmod/moduwebsocket.h"
-
-#if MICROPY_PY_UWEBSOCKET
-
-enum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL };
-
-enum { BLOCKING_WRITE = 0x80 };
-
-typedef struct _mp_obj_websocket_t {
- mp_obj_base_t base;
- mp_obj_t sock;
- uint32_t msg_sz;
- byte mask[4];
- byte state;
- byte to_recv;
- byte mask_pos;
- byte buf_pos;
- byte buf[6];
- byte opts;
- // Copy of last data frame flags
- byte ws_flags;
- // Copy of current frame flags
- byte last_flags;
-} mp_obj_websocket_t;
-
-STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode);
-
-STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 2, false);
- mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
- mp_obj_websocket_t *o = mp_obj_malloc(mp_obj_websocket_t, type);
- o->sock = args[0];
- o->state = FRAME_HEADER;
- o->to_recv = 2;
- o->mask_pos = 0;
- o->buf_pos = 0;
- o->opts = FRAME_TXT;
- if (n_args > 1 && args[1] == mp_const_true) {
- o->opts |= BLOCKING_WRITE;
- }
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
- mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
- const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
- while (1) {
- if (self->to_recv != 0) {
- mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);
- if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
- return out_sz;
- }
- self->buf_pos += out_sz;
- self->to_recv -= out_sz;
- if (self->to_recv != 0) {
- *errcode = MP_EAGAIN;
- return MP_STREAM_ERROR;
- }
- }
-
- switch (self->state) {
- case FRAME_HEADER: {
- // TODO: Split frame handling below is untested so far, so conservatively disable it
- assert(self->buf[0] & 0x80);
-
- // "Control frames MAY be injected in the middle of a fragmented message."
- // So, they must be processed before data frames (and not alter
- // self->ws_flags)
- byte frame_type = self->buf[0];
- self->last_flags = frame_type;
- frame_type &= FRAME_OPCODE_MASK;
-
- if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {
- // Preserve previous frame type
- self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);
- } else {
- self->ws_flags = self->buf[0];
- }
-
- // Reset mask in case someone will use "simplified" protocol
- // without masks.
- memset(self->mask, 0, sizeof(self->mask));
-
- int to_recv = 0;
- size_t sz = self->buf[1] & 0x7f;
- if (sz == 126) {
- // Msg size is next 2 bytes
- to_recv += 2;
- } else if (sz == 127) {
- // Msg size is next 8 bytes
- assert(0);
- }
- if (self->buf[1] & 0x80) {
- // Next 4 bytes is mask
- to_recv += 4;
- }
-
- self->buf_pos = 0;
- self->to_recv = to_recv;
- self->msg_sz = sz; // May be overridden by FRAME_OPT
- if (to_recv != 0) {
- self->state = FRAME_OPT;
- } else {
- if (frame_type >= FRAME_CLOSE) {
- self->state = CONTROL;
- } else {
- self->state = PAYLOAD;
- }
- }
- continue;
- }
-
- case FRAME_OPT: {
- if ((self->buf_pos & 3) == 2) {
- // First two bytes are message length
- self->msg_sz = (self->buf[0] << 8) | self->buf[1];
- }
- if (self->buf_pos >= 4) {
- // Last 4 bytes is mask
- memcpy(self->mask, self->buf + self->buf_pos - 4, 4);
- }
- self->buf_pos = 0;
- if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {
- self->state = CONTROL;
- } else {
- self->state = PAYLOAD;
- }
- continue;
- }
-
- case PAYLOAD:
- case CONTROL: {
- mp_uint_t out_sz = 0;
- if (self->msg_sz == 0) {
- // In case message had zero payload
- goto no_payload;
- }
-
- size_t sz = MIN(size, self->msg_sz);
- out_sz = stream_p->read(self->sock, buf, sz, errcode);
- if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
- return out_sz;
- }
-
- sz = out_sz;
- for (byte *p = buf; sz--; p++) {
- *p ^= self->mask[self->mask_pos++ & 3];
- }
-
- self->msg_sz -= out_sz;
- if (self->msg_sz == 0) {
- byte last_state;
- no_payload:
- last_state = self->state;
- self->state = FRAME_HEADER;
- self->to_recv = 2;
- self->mask_pos = 0;
- self->buf_pos = 0;
-
- // Handle control frame
- if (last_state == CONTROL) {
- byte frame_type = self->last_flags & FRAME_OPCODE_MASK;
- if (frame_type == FRAME_CLOSE) {
- static const char close_resp[2] = {0x88, 0};
- int err;
- websocket_write(self_in, close_resp, sizeof(close_resp), &err);
- return 0;
- }
-
- // DEBUG_printf("Finished receiving ctrl message %x, ignoring\n", self->last_flags);
- continue;
- }
- }
-
- if (out_sz != 0) {
- return out_sz;
- }
- // Empty (data) frame received is not EOF
- continue;
- }
-
- }
- }
-}
-
-STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
- mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
- assert(size < 0x10000);
- byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)};
- int hdr_sz;
- if (size < 126) {
- header[1] = size;
- hdr_sz = 2;
- } else {
- header[1] = 126;
- header[2] = size >> 8;
- header[3] = size & 0xff;
- hdr_sz = 4;
- }
-
- mp_obj_t dest[3];
- if (self->opts & BLOCKING_WRITE) {
- mp_load_method(self->sock, MP_QSTR_setblocking, dest);
- dest[2] = mp_const_true;
- mp_call_method_n_kw(1, 0, dest);
- }
-
- mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode);
- if (*errcode == 0) {
- out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode);
- }
-
- if (self->opts & BLOCKING_WRITE) {
- dest[2] = mp_const_false;
- mp_call_method_n_kw(1, 0, dest);
- }
-
- if (*errcode != 0) {
- return MP_STREAM_ERROR;
- }
- return out_sz;
-}
-
-STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
- mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
- switch (request) {
- case MP_STREAM_CLOSE:
- // TODO: Send close signaling to the other side, otherwise it's
- // abrupt close (connection abort).
- mp_stream_close(self->sock);
- return 0;
- case MP_STREAM_GET_DATA_OPTS:
- return self->ws_flags & FRAME_OPCODE_MASK;
- case MP_STREAM_SET_DATA_OPTS: {
- int cur = self->opts & FRAME_OPCODE_MASK;
- self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK);
- return cur;
- }
- default:
- *errcode = MP_EINVAL;
- return MP_STREAM_ERROR;
- }
-}
-
-STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);
-
-STATIC const mp_stream_p_t websocket_stream_p = {
- .read = websocket_read,
- .write = websocket_write,
- .ioctl = websocket_ioctl,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- websocket_type,
- MP_QSTR_websocket,
- MP_TYPE_FLAG_NONE,
- make_new, websocket_make_new,
- protocol, &websocket_stream_p,
- locals_dict, &websocket_locals_dict
- );
-
-STATIC const mp_rom_map_elem_t uwebsocket_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uwebsocket) },
- { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(uwebsocket_module_globals, uwebsocket_module_globals_table);
-
-const mp_obj_module_t mp_module_uwebsocket = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&uwebsocket_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uwebsocket, mp_module_uwebsocket);
-
-#endif // MICROPY_PY_UWEBSOCKET
diff --git a/extmod/moduwebsocket.h b/extmod/moduwebsocket.h
deleted file mode 100644
index c1ea291ed743..000000000000
--- a/extmod/moduwebsocket.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H
-#define MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H
-
-#define FRAME_OPCODE_MASK 0x0f
-enum {
- FRAME_CONT, FRAME_TXT, FRAME_BIN,
- FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG
-};
-
-#endif // MICROPY_INCLUDED_EXTMOD_MODUWEBSOCKET_H
diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c
deleted file mode 100644
index 14d15321a3c1..000000000000
--- a/extmod/moduzlib.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014-2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "py/mperrno.h"
-
-#if MICROPY_PY_UZLIB
-
-#include "lib/uzlib/tinf.h"
-
-#if 0 // print debugging info
-#define DEBUG_printf DEBUG_printf
-#else // don't print debugging info
-#define DEBUG_printf(...) (void)0
-#endif
-
-typedef struct _mp_obj_decompio_t {
- mp_obj_base_t base;
- mp_obj_t src_stream;
- TINF_DATA decomp;
- bool eof;
-} mp_obj_decompio_t;
-
-STATIC int read_src_stream(TINF_DATA *data) {
- byte *p = (void *)data;
- p -= offsetof(mp_obj_decompio_t, decomp);
- mp_obj_decompio_t *self = (mp_obj_decompio_t *)p;
-
- const mp_stream_p_t *stream = mp_get_stream(self->src_stream);
- int err;
- byte c;
- mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);
- if (out_sz == MP_STREAM_ERROR) {
- mp_raise_OSError(err);
- }
- if (out_sz == 0) {
- mp_raise_type(&mp_type_EOFError);
- }
- return c;
-}
-
-STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 1, 2, false);
- mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
- mp_obj_decompio_t *o = mp_obj_malloc(mp_obj_decompio_t, type);
- memset(&o->decomp, 0, sizeof(o->decomp));
- o->decomp.readSource = read_src_stream;
- o->src_stream = args[0];
- o->eof = false;
-
- mp_int_t dict_opt = 0;
- uint dict_sz;
- if (n_args > 1) {
- dict_opt = mp_obj_get_int(args[1]);
- }
-
- if (dict_opt >= 16) {
- int st = uzlib_gzip_parse_header(&o->decomp);
- if (st != TINF_OK) {
- goto header_error;
- }
- dict_sz = 1 << (dict_opt - 16);
- } else if (dict_opt >= 0) {
- dict_opt = uzlib_zlib_parse_header(&o->decomp);
- if (dict_opt < 0) {
- header_error:
- mp_raise_ValueError(MP_ERROR_TEXT("compression header"));
- }
- // RFC 1950 section 2.2:
- // CINFO is the base-2 logarithm of the LZ77 window size,
- // minus eight (CINFO=7 indicates a 32K window size)
- dict_sz = 1 << (dict_opt + 8);
- } else {
- dict_sz = 1 << -dict_opt;
- }
-
- uzlib_uncompress_init(&o->decomp, m_new(byte, dict_sz), dict_sz);
- return MP_OBJ_FROM_PTR(o);
-}
-
-STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
- mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in);
- if (o->eof) {
- return 0;
- }
-
- o->decomp.dest = buf;
- o->decomp.dest_limit = (byte *)buf + size;
- int st = uzlib_uncompress_chksum(&o->decomp);
- if (st == TINF_DONE) {
- o->eof = true;
- }
- if (st < 0) {
- DEBUG_printf("uncompress error=" INT_FMT "\n", st);
- *errcode = MP_EINVAL;
- return MP_STREAM_ERROR;
- }
- return o->decomp.dest - (byte *)buf;
-}
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table);
-#endif
-
-STATIC const mp_stream_p_t decompio_stream_p = {
- .read = decompio_read,
-};
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- decompio_type,
- MP_QSTR_DecompIO,
- MP_TYPE_FLAG_NONE,
- make_new, decompio_make_new,
- protocol, &decompio_stream_p,
- locals_dict, &decompio_locals_dict
- );
-#endif
-
-STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) {
- mp_obj_t data = args[0];
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
-
- TINF_DATA *decomp = m_new_obj(TINF_DATA);
- memset(decomp, 0, sizeof(*decomp));
- DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp));
- uzlib_uncompress_init(decomp, NULL, 0);
- mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15;
- byte *dest_buf = m_new(byte, dest_buf_size);
-
- decomp->dest = dest_buf;
- decomp->dest_limit = dest_buf + dest_buf_size;
- DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", dest_buf_size);
- decomp->source = bufinfo.buf;
- decomp->source_limit = (byte *)bufinfo.buf + bufinfo.len;
-
- int st;
- bool is_zlib = true;
-
- if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) {
- is_zlib = false;
- }
-
- if (is_zlib) {
- st = uzlib_zlib_parse_header(decomp);
- if (st < 0) {
- goto error;
- }
- }
-
- while (1) {
- st = uzlib_uncompress_chksum(decomp);
- if (st < 0) {
- goto error;
- }
- if (st == TINF_DONE) {
- break;
- }
- size_t offset = decomp->dest - dest_buf;
- dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256);
- dest_buf_size += 256;
- decomp->dest = dest_buf + offset;
- decomp->dest_limit = decomp->dest + 256;
- }
-
- mp_uint_t final_sz = decomp->dest - dest_buf;
- DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", dest_buf_size, final_sz);
- dest_buf = (byte *)m_renew(byte, dest_buf, dest_buf_size, final_sz);
- mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf);
- m_del_obj(TINF_DATA, decomp);
- return res;
-
-error:
- mp_raise_type_arg(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress);
-
-#if !MICROPY_ENABLE_DYNRUNTIME
-STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) },
- { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) },
- { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table);
-
-const mp_obj_module_t mp_module_uzlib = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_uzlib_globals,
-};
-
-
-MP_REGISTER_MODULE(MP_QSTR_uzlib, mp_module_uzlib);
-#endif
-
-// Source files #include'd here to make sure they're compiled in
-// only if module is enabled by config setting.
-
-#include "lib/uzlib/tinflate.c"
-#include "lib/uzlib/tinfzlib.c"
-#include "lib/uzlib/tinfgzip.c"
-#include "lib/uzlib/adler32.c"
-#include "lib/uzlib/crc32.c"
-
-#endif // MICROPY_PY_UZLIB
diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c
index d86f35896234..64276b5a8f3b 100644
--- a/extmod/modwebrepl.c
+++ b/extmod/modwebrepl.c
@@ -34,7 +34,7 @@
#ifdef MICROPY_PY_WEBREPL_DELAY
#include "py/mphal.h"
#endif
-#include "extmod/moduwebsocket.h"
+#include "extmod/modwebsocket.h"
#if MICROPY_PY_WEBREPL
diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c
new file mode 100644
index 000000000000..d2cb72039621
--- /dev/null
+++ b/extmod/modwebsocket.c
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "extmod/modwebsocket.h"
+
+#if MICROPY_PY_WEBSOCKET
+
+enum { FRAME_HEADER, FRAME_OPT, PAYLOAD, CONTROL };
+
+enum { BLOCKING_WRITE = 0x80 };
+
+typedef struct _mp_obj_websocket_t {
+ mp_obj_base_t base;
+ mp_obj_t sock;
+ uint32_t msg_sz;
+ byte mask[4];
+ byte state;
+ byte to_recv;
+ byte mask_pos;
+ byte buf_pos;
+ byte buf[6];
+ byte opts;
+ // Copy of last data frame flags
+ byte ws_flags;
+ // Copy of current frame flags
+ byte last_flags;
+} mp_obj_websocket_t;
+
+STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode);
+
+STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 1, 2, false);
+ mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+ mp_obj_websocket_t *o = mp_obj_malloc(mp_obj_websocket_t, type);
+ o->sock = args[0];
+ o->state = FRAME_HEADER;
+ o->to_recv = 2;
+ o->mask_pos = 0;
+ o->buf_pos = 0;
+ o->opts = FRAME_TXT;
+ if (n_args > 1 && args[1] == mp_const_true) {
+ o->opts |= BLOCKING_WRITE;
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
+ const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
+ while (1) {
+ if (self->to_recv != 0) {
+ mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);
+ if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
+ return out_sz;
+ }
+ self->buf_pos += out_sz;
+ self->to_recv -= out_sz;
+ if (self->to_recv != 0) {
+ *errcode = MP_EAGAIN;
+ return MP_STREAM_ERROR;
+ }
+ }
+
+ switch (self->state) {
+ case FRAME_HEADER: {
+ // TODO: Split frame handling below is untested so far, so conservatively disable it
+ assert(self->buf[0] & 0x80);
+
+ // "Control frames MAY be injected in the middle of a fragmented message."
+ // So, they must be processed before data frames (and not alter
+ // self->ws_flags)
+ byte frame_type = self->buf[0];
+ self->last_flags = frame_type;
+ frame_type &= FRAME_OPCODE_MASK;
+
+ if ((self->buf[0] & FRAME_OPCODE_MASK) == FRAME_CONT) {
+ // Preserve previous frame type
+ self->ws_flags = (self->ws_flags & FRAME_OPCODE_MASK) | (self->buf[0] & ~FRAME_OPCODE_MASK);
+ } else {
+ self->ws_flags = self->buf[0];
+ }
+
+ // Reset mask in case someone will use "simplified" protocol
+ // without masks.
+ memset(self->mask, 0, sizeof(self->mask));
+
+ int to_recv = 0;
+ size_t sz = self->buf[1] & 0x7f;
+ if (sz == 126) {
+ // Msg size is next 2 bytes
+ to_recv += 2;
+ } else if (sz == 127) {
+ // Msg size is next 8 bytes
+ assert(0);
+ }
+ if (self->buf[1] & 0x80) {
+ // Next 4 bytes is mask
+ to_recv += 4;
+ }
+
+ self->buf_pos = 0;
+ self->to_recv = to_recv;
+ self->msg_sz = sz; // May be overridden by FRAME_OPT
+ if (to_recv != 0) {
+ self->state = FRAME_OPT;
+ } else {
+ if (frame_type >= FRAME_CLOSE) {
+ self->state = CONTROL;
+ } else {
+ self->state = PAYLOAD;
+ }
+ }
+ continue;
+ }
+
+ case FRAME_OPT: {
+ if ((self->buf_pos & 3) == 2) {
+ // First two bytes are message length
+ self->msg_sz = (self->buf[0] << 8) | self->buf[1];
+ }
+ if (self->buf_pos >= 4) {
+ // Last 4 bytes is mask
+ memcpy(self->mask, self->buf + self->buf_pos - 4, 4);
+ }
+ self->buf_pos = 0;
+ if ((self->last_flags & FRAME_OPCODE_MASK) >= FRAME_CLOSE) {
+ self->state = CONTROL;
+ } else {
+ self->state = PAYLOAD;
+ }
+ continue;
+ }
+
+ case PAYLOAD:
+ case CONTROL: {
+ mp_uint_t out_sz = 0;
+ if (self->msg_sz == 0) {
+ // In case message had zero payload
+ goto no_payload;
+ }
+
+ size_t sz = MIN(size, self->msg_sz);
+ out_sz = stream_p->read(self->sock, buf, sz, errcode);
+ if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
+ return out_sz;
+ }
+
+ sz = out_sz;
+ for (byte *p = buf; sz--; p++) {
+ *p ^= self->mask[self->mask_pos++ & 3];
+ }
+
+ self->msg_sz -= out_sz;
+ if (self->msg_sz == 0) {
+ byte last_state;
+ no_payload:
+ last_state = self->state;
+ self->state = FRAME_HEADER;
+ self->to_recv = 2;
+ self->mask_pos = 0;
+ self->buf_pos = 0;
+
+ // Handle control frame
+ if (last_state == CONTROL) {
+ byte frame_type = self->last_flags & FRAME_OPCODE_MASK;
+ if (frame_type == FRAME_CLOSE) {
+ static const char close_resp[2] = {0x88, 0};
+ int err;
+ websocket_write(self_in, close_resp, sizeof(close_resp), &err);
+ return 0;
+ }
+
+ // DEBUG_printf("Finished receiving ctrl message %x, ignoring\n", self->last_flags);
+ continue;
+ }
+ }
+
+ if (out_sz != 0) {
+ return out_sz;
+ }
+ // Empty (data) frame received is not EOF
+ continue;
+ }
+
+ }
+ }
+}
+
+STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
+ assert(size < 0x10000);
+ byte header[4] = {0x80 | (self->opts & FRAME_OPCODE_MASK)};
+ int hdr_sz;
+ if (size < 126) {
+ header[1] = size;
+ hdr_sz = 2;
+ } else {
+ header[1] = 126;
+ header[2] = size >> 8;
+ header[3] = size & 0xff;
+ hdr_sz = 4;
+ }
+
+ mp_obj_t dest[3];
+ if (self->opts & BLOCKING_WRITE) {
+ mp_load_method(self->sock, MP_QSTR_setblocking, dest);
+ dest[2] = mp_const_true;
+ mp_call_method_n_kw(1, 0, dest);
+ }
+
+ mp_uint_t out_sz = mp_stream_write_exactly(self->sock, header, hdr_sz, errcode);
+ if (*errcode == 0) {
+ out_sz = mp_stream_write_exactly(self->sock, buf, size, errcode);
+ }
+
+ if (self->opts & BLOCKING_WRITE) {
+ dest[2] = mp_const_false;
+ mp_call_method_n_kw(1, 0, dest);
+ }
+
+ if (*errcode != 0) {
+ return MP_STREAM_ERROR;
+ }
+ return out_sz;
+}
+
+STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ // TODO: Send close signaling to the other side, otherwise it's
+ // abrupt close (connection abort).
+ mp_stream_close(self->sock);
+ return 0;
+ case MP_STREAM_GET_DATA_OPTS:
+ return self->ws_flags & FRAME_OPCODE_MASK;
+ case MP_STREAM_SET_DATA_OPTS: {
+ int cur = self->opts & FRAME_OPCODE_MASK;
+ self->opts = (self->opts & ~FRAME_OPCODE_MASK) | (arg & FRAME_OPCODE_MASK);
+ return cur;
+ }
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+}
+
+STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);
+
+STATIC const mp_stream_p_t websocket_stream_p = {
+ .read = websocket_read,
+ .write = websocket_write,
+ .ioctl = websocket_ioctl,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ websocket_type,
+ MP_QSTR_websocket,
+ MP_TYPE_FLAG_NONE,
+ make_new, websocket_make_new,
+ protocol, &websocket_stream_p,
+ locals_dict, &websocket_locals_dict
+ );
+
+STATIC const mp_rom_map_elem_t websocket_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_websocket) },
+ { MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&websocket_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(websocket_module_globals, websocket_module_globals_table);
+
+const mp_obj_module_t mp_module_websocket = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&websocket_module_globals,
+};
+
+// This module should not be extensible (as it is not a CPython standard
+// library nor is it necessary to override from the filesystem), however it
+// has previously been known as `uwebsocket`, so by making it extensible the
+// `uwebsocket` alias will continue to work.
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_websocket, mp_module_websocket);
+
+#endif // MICROPY_PY_WEBSOCKET
diff --git a/extmod/modwebsocket.h b/extmod/modwebsocket.h
new file mode 100644
index 000000000000..2720147dfdb6
--- /dev/null
+++ b/extmod/modwebsocket.h
@@ -0,0 +1,10 @@
+#ifndef MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H
+#define MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H
+
+#define FRAME_OPCODE_MASK 0x0f
+enum {
+ FRAME_CONT, FRAME_TXT, FRAME_BIN,
+ FRAME_CLOSE = 0x8, FRAME_PING, FRAME_PONG
+};
+
+#endif // MICROPY_INCLUDED_EXTMOD_MODWEBSOCKET_H
diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c
index 87d9b9f61428..168bd3d52b52 100644
--- a/extmod/network_cyw43.c
+++ b/extmod/network_cyw43.c
@@ -36,11 +36,20 @@
#include "extmod/network_cyw43.h"
#include "modnetwork.h"
-#if MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
#include "lib/cyw43-driver/src/cyw43.h"
-#else
-#include "drivers/cyw43/cyw43.h"
-#endif
+#include "lib/cyw43-driver/src/cyw43_country.h"
+
+// This is the same as cyw43_pm_value but as a macro, to make it a true constant.
+#define CYW43_PM_VALUE(pm_mode, pm2_sleep_ret_ms, li_beacon_period, li_dtim_period, li_assoc) \
+ ((li_assoc) << 20 \
+ | (li_dtim_period) << 16 \
+ | (li_beacon_period) << 12 \
+ | ((pm2_sleep_ret_ms) / 10) << 4 \
+ | (pm_mode))
+
+#define PM_NONE (CYW43_PM_VALUE(CYW43_NO_POWERSAVE_MODE, 10, 0, 0, 0))
+#define PM_PERFORMANCE (CYW43_PM_VALUE(CYW43_PM2_POWERSAVE_MODE, 200, 1, 1, 10))
+#define PM_POWERSAVE (CYW43_PM_VALUE(CYW43_PM1_POWERSAVE_MODE, 10, 0, 0, 0))
typedef struct _network_cyw43_obj_t {
mp_obj_base_t base;
@@ -124,11 +133,8 @@ STATIC mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf));
} else {
- #if MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
- cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]), MICROPY_CYW43_COUNTRY);
- #else
- cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]));
- #endif
+ uint32_t country = CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0);
+ cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]), country);
return mp_const_none;
}
}
@@ -232,7 +238,7 @@ STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, m
{ MP_QSTR_auth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = CYW43_CHANNEL_NONE} },
};
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
@@ -244,13 +250,18 @@ STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, m
args[ARG_security] = args[ARG_auth];
}
+ // Extract the SSID.
mp_buffer_info_t ssid;
mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ);
+
+ // Extract the key, if given.
mp_buffer_info_t key;
key.buf = NULL;
if (args[ARG_key].u_obj != mp_const_none) {
mp_get_buffer_raise(args[ARG_key].u_obj, &key, MP_BUFFER_READ);
}
+
+ // Extract the BSSID, if given.
mp_buffer_info_t bssid;
bssid.buf = NULL;
if (args[ARG_bssid].u_obj != mp_const_none) {
@@ -259,8 +270,25 @@ STATIC mp_obj_t network_cyw43_connect(size_t n_args, const mp_obj_t *pos_args, m
mp_raise_ValueError(NULL);
}
}
+
+ // Extract the security type, if given.
+ uint32_t auth_type;
+ if (args[ARG_security].u_int == -1) {
+ if (key.buf == NULL || key.len == 0) {
+ // Default to open when no password set.
+ auth_type = CYW43_AUTH_OPEN;
+ } else {
+ // Default to WPA2 otherwise. All other modes require the security
+ // kwarg to be set explicitly.
+ auth_type = CYW43_AUTH_WPA2_MIXED_PSK;
+ }
+ } else {
+ auth_type = args[ARG_security].u_int;
+ }
+
+ // Start the WiFi join procedure. It will run in the background.
int ret = cyw43_wifi_join(self->cyw, ssid.len, ssid.buf, key.len, key.buf,
- args[ARG_security].u_int, bssid.buf, args[ARG_channel].u_int);
+ auth_type, bssid.buf, args[ARG_channel].u_int);
if (ret != 0) {
mp_raise_OSError(-ret);
}
@@ -298,6 +326,14 @@ STATIC mp_obj_t network_cyw43_status(size_t n_args, const mp_obj_t *args) {
// one argument: return status based on query parameter
switch (mp_obj_str_get_qstr(args[1])) {
+ case MP_QSTR_rssi: {
+ if (self->itf != CYW43_ITF_STA) {
+ mp_raise_ValueError(MP_ERROR_TEXT("STA required"));
+ }
+ int32_t rssi;
+ cyw43_wifi_get_rssi(self->cyw, &rssi);
+ return mp_obj_new_int(rssi);
+ }
case MP_QSTR_stations: {
// return list of connected stations
if (self->itf != CYW43_ITF_AP) {
@@ -365,27 +401,29 @@ STATIC mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
return mp_obj_new_str((const char *)buf, len);
}
}
- #if MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
case MP_QSTR_security: {
return MP_OBJ_NEW_SMALL_INT(cyw43_wifi_ap_get_auth(self->cyw));
}
- #endif
case MP_QSTR_mac: {
uint8_t buf[6];
cyw43_wifi_get_mac(self->cyw, self->itf, buf);
return mp_obj_new_bytes(buf, 6);
}
+ case MP_QSTR_pm: {
+ uint32_t pm;
+ cyw43_wifi_get_pm(self->cyw, &pm);
+ return MP_OBJ_NEW_SMALL_INT(pm);
+ }
case MP_QSTR_txpower: {
uint8_t buf[13];
memcpy(buf, "qtxpower\x00\x00\x00\x00\x00", 13);
cyw43_ioctl(self->cyw, CYW43_IOCTL_GET_VAR, 13, buf, self->itf);
return MP_OBJ_NEW_SMALL_INT(nw_get_le32(buf) / 4);
}
- #if !MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
case MP_QSTR_hostname: {
- return mp_obj_new_str(self->cyw->hostname, strlen(self->cyw->hostname));
+ // TODO: Deprecated. Use network.hostname() instead.
+ return mp_obj_new_str(mod_network_hostname, strlen(mod_network_hostname));
}
- #endif
default:
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
}
@@ -458,14 +496,16 @@ STATIC mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map
cyw43_ioctl(self->cyw, CYW43_IOCTL_SET_VAR, 9 + 4, buf, self->itf);
break;
}
- #if !MICROPY_PY_NETWORK_CYW43_USE_LIB_DRIVER
case MP_QSTR_hostname: {
- const char *hostname = mp_obj_str_get_str(e->value);
- strncpy(self->cyw->hostname, hostname, MICROPY_BOARD_HOSTNAME_LENGTH);
- self->cyw->hostname[MICROPY_BOARD_HOSTNAME_LENGTH - 1] = 0;
+ // TODO: Deprecated. Use network.hostname(name) instead.
+ size_t len;
+ const char *str = mp_obj_str_get_data(e->value, &len);
+ if (len >= MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN) {
+ mp_raise_ValueError(NULL);
+ }
+ strcpy(mod_network_hostname, str);
break;
}
- #endif
default:
mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
}
@@ -493,6 +533,11 @@ STATIC const mp_rom_map_elem_t network_cyw43_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_cyw43_ifconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_cyw43_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_cyw43_config_obj) },
+
+ // Class constants.
+ { MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(PM_NONE) },
+ { MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(PM_PERFORMANCE) },
+ { MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(PM_POWERSAVE) },
};
STATIC MP_DEFINE_CONST_DICT(network_cyw43_locals_dict, network_cyw43_locals_dict_table);
diff --git a/extmod/network_lwip.c b/extmod/network_lwip.c
new file mode 100644
index 000000000000..caa30f6fff4d
--- /dev/null
+++ b/extmod/network_lwip.c
@@ -0,0 +1,95 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
+
+#include "shared/netutils/netutils.h"
+#include "extmod/modnetwork.h"
+
+#include "lwip/init.h"
+
+#if LWIP_VERSION_MAJOR >= 2
+
+#include "lwip/netif.h"
+#include "lwip/timeouts.h"
+#include "lwip/dns.h"
+#include "lwip/dhcp.h"
+
+// Implementations of network methods that can be used by any interface.
+
+mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ // Get IP addresses
+ const ip_addr_t *dns = dns_getserver(0);
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr((uint8_t *)&netif->ip_addr, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&netif->netmask, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&netif->gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)dns, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else if (args[0] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) {
+ // Start the DHCP client
+ if (dhcp_supplied_address(netif)) {
+ dhcp_renew(netif);
+ } else {
+ dhcp_stop(netif);
+ dhcp_start(netif);
+ }
+
+ // Wait for DHCP to get IP address
+ uint32_t start = mp_hal_ticks_ms();
+ while (!dhcp_supplied_address(netif)) {
+ if (mp_hal_ticks_ms() - start > 10000) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("timeout waiting for DHCP to get IP address"));
+ }
+ mp_hal_delay_ms(100);
+ }
+
+ return mp_const_none;
+ } else {
+ // Release and stop any existing DHCP
+ dhcp_release(netif);
+ dhcp_stop(netif);
+ // Set static IP addresses
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[0], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (uint8_t *)&netif->ip_addr, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[1], (uint8_t *)&netif->netmask, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[2], (uint8_t *)&netif->gw, NETUTILS_BIG);
+ ip_addr_t dns;
+ netutils_parse_ipv4_addr(items[3], (uint8_t *)&dns, NETUTILS_BIG);
+ dns_setserver(0, &dns);
+ return mp_const_none;
+ }
+}
+
+#endif // LWIP_VERSION_MAJOR >= 2
+
+#endif // MICROPY_PY_NETWORK && MICROPY_PY_LWIP
diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c
index f4cc0b22244d..00f53eff137a 100644
--- a/extmod/network_ninaw10.c
+++ b/extmod/network_ninaw10.c
@@ -51,6 +51,9 @@ typedef struct _nina_obj_t {
mp_obj_base_t base;
bool active;
uint32_t itf;
+ mp_uint_t security;
+ char ssid[NINA_MAX_SSID_LEN + 1];
+ char key[NINA_MAX_WPA_LEN + 1];
} nina_obj_t;
// For auto-binding UDP sockets
@@ -74,10 +77,11 @@ typedef struct _nina_obj_t {
#define debug_printf(...) // mp_printf(&mp_plat_print, __VA_ARGS__)
static uint16_t bind_port = BIND_PORT_RANGE_MIN;
-const mod_network_nic_type_t mod_network_nic_type_nina;
+const mp_obj_type_t mod_network_nic_type_nina;
static nina_obj_t network_nina_wl_sta = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF};
static nina_obj_t network_nina_wl_ap = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_AP_IF};
static mp_sched_node_t mp_wifi_sockpoll_node;
+static mp_sched_node_t mp_wifi_connpoll_node;
STATIC void network_ninaw10_poll_sockets(mp_sched_node_t *node) {
(void)node;
@@ -99,6 +103,40 @@ STATIC void network_ninaw10_poll_sockets(mp_sched_node_t *node) {
}
}
+STATIC void network_ninaw10_poll_connect(mp_sched_node_t *node) {
+ nina_obj_t *self = &network_nina_wl_sta;
+
+ int status = nina_connection_status();
+ if (status == NINA_STATUS_CONNECTED) {
+ // Connected to AP, nothing else to do.
+ return;
+ }
+
+ if (status != NINA_STATUS_NO_SSID_AVAIL) {
+ // If not connected, and no connection in progress, the connection attempt has failed.
+ // Read the ESP failure reason, reconnect and reschedule the connection polling code.
+ int reason = nina_connection_reason();
+ if (reason == NINA_ESP_REASON_AUTH_EXPIRE ||
+ reason == NINA_ESP_REASON_ASSOC_EXPIRE ||
+ reason == NINA_ESP_REASON_NOT_AUTHED ||
+ reason == NINA_ESP_REASON_4WAY_HANDSHAKE_TIMEOUT ||
+ reason >= NINA_ESP_REASON_BEACON_TIMEOUT) {
+ debug_printf(&mp_plat_print, "poll_connect() status: %d reason %d\n", status, reason);
+ if (nina_connect(self->ssid, self->security, self->key, 0) != 0) {
+ mp_raise_msg_varg(&mp_type_OSError,
+ MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"),
+ self->ssid, self->security, self->key);
+ }
+ } else {
+ // Will not attempt to reconnect if there's another error code set.
+ return;
+ }
+ }
+
+ // Reschedule the connection polling code.
+ mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
+}
+
STATIC mp_obj_t network_ninaw10_timer_callback(mp_obj_t none_in) {
if (MP_STATE_PORT(mp_wifi_sockpoll_list) != MP_OBJ_NULL && MP_STATE_PORT(mp_wifi_sockpoll_list)->len) {
mp_sched_schedule_node(&mp_wifi_sockpoll_node, network_ninaw10_poll_sockets);
@@ -240,6 +278,12 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
mp_raise_msg_varg(&mp_type_OSError,
MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key);
}
+
+ // Save connection info to re-connect if needed.
+ self->security = security;
+ strncpy(self->key, key, NINA_MAX_WPA_LEN);
+ strncpy(self->ssid, ssid, NINA_MAX_SSID_LEN);
+ mp_sched_schedule_node(&mp_wifi_connpoll_node, network_ninaw10_poll_connect);
} else {
mp_uint_t channel = args[ARG_channel].u_int;
@@ -252,6 +296,7 @@ STATIC mp_obj_t network_ninaw10_connect(mp_uint_t n_args, const mp_obj_t *pos_ar
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode"));
}
}
+
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect);
@@ -441,13 +486,33 @@ STATIC int network_ninaw10_socket_listening(mod_network_socket_obj_t *socket, in
STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
debug_printf("socket_socket(%d %d %d)\n", socket->domain, socket->type, socket->proto);
+ uint8_t socket_type;
+
+ switch (socket->type) {
+ case MOD_NETWORK_SOCK_STREAM:
+ socket_type = NINA_SOCKET_TYPE_TCP;
+ break;
+
+ case MOD_NETWORK_SOCK_DGRAM:
+ socket_type = NINA_SOCKET_TYPE_UDP;
+ break;
+
+ case MOD_NETWORK_SOCK_RAW:
+ socket_type = NINA_SOCKET_TYPE_RAW;
+ break;
+
+ default:
+ *_errno = MP_EINVAL;
+ return -1;
+ }
+
if (socket->domain != MOD_NETWORK_AF_INET) {
*_errno = MP_EAFNOSUPPORT;
return -1;
}
// open socket
- int fd = nina_socket_socket(socket->type, socket->proto);
+ int fd = nina_socket_socket(socket_type, socket->proto);
if (fd < 0) {
nina_socket_errno(_errno);
debug_printf("socket_socket() -> errno %d\n", *_errno);
@@ -477,20 +542,6 @@ STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) {
STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
debug_printf("socket_bind(%d, %d)\n", socket->fileno, port);
- uint8_t type;
- switch (socket->type) {
- case MOD_NETWORK_SOCK_STREAM:
- type = NINA_SOCKET_TYPE_TCP;
- break;
-
- case MOD_NETWORK_SOCK_DGRAM:
- type = NINA_SOCKET_TYPE_UDP;
- break;
-
- default:
- *_errno = MP_EINVAL;
- return -1;
- }
int ret = nina_socket_bind(socket->fileno, ip, port);
if (ret < 0) {
@@ -753,7 +804,7 @@ STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uin
return ret;
}
-static const mp_rom_map_elem_t nina_locals_dict_table[] = {
+STATIC const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) },
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) },
{ MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) },
@@ -772,18 +823,9 @@ static const mp_rom_map_elem_t nina_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) },
};
-static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
-
-STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE(
- mod_network_nic_type_nina_base,
- MP_QSTR_nina,
- MP_TYPE_FLAG_NONE,
- make_new, network_ninaw10_make_new,
- locals_dict, &nina_locals_dict
- );
+STATIC MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table);
-const mod_network_nic_type_t mod_network_nic_type_nina = {
- .base = mod_network_nic_type_nina_base,
+STATIC const mod_network_nic_protocol_t mod_network_nic_protocol_nina = {
.gethostbyname = network_ninaw10_gethostbyname,
.socket = network_ninaw10_socket_socket,
.close = network_ninaw10_socket_close,
@@ -800,6 +842,15 @@ const mod_network_nic_type_t mod_network_nic_type_nina = {
.ioctl = network_ninaw10_socket_ioctl,
};
+MP_DEFINE_CONST_OBJ_TYPE(
+ mod_network_nic_type_nina,
+ MP_QSTR_nina,
+ MP_TYPE_FLAG_NONE,
+ make_new, network_ninaw10_make_new,
+ locals_dict, &nina_locals_dict,
+ protocol, &mod_network_nic_protocol_nina
+ );
+
MP_REGISTER_ROOT_POINTER(struct _machine_spi_obj_t *mp_wifi_spi);
MP_REGISTER_ROOT_POINTER(struct _machine_timer_obj_t *mp_wifi_timer);
MP_REGISTER_ROOT_POINTER(struct _mp_obj_list_t *mp_wifi_sockpoll_list);
diff --git a/extmod/network_wiznet5k.c b/extmod/network_wiznet5k.c
index 78cbff4ce2df..eed656ee2419 100644
--- a/extmod/network_wiznet5k.c
+++ b/extmod/network_wiznet5k.c
@@ -1017,24 +1017,9 @@ STATIC const mp_rom_map_elem_t wiznet5k_locals_dict_table[] = {
STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
#if WIZNET5K_WITH_LWIP_STACK
-MP_DEFINE_CONST_OBJ_TYPE(
- mod_network_nic_type_wiznet5k,
- MP_QSTR_WIZNET5K,
- MP_TYPE_FLAG_NONE,
- make_new, wiznet5k_make_new,
- locals_dict, &wiznet5k_locals_dict
- );
+#define NIC_TYPE_WIZNET_PROTOCOL
#else // WIZNET5K_PROVIDED_STACK
-STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE(
- mod_network_nic_type_wiznet5k_base,
- MP_QSTR_WIZNET5K,
- MP_TYPE_FLAG_NONE,
- make_new, wiznet5k_make_new,
- locals_dict, &wiznet5k_locals_dict
- );
-
-const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
- .base = mod_network_nic_type_wiznet5k_base,
+const mod_network_nic_protocol_t mod_network_nic_protocol_wiznet = {
.gethostbyname = wiznet5k_gethostbyname,
.socket = wiznet5k_socket_socket,
.close = wiznet5k_socket_close,
@@ -1050,6 +1035,16 @@ const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
.settimeout = wiznet5k_socket_settimeout,
.ioctl = wiznet5k_socket_ioctl,
};
+#define NIC_TYPE_WIZNET_PROTOCOL protocol, &mod_network_nic_protocol_wiznet,
#endif
+MP_DEFINE_CONST_OBJ_TYPE(
+ mod_network_nic_type_wiznet5k,
+ MP_QSTR_WIZNET5K,
+ MP_TYPE_FLAG_NONE,
+ make_new, wiznet5k_make_new,
+ NIC_TYPE_WIZNET_PROTOCOL
+ locals_dict, &wiznet5k_locals_dict
+ );
+
#endif // MICROPY_PY_NETWORK_WIZNET5K
diff --git a/extmod/nimble/hal/hal_uart.c b/extmod/nimble/hal/hal_uart.c
index 6c17da086071..f4a9319c8b5f 100644
--- a/extmod/nimble/hal/hal_uart.c
+++ b/extmod/nimble/hal/hal_uart.c
@@ -39,6 +39,9 @@
#endif
#define HCI_TRACE (0)
+#define COL_OFF "\033[0m"
+#define COL_GREEN "\033[0;32m"
+#define COL_BLUE "\033[0;34m"
static hal_uart_tx_cb_t hal_uart_tx_cb;
static void *hal_uart_tx_arg;
@@ -71,17 +74,17 @@ void hal_uart_start_tx(uint32_t port) {
}
#if HCI_TRACE
- printf("< [% 8d] %02x", (int)mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]);
+ printf(COL_GREEN "< [% 8d] %02x", (int)mp_hal_ticks_ms(), mp_bluetooth_hci_cmd_buf[0]);
for (size_t i = 1; i < len; ++i) {
printf(":%02x", mp_bluetooth_hci_cmd_buf[i]);
}
- printf("\n");
+ printf(COL_OFF "\n");
#endif
mp_bluetooth_hci_uart_write(mp_bluetooth_hci_cmd_buf, len);
if (len > 0) {
- // Allow modbluetooth bindings to hook "sent packet" (e.g. to unstall l2cap channels).
+ // Allow modbluetooth bindings to hook "sent packet" (e.g. to un-stall l2cap channels).
mp_bluetooth_nimble_sent_hci_packet();
}
}
@@ -92,7 +95,7 @@ int hal_uart_close(uint32_t port) {
STATIC void mp_bluetooth_hci_uart_char_cb(uint8_t chr) {
#if HCI_TRACE
- printf("> %02x\n", chr);
+ printf(COL_BLUE "> [% 8d] %02x" COL_OFF "\n", (int)mp_hal_ticks_ms(), chr);
#endif
hal_uart_rx_cb(hal_uart_rx_arg, chr);
}
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index b0194446bd4b..e23ffbf0f981 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -652,7 +652,7 @@ int mp_bluetooth_init(void) {
// By default, just register the default gap/gatt service.
ble_svc_gap_init();
ble_svc_gatt_init();
- // The preceeding two calls allocate service definitions on the heap,
+ // The preceding two calls allocate service definitions on the heap,
// then we must now call gatts_start to register those services
// and free the heap memory.
// Otherwise it will be realloc'ed on the next stack startup.
@@ -851,6 +851,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle,
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
case BLE_GATT_ACCESS_OP_READ_DSC: {
+ DEBUG_printf("write for %d %d (op=%d)\n", conn_handle, value_handle, ctxt->op);
// Allow Python code to override (by using gatts_write), or deny (by returning false) the read.
// Note this will be a no-op if the ringbuffer implementation is being used (i.e. the stack isn't
// run in the scheduler). The ringbuffer is not used on STM32 and Unix-H4 only.
@@ -872,6 +873,7 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle,
}
case BLE_GATT_ACCESS_OP_WRITE_CHR:
case BLE_GATT_ACCESS_OP_WRITE_DSC:
+ DEBUG_printf("write for %d %d (op=%d)\n", conn_handle, value_handle, ctxt->op);
entry = mp_bluetooth_gatts_db_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle);
if (!entry) {
return BLE_ATT_ERR_ATTR_NOT_FOUND;
@@ -963,7 +965,14 @@ int mp_bluetooth_gatts_register_service(mp_obj_bluetooth_uuid_t *service_uuid, m
descriptors[j].uuid = create_nimble_uuid(descriptor_uuids[descriptor_index], NULL);
descriptors[j].access_cb = characteristic_access_cb;
// NimBLE doesn't support security/privacy options on descriptors.
- descriptors[j].att_flags = (uint8_t)descriptor_flags[descriptor_index];
+ uint8_t desc_att_flags = 0;
+ if (descriptor_flags[descriptor_index] & MP_BLUETOOTH_CHARACTERISTIC_FLAG_READ) {
+ desc_att_flags |= BLE_ATT_F_READ;
+ }
+ if (descriptor_flags[descriptor_index] & (MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE | MP_BLUETOOTH_CHARACTERISTIC_FLAG_WRITE_NO_RESPONSE)) {
+ desc_att_flags |= BLE_ATT_F_WRITE;
+ }
+ descriptors[j].att_flags = desc_att_flags;
descriptors[j].min_key_size = 0;
// Unlike characteristic, Nimble doesn't provide an automatic way to remember the handle, so use the arg.
descriptors[j].arg = &handles[handle_index];
@@ -1008,7 +1017,7 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle) {
return ble_hs_err_to_errno(ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM));
}
-int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) {
+int mp_bluetooth_gatts_read(uint16_t value_handle, const uint8_t **value, size_t *value_len) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
@@ -1026,35 +1035,40 @@ int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t
return err;
}
-// TODO: Could use ble_gatts_chr_updated to send to all subscribed centrals.
-
-int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) {
+int mp_bluetooth_gatts_notify_indicate(uint16_t conn_handle, uint16_t value_handle, int gatts_op, const uint8_t *value, size_t value_len) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- // Confusingly, notify/notify_custom/indicate are "gattc" function (even though they're used by peripherals (i.e. gatt servers)).
- // See https://www.mail-archive.com/dev@mynewt.apache.org/msg01293.html
- return ble_hs_err_to_errno(ble_gattc_notify(conn_handle, value_handle));
-}
-int mp_bluetooth_gatts_notify_send(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len) {
- if (!mp_bluetooth_is_active()) {
- return ERRNO_BLUETOOTH_NOT_ACTIVE;
- }
- struct os_mbuf *om = ble_hs_mbuf_from_flat(value, value_len);
- if (om == NULL) {
- return MP_ENOMEM;
+ int err = BLE_HS_EINVAL;
+
+ // NULL om in the _custom methods means "use DB value" (NimBLE will call
+ // back into mp_bluetooth_gatts_read for us).
+ struct os_mbuf *om = NULL;
+
+ if (value) {
+ om = ble_hs_mbuf_from_flat(value, value_len);
+ if (om == NULL) {
+ return MP_ENOMEM;
+ }
}
- return ble_hs_err_to_errno(ble_gattc_notify_custom(conn_handle, value_handle, om));
-}
-int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) {
- if (!mp_bluetooth_is_active()) {
- return ERRNO_BLUETOOTH_NOT_ACTIVE;
+ // Note: Confusingly, Nimble's notify/notify_custom and indicate/indicate_custom
+ // are "gattc" functions (even though they're used by peripherals, i.e. gatt servers).
+ // See https://www.mail-archive.com/dev@mynewt.apache.org/msg01293.html
+
+ switch (gatts_op) {
+ case MP_BLUETOOTH_GATTS_OP_NOTIFY:
+ err = ble_gattc_notify_custom(conn_handle, value_handle, om);
+ break;
+ case MP_BLUETOOTH_GATTS_OP_INDICATE:
+ // This will raise BLE_GAP_EVENT_NOTIFY_TX with a status when it is
+ // acknowledged (or timeout/error).
+ err = ble_gattc_indicate_custom(conn_handle, value_handle, om);
+ break;
}
- // This will raise BLE_GAP_EVENT_NOTIFY_TX with a status when it is
- // acknowledged (or timeout/error).
- return ble_hs_err_to_errno(ble_gattc_indicate(conn_handle, value_handle));
+
+ return ble_hs_err_to_errno(err);
}
int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) {
@@ -1446,15 +1460,15 @@ STATIC int ble_gattc_attr_write_cb(uint16_t conn_handle, const struct ble_gatt_e
}
// Write the value to the remote peripheral.
-int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t *value_len, unsigned int mode) {
+int mp_bluetooth_gattc_write(uint16_t conn_handle, uint16_t value_handle, const uint8_t *value, size_t value_len, unsigned int mode) {
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
int err;
if (mode == MP_BLUETOOTH_WRITE_MODE_NO_RESPONSE) {
- err = ble_gattc_write_no_rsp_flat(conn_handle, value_handle, value, *value_len);
+ err = ble_gattc_write_no_rsp_flat(conn_handle, value_handle, value, value_len);
} else if (mode == MP_BLUETOOTH_WRITE_MODE_WITH_RESPONSE) {
- err = ble_gattc_write_flat(conn_handle, value_handle, value, *value_len, &ble_gattc_attr_write_cb, NULL);
+ err = ble_gattc_write_flat(conn_handle, value_handle, value, value_len, &ble_gattc_attr_write_cb, NULL);
} else {
err = BLE_HS_EINVAL;
}
@@ -1523,7 +1537,7 @@ STATIC void destroy_l2cap_channel() {
STATIC void unstall_l2cap_channel(void) {
// Whenever we send an HCI packet and the sys mempool is now less than 1/4 full,
- // we can unstall the L2CAP channel if it was marked as "mem_stalled" by
+ // we can un-stall the L2CAP channel if it was marked as "mem_stalled" by
// mp_bluetooth_l2cap_send. (This happens if the pool is half-empty).
mp_bluetooth_nimble_l2cap_channel_t *chan = MP_STATE_PORT(bluetooth_nimble_root_pointers)->l2cap_chan;
if (!chan || !chan->mem_stalled) {
@@ -1630,7 +1644,7 @@ STATIC int l2cap_channel_event(struct ble_l2cap_event *event, void *arg) {
case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: {
DEBUG_printf("l2cap_channel_event: tx_unstalled: conn_handle=%d status=%d\n", event->tx_unstalled.conn_handle, event->tx_unstalled.status);
assert(event->tx_unstalled.conn_handle == chan->chan->conn_handle);
- // Don't unstall if we're still waiting for room in the sys pool.
+ // Don't un-stall if we're still waiting for room in the sys pool.
if (!chan->mem_stalled) {
ble_l2cap_get_chan_info(event->receive.chan, &info);
// Map status to {0,1} (i.e. "sent everything", or "partial send").
@@ -1788,7 +1802,7 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b
err = ble_l2cap_send(chan->chan, sdu_tx);
if (err == BLE_HS_ESTALLED) {
// Stalled means that this one will still send but any future ones
- // will fail until we receive an unstalled event.
+ // will fail until we receive an un-stalled event.
DEBUG_printf("mp_bluetooth_l2cap_send: credit stall\n");
*stalled = true;
err = 0;
diff --git a/extmod/os_dupterm.c b/extmod/os_dupterm.c
new file mode 100644
index 000000000000..cfd1c6261649
--- /dev/null
+++ b/extmod/os_dupterm.c
@@ -0,0 +1,207 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Paul Sokolovsky
+ * Copyright (c) 2017-2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/mpconfig.h"
+
+#include "py/runtime.h"
+#include "py/objtuple.h"
+#include "py/objarray.h"
+#include "py/stream.h"
+#include "extmod/misc.h"
+
+#if MICROPY_PY_OS_DUPTERM
+
+#include "shared/runtime/interrupt_char.h"
+
+void mp_os_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
+ mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
+ MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL;
+ mp_printf(&mp_plat_print, msg);
+ if (exc != MP_OBJ_NULL) {
+ mp_obj_print_exception(&mp_plat_print, exc);
+ }
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_stream_close(term);
+ nlr_pop();
+ } else {
+ // Ignore any errors during stream closing
+ }
+}
+
+uintptr_t mp_os_dupterm_poll(uintptr_t poll_flags) {
+ uintptr_t poll_flags_out = 0;
+
+ for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]);
+ if (s == MP_OBJ_NULL) {
+ continue;
+ }
+
+ int errcode = 0;
+ mp_uint_t ret = 0;
+ const mp_stream_p_t *stream_p = mp_get_stream(s);
+ #if MICROPY_PY_OS_DUPTERM_BUILTIN_STREAM
+ if (mp_os_dupterm_is_builtin_stream(s)) {
+ ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+ } else
+ #endif
+ {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
+ nlr_pop();
+ } else {
+ // Ignore error with ioctl
+ }
+ }
+
+ if (ret != MP_STREAM_ERROR) {
+ poll_flags_out |= ret;
+ if (poll_flags_out == poll_flags) {
+ // Finish early if all requested flags are set
+ break;
+ }
+ }
+ }
+
+ return poll_flags_out;
+}
+
+int mp_os_dupterm_rx_chr(void) {
+ for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
+ continue;
+ }
+
+ #if MICROPY_PY_OS_DUPTERM_BUILTIN_STREAM
+ if (mp_os_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
+ byte buf[1];
+ int errcode = 0;
+ const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+ mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
+ if (errcode == 0 && out_sz != 0) {
+ return buf[0];
+ } else {
+ continue;
+ }
+ }
+ #endif
+
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ byte buf[1];
+ int errcode;
+ const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+ mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
+ if (out_sz == 0) {
+ nlr_pop();
+ mp_os_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
+ } else if (out_sz == MP_STREAM_ERROR) {
+ // errcode is valid
+ if (mp_is_nonblocking_error(errcode)) {
+ nlr_pop();
+ } else {
+ mp_raise_OSError(errcode);
+ }
+ } else {
+ // read 1 byte
+ nlr_pop();
+ if (buf[0] == mp_interrupt_char) {
+ // Signal keyboard interrupt to be raised as soon as the VM resumes
+ mp_sched_keyboard_interrupt();
+ return -2;
+ }
+ return buf[0];
+ }
+ } else {
+ mp_os_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+ }
+
+ // No chars available
+ return -1;
+}
+
+void mp_os_dupterm_tx_strn(const char *str, size_t len) {
+ for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
+ if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
+ continue;
+ }
+
+ #if MICROPY_PY_OS_DUPTERM_BUILTIN_STREAM
+ if (mp_os_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
+ int errcode = 0;
+ const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+ stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode);
+ continue;
+ }
+ #endif
+
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);
+ nlr_pop();
+ } else {
+ mp_os_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val));
+ }
+ }
+}
+
+STATIC mp_obj_t mp_os_dupterm(size_t n_args, const mp_obj_t *args) {
+ mp_int_t idx = 0;
+ if (n_args == 2) {
+ idx = mp_obj_get_int(args[1]);
+ }
+
+ if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid dupterm index"));
+ }
+
+ mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]);
+ if (previous_obj == MP_OBJ_NULL) {
+ previous_obj = mp_const_none;
+ }
+ if (args[0] == mp_const_none) {
+ MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
+ } else {
+ mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+ MP_STATE_VM(dupterm_objs[idx]) = args[0];
+ }
+
+ #if MICROPY_PY_OS_DUPTERM_STREAM_DETACHED_ATTACHED
+ mp_os_dupterm_stream_detached_attached(previous_obj, args[0]);
+ #endif
+
+ return previous_obj;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_dupterm_obj, 1, 2, mp_os_dupterm);
+
+MP_REGISTER_ROOT_POINTER(mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]);
+
+#endif // MICROPY_PY_OS_DUPTERM
diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py
deleted file mode 100644
index fa64438f6b2a..000000000000
--- a/extmod/uasyncio/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# MicroPython uasyncio module
-# MIT license; Copyright (c) 2019 Damien P. George
-
-from .core import *
-
-__version__ = (3, 0, 0)
-
-_attrs = {
- "wait_for": "funcs",
- "wait_for_ms": "funcs",
- "gather": "funcs",
- "Event": "event",
- "ThreadSafeFlag": "event",
- "Lock": "lock",
- "open_connection": "stream",
- "start_server": "stream",
- "StreamReader": "stream",
- "StreamWriter": "stream",
-}
-
-# Lazy loader, effectively does:
-# global attr
-# from .mod import attr
-def __getattr__(attr):
- mod = _attrs.get(attr, None)
- if mod is None:
- raise AttributeError(attr)
- value = getattr(__import__(mod, None, None, True, 1), attr)
- globals()[attr] = value
- return value
diff --git a/extmod/uasyncio/manifest.py b/extmod/uasyncio/manifest.py
deleted file mode 100644
index d425a467b3af..000000000000
--- a/extmod/uasyncio/manifest.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This list of package files doesn't include task.py because that's provided
-# by the C module.
-package(
- "uasyncio",
- (
- "__init__.py",
- "core.py",
- "event.py",
- "funcs.py",
- "lock.py",
- "stream.py",
- ),
- base_path="..",
- opt=3,
-)
diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c
deleted file mode 100644
index 826bf1715df3..000000000000
--- a/extmod/uos_dupterm.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Paul Sokolovsky
- * Copyright (c) 2017-2019 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include "py/mpconfig.h"
-
-#include "py/runtime.h"
-#include "py/objtuple.h"
-#include "py/objarray.h"
-#include "py/stream.h"
-#include "extmod/misc.h"
-#include "shared/runtime/interrupt_char.h"
-
-#if MICROPY_PY_OS_DUPTERM
-
-void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) {
- mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
- MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL;
- mp_printf(&mp_plat_print, msg);
- if (exc != MP_OBJ_NULL) {
- mp_obj_print_exception(&mp_plat_print, exc);
- }
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_stream_close(term);
- nlr_pop();
- } else {
- // Ignore any errors during stream closing
- }
-}
-
-uintptr_t mp_uos_dupterm_poll(uintptr_t poll_flags) {
- uintptr_t poll_flags_out = 0;
-
- for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
- mp_obj_t s = MP_STATE_VM(dupterm_objs[idx]);
- if (s == MP_OBJ_NULL) {
- continue;
- }
-
- int errcode = 0;
- mp_uint_t ret = 0;
- const mp_stream_p_t *stream_p = mp_get_stream(s);
- #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
- if (mp_uos_dupterm_is_builtin_stream(s)) {
- ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
- } else
- #endif
- {
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- ret = stream_p->ioctl(s, MP_STREAM_POLL, poll_flags, &errcode);
- nlr_pop();
- } else {
- // Ignore error with ioctl
- }
- }
-
- if (ret != MP_STREAM_ERROR) {
- poll_flags_out |= ret;
- if (poll_flags_out == poll_flags) {
- // Finish early if all requested flags are set
- break;
- }
- }
- }
-
- return poll_flags_out;
-}
-
-int mp_uos_dupterm_rx_chr(void) {
- for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
- if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
- continue;
- }
-
- #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
- if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
- byte buf[1];
- int errcode = 0;
- const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
- mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
- if (errcode == 0 && out_sz != 0) {
- return buf[0];
- } else {
- continue;
- }
- }
- #endif
-
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- byte buf[1];
- int errcode;
- const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
- mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
- if (out_sz == 0) {
- nlr_pop();
- mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
- } else if (out_sz == MP_STREAM_ERROR) {
- // errcode is valid
- if (mp_is_nonblocking_error(errcode)) {
- nlr_pop();
- } else {
- mp_raise_OSError(errcode);
- }
- } else {
- // read 1 byte
- nlr_pop();
- if (buf[0] == mp_interrupt_char) {
- // Signal keyboard interrupt to be raised as soon as the VM resumes
- mp_sched_keyboard_interrupt();
- return -2;
- }
- return buf[0];
- }
- } else {
- mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val));
- }
- }
-
- // No chars available
- return -1;
-}
-
-void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
- for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) {
- if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) {
- continue;
- }
-
- #if MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM
- if (mp_uos_dupterm_is_builtin_stream(MP_STATE_VM(dupterm_objs[idx]))) {
- int errcode = 0;
- const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
- stream_p->write(MP_STATE_VM(dupterm_objs[idx]), str, len, &errcode);
- continue;
- }
- #endif
-
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);
- nlr_pop();
- } else {
- mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", MP_OBJ_FROM_PTR(nlr.ret_val));
- }
- }
-}
-
-STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
- mp_int_t idx = 0;
- if (n_args == 2) {
- idx = mp_obj_get_int(args[1]);
- }
-
- if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid dupterm index"));
- }
-
- mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]);
- if (previous_obj == MP_OBJ_NULL) {
- previous_obj = mp_const_none;
- }
- if (args[0] == mp_const_none) {
- MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
- } else {
- mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
- MP_STATE_VM(dupterm_objs[idx]) = args[0];
- }
-
- #if MICROPY_PY_UOS_DUPTERM_STREAM_DETACHED_ATTACHED
- mp_uos_dupterm_stream_detached_attached(previous_obj, args[0]);
- #endif
-
- return previous_obj;
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm);
-
-MP_REGISTER_ROOT_POINTER(mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]);
-
-#endif // MICROPY_PY_OS_DUPTERM
diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c
deleted file mode 100644
index 3d1cdfd82062..000000000000
--- a/extmod/utime_mphal.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013-2016 Damien P. George
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-#if MICROPY_PY_UTIME_MP_HAL
-
-#include
-
-#include "py/obj.h"
-#include "py/mphal.h"
-#include "py/smallint.h"
-#include "py/runtime.h"
-#include "extmod/utime_mphal.h"
-
-STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
- #if MICROPY_PY_BUILTINS_FLOAT
- mp_hal_delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o)));
- #else
- mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o));
- #endif
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep);
-
-STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) {
- mp_int_t ms = mp_obj_get_int(arg);
- if (ms >= 0) {
- mp_hal_delay_ms(ms);
- }
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms);
-
-STATIC mp_obj_t time_sleep_us(mp_obj_t arg) {
- mp_int_t us = mp_obj_get_int(arg);
- if (us > 0) {
- mp_hal_delay_us(us);
- }
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us);
-
-STATIC mp_obj_t time_ticks_ms(void) {
- return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
-MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms);
-
-STATIC mp_obj_t time_ticks_us(void) {
- return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
-MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us);
-
-STATIC mp_obj_t time_ticks_cpu(void) {
- return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
-MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu);
-
-STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) {
- // we assume that the arguments come from ticks_xx so are small ints
- mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in);
- mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in);
- // Optimized formula avoiding if conditions. We adjust difference "forward",
- // wrap it around and adjust back.
- mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1))
- - MICROPY_PY_UTIME_TICKS_PERIOD / 2;
- return MP_OBJ_NEW_SMALL_INT(diff);
-}
-MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff);
-
-STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {
- // we assume that first argument come from ticks_xx so is small int
- mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in);
- mp_uint_t delta = mp_obj_get_int(delta_in);
- return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
-}
-MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add);
-
-// Returns the number of nanoseconds since the Epoch, as an integer.
-STATIC mp_obj_t time_time_ns(void) {
- return mp_obj_new_int_from_ull(mp_hal_time_ns());
-}
-MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_time_ns_obj, time_time_ns);
-
-#endif // MICROPY_PY_UTIME_MP_HAL
diff --git a/extmod/utime_mphal.h b/extmod/utime_mphal.h
index 57fc34883281..8b137891791f 100644
--- a/extmod/utime_mphal.h
+++ b/extmod/utime_mphal.h
@@ -1,42 +1 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013-2016 Damien P. George
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H
-#define MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H
-#include "py/obj.h"
-
-MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_obj);
-MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj);
-MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj);
-MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj);
-MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj);
-MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj);
-MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj);
-MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj);
-MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_time_ns_obj);
-
-#endif // MICROPY_INCLUDED_EXTMOD_UTIME_MPHAL_H
diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c
index 07e6df9bf959..f82fe4aaae7e 100644
--- a/extmod/vfs_fat_file.c
+++ b/extmod/vfs_fat_file.c
@@ -96,13 +96,6 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz
return sz_out;
}
-
-STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- return mp_stream_close(args[0]);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__);
-
STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
pyb_file_obj_t *self = MP_OBJ_TO_PTR(o_in);
@@ -165,7 +158,7 @@ STATIC const mp_rom_map_elem_t vfs_fat_rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
- { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
};
STATIC MP_DEFINE_CONST_DICT(vfs_fat_rawfile_locals_dict, vfs_fat_rawfile_locals_dict_table);
diff --git a/extmod/vfs_lfs.c b/extmod/vfs_lfs.c
index f6a9a24623a9..4fb86b89b76c 100644
--- a/extmod/vfs_lfs.c
+++ b/extmod/vfs_lfs.c
@@ -26,12 +26,13 @@
#include "py/runtime.h"
#include "py/mphal.h"
+
+#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
+
#include "shared/timeutils/timeutils.h"
#include "extmod/vfs.h"
#include "extmod/vfs_lfs.h"
-#if MICROPY_VFS && (MICROPY_VFS_LFS1 || MICROPY_VFS_LFS2)
-
enum { LFS_MAKE_ARG_bdev, LFS_MAKE_ARG_readsize, LFS_MAKE_ARG_progsize, LFS_MAKE_ARG_lookahead, LFS_MAKE_ARG_mtime };
static const mp_arg_t lfs_make_allowed_args[] = {
diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c
index d9617817f956..fe0731eced2a 100644
--- a/extmod/vfs_lfsx.c
+++ b/extmod/vfs_lfsx.c
@@ -24,6 +24,9 @@
* THE SOFTWARE.
*/
+// This file should be compiled when included from vfs_lfs.c.
+#if defined(LFS_BUILD_VERSION)
+
#include
#include
@@ -320,7 +323,7 @@ STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
size_t from = 1;
char *cwd = vstr_str(&self->cur_dir);
while (from < CWD_LEN) {
- for (; cwd[from] == '/' && from < CWD_LEN; ++from) {
+ for (; from < CWD_LEN && cwd[from] == '/'; ++from) {
// Scan for the start
}
if (from > to) {
@@ -328,7 +331,7 @@ STATIC mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
vstr_cut_out_bytes(&self->cur_dir, to, from - to);
from = to;
}
- for (; cwd[from] != '/' && from < CWD_LEN; ++from) {
+ for (; from < CWD_LEN && cwd[from] != '/'; ++from) {
// Scan for the next /
}
if ((from - to) == 1 && cwd[to] == '.') {
@@ -518,3 +521,5 @@ MP_DEFINE_CONST_OBJ_TYPE(
);
#undef VFS_LFSx_QSTR
+
+#endif // defined(LFS_BUILD_VERSION)
diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c
index 2c87fd5b994c..879ba78973db 100644
--- a/extmod/vfs_lfsx_file.c
+++ b/extmod/vfs_lfsx_file.c
@@ -24,6 +24,9 @@
* THE SOFTWARE.
*/
+// This file should be compiled when included from vfs_lfs.c.
+#if defined(LFS_BUILD_VERSION)
+
#include
#include
@@ -120,12 +123,6 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod
return MP_OBJ_FROM_PTR(o);
}
-STATIC mp_obj_t MP_VFS_LFSx(file___exit__)(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- return mp_stream_close(args[0]);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(MP_VFS_LFSx(file___exit___obj), 4, 4, MP_VFS_LFSx(file___exit__));
-
STATIC mp_uint_t MP_VFS_LFSx(file_read)(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
MP_OBJ_VFS_LFSx_FILE *self = MP_OBJ_TO_PTR(self_in);
MP_VFS_LFSx(check_open)(self);
@@ -210,7 +207,7 @@ STATIC const mp_rom_map_elem_t MP_VFS_LFSx(file_locals_dict_table)[] = {
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
- { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&MP_VFS_LFSx(file___exit___obj)) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
};
STATIC MP_DEFINE_CONST_DICT(MP_VFS_LFSx(file_locals_dict), MP_VFS_LFSx(file_locals_dict_table));
@@ -244,3 +241,5 @@ MP_DEFINE_CONST_OBJ_TYPE(
protocol, &MP_VFS_LFSx(textio_stream_p),
locals_dict, &MP_VFS_LFSx(file_locals_dict)
);
+
+#endif // defined(LFS_BUILD_VERSION)
diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c
index 3694ebaf9974..d63bb5be7bff 100644
--- a/extmod/vfs_posix.c
+++ b/extmod/vfs_posix.c
@@ -37,9 +37,11 @@
#error "MICROPY_VFS_POSIX requires MICROPY_ENABLE_FINALISER"
#endif
+#include
#include
#include
#include
+#include
#include
#ifdef _MSC_VER
#include // For mkdir etc.
@@ -190,7 +192,7 @@ STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {
MP_THREAD_GIL_ENTER();
const char *fn = dirent->d_name;
- if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
+ if (fn[0] == '.' && (fn[1] == 0 || (fn[1] == '.' && fn[2] == 0))) {
// skip . and ..
continue;
}
@@ -330,7 +332,7 @@ STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
-#if MICROPY_PY_UOS_STATVFS
+#if MICROPY_PY_OS_STATVFS
#ifdef __ANDROID__
#define USE_STATFS 1
@@ -388,7 +390,7 @@ STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) },
{ MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) },
{ MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) },
- #if MICROPY_PY_UOS_STATVFS
+ #if MICROPY_PY_OS_STATVFS
{ MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) },
#endif
};
diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c
index ea19de7fd04a..cfc56df99f10 100644
--- a/extmod/vfs_posix_file.c
+++ b/extmod/vfs_posix_file.c
@@ -115,12 +115,6 @@ STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno);
-STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- return mp_stream_close(args[0]);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__);
-
STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
@@ -194,7 +188,7 @@ STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_
return 0;
case MP_STREAM_GET_FILENO:
return o->fd;
- #if MICROPY_PY_USELECT
+ #if MICROPY_PY_SELECT
case MP_STREAM_POLL: {
#ifdef _WIN32
mp_raise_NotImplementedError(MP_ERROR_TEXT("poll on file not available on win32"));
@@ -239,7 +233,7 @@ STATIC const mp_rom_map_elem_t vfs_posix_rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
- { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
};
STATIC MP_DEFINE_CONST_DICT(vfs_posix_rawfile_locals_dict, vfs_posix_rawfile_locals_dict_table);
diff --git a/lib/btstack b/lib/btstack
index c8b9823f68c6..77e752abd6a0 160000
--- a/lib/btstack
+++ b/lib/btstack
@@ -1 +1 @@
-Subproject commit c8b9823f68c6af0fa52e2c4e009aba4dbf257232
+Subproject commit 77e752abd6a0992334047a48038a5a3960e5c6bc
diff --git a/lib/cyw43-driver b/lib/cyw43-driver
index 2ab6ca93f9cd..8ef38a6d32c5 160000
--- a/lib/cyw43-driver
+++ b/lib/cyw43-driver
@@ -1 +1 @@
-Subproject commit 2ab6ca93f9cd044bc6f35c1403b1284e4161294a
+Subproject commit 8ef38a6d32c54f850bff8f189bdca19ded33792a
diff --git a/lib/fsp b/lib/fsp
index 55bffd3a71cb..e78939d32d1c 160000
--- a/lib/fsp
+++ b/lib/fsp
@@ -1 +1 @@
-Subproject commit 55bffd3a71cbeed2104cf30e7a39b641d8c1ff48
+Subproject commit e78939d32d1ccea9f0ba8bb42c51aceffd386b9b
diff --git a/lib/libm/thumb_vfp_sqrtf.c b/lib/libm/thumb_vfp_sqrtf.c
index 12ffebf82709..25b8823163c6 100644
--- a/lib/libm/thumb_vfp_sqrtf.c
+++ b/lib/libm/thumb_vfp_sqrtf.c
@@ -3,7 +3,7 @@
#include
float sqrtf(float x) {
- asm volatile (
+ __asm__ volatile (
"vsqrt.f32 %[r], %[x]\n"
: [r] "=t" (x)
: [x] "t" (x));
diff --git a/lib/libm_dbl/thumb_vfp_sqrt.c b/lib/libm_dbl/thumb_vfp_sqrt.c
index dd37a07b053c..ccd33e97960f 100644
--- a/lib/libm_dbl/thumb_vfp_sqrt.c
+++ b/lib/libm_dbl/thumb_vfp_sqrt.c
@@ -2,7 +2,7 @@
double sqrt(double x) {
double ret;
- asm volatile (
+ __asm__ volatile (
"vsqrt.f64 %P0, %P1\n"
: "=w" (ret)
: "w" (x));
diff --git a/lib/mbedtls b/lib/mbedtls
index 1bc2c9cb8b8f..981743de6fcd 160000
--- a/lib/mbedtls
+++ b/lib/mbedtls
@@ -1 +1 @@
-Subproject commit 1bc2c9cb8b8fe4659bd94b8ebba5a4c02029b7fa
+Subproject commit 981743de6fcdbe672e482b6fd724d31d0a0d2476
diff --git a/lib/mbedtls_errors/error.fmt b/lib/mbedtls_errors/error.fmt
index 5beeb6e7c96b..15889128d44c 100644
--- a/lib/mbedtls_errors/error.fmt
+++ b/lib/mbedtls_errors/error.fmt
@@ -110,7 +110,7 @@ void mbedtls_strerror(int ret, char *buf, size_t buflen) {
if (got_hl) {
use_ret = ret & 0xFF80;
- // special case
+ // special case, don't try to translate low level code
#if defined(MBEDTLS_SSL_TLS_C)
if (use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)) {
strncpy(buf, "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE", buflen);
diff --git a/lib/mbedtls_errors/esp32_mbedtls_errors.c b/lib/mbedtls_errors/esp32_mbedtls_errors.c
new file mode 100644
index 000000000000..c56f8a19ffb1
--- /dev/null
+++ b/lib/mbedtls_errors/esp32_mbedtls_errors.c
@@ -0,0 +1,710 @@
+/*
+ * Error message information
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY)
+#include "mbedtls/error.h"
+#include
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#define mbedtls_snprintf snprintf
+#define mbedtls_time_t time_t
+#endif
+
+#if defined(MBEDTLS_ERROR_C)
+
+#include
+
+#if defined(MBEDTLS_AES_C)
+#include "mbedtls/aes.h"
+#endif
+
+#if defined(MBEDTLS_ARC4_C)
+#include "mbedtls/arc4.h"
+#endif
+
+#if defined(MBEDTLS_ARIA_C)
+#include "mbedtls/aria.h"
+#endif
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+#include "mbedtls/asn1.h"
+#endif
+
+#if defined(MBEDTLS_BASE64_C)
+#include "mbedtls/base64.h"
+#endif
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+#if defined(MBEDTLS_BLOWFISH_C)
+#include "mbedtls/blowfish.h"
+#endif
+
+#if defined(MBEDTLS_CAMELLIA_C)
+#include "mbedtls/camellia.h"
+#endif
+
+#if defined(MBEDTLS_CCM_C)
+#include "mbedtls/ccm.h"
+#endif
+
+#if defined(MBEDTLS_CHACHA20_C)
+#include "mbedtls/chacha20.h"
+#endif
+
+#if defined(MBEDTLS_CHACHAPOLY_C)
+#include "mbedtls/chachapoly.h"
+#endif
+
+#if defined(MBEDTLS_CIPHER_C)
+#include "mbedtls/cipher.h"
+#endif
+
+#if defined(MBEDTLS_CMAC_C)
+#include "mbedtls/cmac.h"
+#endif
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+#include "mbedtls/ctr_drbg.h"
+#endif
+
+#if defined(MBEDTLS_DES_C)
+#include "mbedtls/des.h"
+#endif
+
+#if defined(MBEDTLS_DHM_C)
+#include "mbedtls/dhm.h"
+#endif
+
+#if defined(MBEDTLS_ECP_C)
+#include "mbedtls/ecp.h"
+#endif
+
+#if defined(MBEDTLS_ENTROPY_C)
+#include "mbedtls/entropy.h"
+#endif
+
+#if defined(MBEDTLS_GCM_C)
+#include "mbedtls/gcm.h"
+#endif
+
+#if defined(MBEDTLS_HKDF_C)
+#include "mbedtls/hkdf.h"
+#endif
+
+#if defined(MBEDTLS_HMAC_DRBG_C)
+#include "mbedtls/hmac_drbg.h"
+#endif
+
+#if defined(MBEDTLS_MD_C)
+#include "mbedtls/md.h"
+#endif
+
+#if defined(MBEDTLS_MD2_C)
+#include "mbedtls/md2.h"
+#endif
+
+#if defined(MBEDTLS_MD4_C)
+#include "mbedtls/md4.h"
+#endif
+
+#if defined(MBEDTLS_MD5_C)
+#include "mbedtls/md5.h"
+#endif
+
+#if defined(MBEDTLS_NET_C)
+#include "mbedtls/net_sockets.h"
+#endif
+
+#if defined(MBEDTLS_OID_C)
+#include "mbedtls/oid.h"
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C)
+#include "mbedtls/padlock.h"
+#endif
+
+#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
+#include "mbedtls/pem.h"
+#endif
+
+#if defined(MBEDTLS_PK_C)
+#include "mbedtls/pk.h"
+#endif
+
+#if defined(MBEDTLS_PKCS12_C)
+#include "mbedtls/pkcs12.h"
+#endif
+
+#if defined(MBEDTLS_PKCS5_C)
+#include "mbedtls/pkcs5.h"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#endif
+
+#if defined(MBEDTLS_POLY1305_C)
+#include "mbedtls/poly1305.h"
+#endif
+
+#if defined(MBEDTLS_RIPEMD160_C)
+#include "mbedtls/ripemd160.h"
+#endif
+
+#if defined(MBEDTLS_RSA_C)
+#include "mbedtls/rsa.h"
+#endif
+
+#if defined(MBEDTLS_SHA1_C)
+#include "mbedtls/sha1.h"
+#endif
+
+#if defined(MBEDTLS_SHA256_C)
+#include "mbedtls/sha256.h"
+#endif
+
+#if defined(MBEDTLS_SHA512_C)
+#include "mbedtls/sha512.h"
+#endif
+
+#if defined(MBEDTLS_SSL_TLS_C)
+#include "mbedtls/ssl.h"
+#endif
+
+#if defined(MBEDTLS_THREADING_C)
+#include "mbedtls/threading.h"
+#endif
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+#include "mbedtls/x509.h"
+#endif
+
+#if defined(MBEDTLS_XTEA_C)
+#include "mbedtls/xtea.h"
+#endif
+
+
+// Error code table type
+struct ssl_errs {
+ int16_t errnum;
+ const char *errstr;
+};
+
+// Table of high level error codes
+static const struct ssl_errs mbedtls_high_level_error_tab[] = {
+// BEGIN generated code
+#if defined(MBEDTLS_CIPHER_C)
+ { -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE), "CIPHER_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA), "CIPHER_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED), "CIPHER_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_CIPHER_INVALID_PADDING), "CIPHER_INVALID_PADDING" },
+ { -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED), "CIPHER_FULL_BLOCK_EXPECTED" },
+ { -(MBEDTLS_ERR_CIPHER_AUTH_FAILED), "CIPHER_AUTH_FAILED" },
+ { -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT), "CIPHER_INVALID_CONTEXT" },
+ { -(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED), "CIPHER_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_CIPHER_C */
+
+#if defined(MBEDTLS_DHM_C)
+ { -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA), "DHM_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED), "DHM_READ_PARAMS_FAILED" },
+ { -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED), "DHM_MAKE_PARAMS_FAILED" },
+ { -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED), "DHM_READ_PUBLIC_FAILED" },
+ { -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED), "DHM_MAKE_PUBLIC_FAILED" },
+ { -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED), "DHM_CALC_SECRET_FAILED" },
+ { -(MBEDTLS_ERR_DHM_INVALID_FORMAT), "DHM_INVALID_FORMAT" },
+ { -(MBEDTLS_ERR_DHM_ALLOC_FAILED), "DHM_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_DHM_FILE_IO_ERROR), "DHM_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_DHM_HW_ACCEL_FAILED), "DHM_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_DHM_SET_GROUP_FAILED), "DHM_SET_GROUP_FAILED" },
+#endif /* MBEDTLS_DHM_C */
+
+#if defined(MBEDTLS_ECP_C)
+ { -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA), "ECP_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL), "ECP_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE), "ECP_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_ECP_VERIFY_FAILED), "ECP_VERIFY_FAILED" },
+ { -(MBEDTLS_ERR_ECP_ALLOC_FAILED), "ECP_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_ECP_RANDOM_FAILED), "ECP_RANDOM_FAILED" },
+ { -(MBEDTLS_ERR_ECP_INVALID_KEY), "ECP_INVALID_KEY" },
+ { -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH), "ECP_SIG_LEN_MISMATCH" },
+ { -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED), "ECP_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_ECP_IN_PROGRESS), "ECP_IN_PROGRESS" },
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_MD_C)
+ { -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE), "MD_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_MD_BAD_INPUT_DATA), "MD_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_MD_ALLOC_FAILED), "MD_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_MD_FILE_IO_ERROR), "MD_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_MD_HW_ACCEL_FAILED), "MD_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_MD_C */
+
+#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C)
+ { -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT), "PEM_NO_HEADER_FOOTER_PRESENT" },
+ { -(MBEDTLS_ERR_PEM_INVALID_DATA), "PEM_INVALID_DATA" },
+ { -(MBEDTLS_ERR_PEM_ALLOC_FAILED), "PEM_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_PEM_INVALID_ENC_IV), "PEM_INVALID_ENC_IV" },
+ { -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG), "PEM_UNKNOWN_ENC_ALG" },
+ { -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED), "PEM_PASSWORD_REQUIRED" },
+ { -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH), "PEM_PASSWORD_MISMATCH" },
+ { -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE), "PEM_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA), "PEM_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
+
+#if defined(MBEDTLS_PK_C)
+ { -(MBEDTLS_ERR_PK_ALLOC_FAILED), "PK_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_PK_TYPE_MISMATCH), "PK_TYPE_MISMATCH" },
+ { -(MBEDTLS_ERR_PK_BAD_INPUT_DATA), "PK_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_PK_FILE_IO_ERROR), "PK_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION), "PK_KEY_INVALID_VERSION" },
+ { -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT), "PK_KEY_INVALID_FORMAT" },
+ { -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG), "PK_UNKNOWN_PK_ALG" },
+ { -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED), "PK_PASSWORD_REQUIRED" },
+ { -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH), "PK_PASSWORD_MISMATCH" },
+ { -(MBEDTLS_ERR_PK_INVALID_PUBKEY), "PK_INVALID_PUBKEY" },
+ { -(MBEDTLS_ERR_PK_INVALID_ALG), "PK_INVALID_ALG" },
+ { -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE), "PK_UNKNOWN_NAMED_CURVE" },
+ { -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE), "PK_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH), "PK_SIG_LEN_MISMATCH" },
+ { -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED), "PK_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_PK_C */
+
+#if defined(MBEDTLS_PKCS12_C)
+ { -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA), "PKCS12_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE), "PKCS12_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT), "PKCS12_PBE_INVALID_FORMAT" },
+ { -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH), "PKCS12_PASSWORD_MISMATCH" },
+#endif /* MBEDTLS_PKCS12_C */
+
+#if defined(MBEDTLS_PKCS5_C)
+ { -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA), "PKCS5_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT), "PKCS5_INVALID_FORMAT" },
+ { -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE), "PKCS5_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH), "PKCS5_PASSWORD_MISMATCH" },
+#endif /* MBEDTLS_PKCS5_C */
+
+#if defined(MBEDTLS_RSA_C)
+ { -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA), "RSA_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_RSA_INVALID_PADDING), "RSA_INVALID_PADDING" },
+ { -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED), "RSA_KEY_GEN_FAILED" },
+ { -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED), "RSA_KEY_CHECK_FAILED" },
+ { -(MBEDTLS_ERR_RSA_PUBLIC_FAILED), "RSA_PUBLIC_FAILED" },
+ { -(MBEDTLS_ERR_RSA_PRIVATE_FAILED), "RSA_PRIVATE_FAILED" },
+ { -(MBEDTLS_ERR_RSA_VERIFY_FAILED), "RSA_VERIFY_FAILED" },
+ { -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE), "RSA_OUTPUT_TOO_LARGE" },
+ { -(MBEDTLS_ERR_RSA_RNG_FAILED), "RSA_RNG_FAILED" },
+ { -(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION), "RSA_UNSUPPORTED_OPERATION" },
+ { -(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED), "RSA_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_SSL_TLS_C)
+ { -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE), "SSL_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA), "SSL_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_SSL_INVALID_MAC), "SSL_INVALID_MAC" },
+ { -(MBEDTLS_ERR_SSL_INVALID_RECORD), "SSL_INVALID_RECORD" },
+ { -(MBEDTLS_ERR_SSL_CONN_EOF), "SSL_CONN_EOF" },
+ { -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER), "SSL_UNKNOWN_CIPHER" },
+ { -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN), "SSL_NO_CIPHER_CHOSEN" },
+ { -(MBEDTLS_ERR_SSL_NO_RNG), "SSL_NO_RNG" },
+ { -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE), "SSL_NO_CLIENT_CERTIFICATE" },
+ { -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE), "SSL_CERTIFICATE_TOO_LARGE" },
+ { -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED), "SSL_CERTIFICATE_REQUIRED" },
+ { -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED), "SSL_PRIVATE_KEY_REQUIRED" },
+ { -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED), "SSL_CA_CHAIN_REQUIRED" },
+ { -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE), "SSL_UNEXPECTED_MESSAGE" },
+ { -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED), "SSL_PEER_VERIFY_FAILED" },
+ { -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY), "SSL_PEER_CLOSE_NOTIFY" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO), "SSL_BAD_HS_CLIENT_HELLO" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO), "SSL_BAD_HS_SERVER_HELLO" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE), "SSL_BAD_HS_CERTIFICATE" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST), "SSL_BAD_HS_CERTIFICATE_REQUEST" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE), "SSL_BAD_HS_SERVER_KEY_EXCHANGE" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE), "SSL_BAD_HS_SERVER_HELLO_DONE" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY), "SSL_BAD_HS_CERTIFICATE_VERIFY" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC), "SSL_BAD_HS_CHANGE_CIPHER_SPEC" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED), "SSL_BAD_HS_FINISHED" },
+ { -(MBEDTLS_ERR_SSL_ALLOC_FAILED), "SSL_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED), "SSL_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH), "SSL_HW_ACCEL_FALLTHROUGH" },
+ { -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED), "SSL_COMPRESSION_FAILED" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION), "SSL_BAD_HS_PROTOCOL_VERSION" },
+ { -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET), "SSL_BAD_HS_NEW_SESSION_TICKET" },
+ { -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED), "SSL_SESSION_TICKET_EXPIRED" },
+ { -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH), "SSL_PK_TYPE_MISMATCH" },
+ { -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY), "SSL_UNKNOWN_IDENTITY" },
+ { -(MBEDTLS_ERR_SSL_INTERNAL_ERROR), "SSL_INTERNAL_ERROR" },
+ { -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING), "SSL_COUNTER_WRAPPING" },
+ { -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO), "SSL_WAITING_SERVER_HELLO_RENEGO" },
+ { -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED), "SSL_HELLO_VERIFY_REQUIRED" },
+ { -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL), "SSL_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE), "SSL_NO_USABLE_CIPHERSUITE" },
+ { -(MBEDTLS_ERR_SSL_WANT_READ), "SSL_WANT_READ" },
+ { -(MBEDTLS_ERR_SSL_WANT_WRITE), "SSL_WANT_WRITE" },
+ { -(MBEDTLS_ERR_SSL_TIMEOUT), "SSL_TIMEOUT" },
+ { -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT), "SSL_CLIENT_RECONNECT" },
+ { -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD), "SSL_UNEXPECTED_RECORD" },
+ { -(MBEDTLS_ERR_SSL_NON_FATAL), "SSL_NON_FATAL" },
+ { -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH), "SSL_INVALID_VERIFY_HASH" },
+ { -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING), "SSL_CONTINUE_PROCESSING" },
+ { -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS), "SSL_ASYNC_IN_PROGRESS" },
+ { -(MBEDTLS_ERR_SSL_EARLY_MESSAGE), "SSL_EARLY_MESSAGE" },
+ { -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS), "SSL_CRYPTO_IN_PROGRESS" },
+ { -(MBEDTLS_ERR_SSL_BAD_CONFIG), "SSL_BAD_CONFIG" },
+#endif /* MBEDTLS_SSL_TLS_C */
+
+#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
+ { -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE), "X509_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_X509_UNKNOWN_OID), "X509_UNKNOWN_OID" },
+ { -(MBEDTLS_ERR_X509_INVALID_FORMAT), "X509_INVALID_FORMAT" },
+ { -(MBEDTLS_ERR_X509_INVALID_VERSION), "X509_INVALID_VERSION" },
+ { -(MBEDTLS_ERR_X509_INVALID_SERIAL), "X509_INVALID_SERIAL" },
+ { -(MBEDTLS_ERR_X509_INVALID_ALG), "X509_INVALID_ALG" },
+ { -(MBEDTLS_ERR_X509_INVALID_NAME), "X509_INVALID_NAME" },
+ { -(MBEDTLS_ERR_X509_INVALID_DATE), "X509_INVALID_DATE" },
+ { -(MBEDTLS_ERR_X509_INVALID_SIGNATURE), "X509_INVALID_SIGNATURE" },
+ { -(MBEDTLS_ERR_X509_INVALID_EXTENSIONS), "X509_INVALID_EXTENSIONS" },
+ { -(MBEDTLS_ERR_X509_UNKNOWN_VERSION), "X509_UNKNOWN_VERSION" },
+ { -(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG), "X509_UNKNOWN_SIG_ALG" },
+ { -(MBEDTLS_ERR_X509_SIG_MISMATCH), "X509_SIG_MISMATCH" },
+ { -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED), "X509_CERT_VERIFY_FAILED" },
+ { -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT), "X509_CERT_UNKNOWN_FORMAT" },
+ { -(MBEDTLS_ERR_X509_BAD_INPUT_DATA), "X509_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_X509_ALLOC_FAILED), "X509_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_X509_FILE_IO_ERROR), "X509_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL), "X509_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_X509_FATAL_ERROR), "X509_FATAL_ERROR" },
+#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
+// END generated code
+};
+
+static const struct ssl_errs mbedtls_low_level_error_tab[] = {
+// Low level error codes
+//
+// BEGIN generated code
+#if defined(MBEDTLS_AES_C)
+ { -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH), "AES_INVALID_KEY_LENGTH" },
+ { -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH), "AES_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_AES_BAD_INPUT_DATA), "AES_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE), "AES_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED), "AES_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_AES_C */
+
+#if defined(MBEDTLS_ARC4_C)
+ { -(MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED), "ARC4_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_ARC4_C */
+
+#if defined(MBEDTLS_ARIA_C)
+ { -(MBEDTLS_ERR_ARIA_BAD_INPUT_DATA), "ARIA_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH), "ARIA_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE), "ARIA_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED), "ARIA_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_ARIA_C */
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+ { -(MBEDTLS_ERR_ASN1_OUT_OF_DATA), "ASN1_OUT_OF_DATA" },
+ { -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG), "ASN1_UNEXPECTED_TAG" },
+ { -(MBEDTLS_ERR_ASN1_INVALID_LENGTH), "ASN1_INVALID_LENGTH" },
+ { -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH), "ASN1_LENGTH_MISMATCH" },
+ { -(MBEDTLS_ERR_ASN1_INVALID_DATA), "ASN1_INVALID_DATA" },
+ { -(MBEDTLS_ERR_ASN1_ALLOC_FAILED), "ASN1_ALLOC_FAILED" },
+ { -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL), "ASN1_BUF_TOO_SMALL" },
+#endif /* MBEDTLS_ASN1_PARSE_C */
+
+#if defined(MBEDTLS_BASE64_C)
+ { -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL), "BASE64_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER), "BASE64_INVALID_CHARACTER" },
+#endif /* MBEDTLS_BASE64_C */
+
+#if defined(MBEDTLS_BIGNUM_C)
+ { -(MBEDTLS_ERR_MPI_FILE_IO_ERROR), "MPI_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA), "MPI_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_MPI_INVALID_CHARACTER), "MPI_INVALID_CHARACTER" },
+ { -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL), "MPI_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE), "MPI_NEGATIVE_VALUE" },
+ { -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO), "MPI_DIVISION_BY_ZERO" },
+ { -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE), "MPI_NOT_ACCEPTABLE" },
+ { -(MBEDTLS_ERR_MPI_ALLOC_FAILED), "MPI_ALLOC_FAILED" },
+#endif /* MBEDTLS_BIGNUM_C */
+
+#if defined(MBEDTLS_BLOWFISH_C)
+ { -(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA), "BLOWFISH_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH), "BLOWFISH_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED), "BLOWFISH_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_BLOWFISH_C */
+
+#if defined(MBEDTLS_CAMELLIA_C)
+ { -(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA), "CAMELLIA_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH), "CAMELLIA_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED), "CAMELLIA_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_CAMELLIA_C */
+
+#if defined(MBEDTLS_CCM_C)
+ { -(MBEDTLS_ERR_CCM_BAD_INPUT), "CCM_BAD_INPUT" },
+ { -(MBEDTLS_ERR_CCM_AUTH_FAILED), "CCM_AUTH_FAILED" },
+ { -(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED), "CCM_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_CCM_C */
+
+#if defined(MBEDTLS_CHACHA20_C)
+ { -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA), "CHACHA20_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE), "CHACHA20_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED), "CHACHA20_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_CHACHA20_C */
+
+#if defined(MBEDTLS_CHACHAPOLY_C)
+ { -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE), "CHACHAPOLY_BAD_STATE" },
+ { -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED), "CHACHAPOLY_AUTH_FAILED" },
+#endif /* MBEDTLS_CHACHAPOLY_C */
+
+#if defined(MBEDTLS_CMAC_C)
+ { -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED), "CMAC_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_CMAC_C */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+ { -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED), "CTR_DRBG_ENTROPY_SOURCE_FAILED" },
+ { -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG), "CTR_DRBG_REQUEST_TOO_BIG" },
+ { -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG), "CTR_DRBG_INPUT_TOO_BIG" },
+ { -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR), "CTR_DRBG_FILE_IO_ERROR" },
+#endif /* MBEDTLS_CTR_DRBG_C */
+
+#if defined(MBEDTLS_DES_C)
+ { -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH), "DES_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_DES_HW_ACCEL_FAILED), "DES_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_DES_C */
+
+#if defined(MBEDTLS_ENTROPY_C)
+ { -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED), "ENTROPY_SOURCE_FAILED" },
+ { -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES), "ENTROPY_MAX_SOURCES" },
+ { -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED), "ENTROPY_NO_SOURCES_DEFINED" },
+ { -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE), "ENTROPY_NO_STRONG_SOURCE" },
+ { -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR), "ENTROPY_FILE_IO_ERROR" },
+#endif /* MBEDTLS_ENTROPY_C */
+
+#if defined(MBEDTLS_GCM_C)
+ { -(MBEDTLS_ERR_GCM_AUTH_FAILED), "GCM_AUTH_FAILED" },
+ { -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED), "GCM_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_GCM_BAD_INPUT), "GCM_BAD_INPUT" },
+#endif /* MBEDTLS_GCM_C */
+
+#if defined(MBEDTLS_HKDF_C)
+ { -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA), "HKDF_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_HKDF_C */
+
+#if defined(MBEDTLS_HMAC_DRBG_C)
+ { -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG), "HMAC_DRBG_REQUEST_TOO_BIG" },
+ { -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG), "HMAC_DRBG_INPUT_TOO_BIG" },
+ { -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR), "HMAC_DRBG_FILE_IO_ERROR" },
+ { -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED), "HMAC_DRBG_ENTROPY_SOURCE_FAILED" },
+#endif /* MBEDTLS_HMAC_DRBG_C */
+
+#if defined(MBEDTLS_MD2_C)
+ { -(MBEDTLS_ERR_MD2_HW_ACCEL_FAILED), "MD2_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_MD2_C */
+
+#if defined(MBEDTLS_MD4_C)
+ { -(MBEDTLS_ERR_MD4_HW_ACCEL_FAILED), "MD4_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_MD4_C */
+
+#if defined(MBEDTLS_MD5_C)
+ { -(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED), "MD5_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_MD5_C */
+
+#if defined(MBEDTLS_NET_C)
+ { -(MBEDTLS_ERR_NET_SOCKET_FAILED), "NET_SOCKET_FAILED" },
+ { -(MBEDTLS_ERR_NET_CONNECT_FAILED), "NET_CONNECT_FAILED" },
+ { -(MBEDTLS_ERR_NET_BIND_FAILED), "NET_BIND_FAILED" },
+ { -(MBEDTLS_ERR_NET_LISTEN_FAILED), "NET_LISTEN_FAILED" },
+ { -(MBEDTLS_ERR_NET_ACCEPT_FAILED), "NET_ACCEPT_FAILED" },
+ { -(MBEDTLS_ERR_NET_RECV_FAILED), "NET_RECV_FAILED" },
+ { -(MBEDTLS_ERR_NET_SEND_FAILED), "NET_SEND_FAILED" },
+ { -(MBEDTLS_ERR_NET_CONN_RESET), "NET_CONN_RESET" },
+ { -(MBEDTLS_ERR_NET_UNKNOWN_HOST), "NET_UNKNOWN_HOST" },
+ { -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL), "NET_BUFFER_TOO_SMALL" },
+ { -(MBEDTLS_ERR_NET_INVALID_CONTEXT), "NET_INVALID_CONTEXT" },
+ { -(MBEDTLS_ERR_NET_POLL_FAILED), "NET_POLL_FAILED" },
+ { -(MBEDTLS_ERR_NET_BAD_INPUT_DATA), "NET_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_NET_C */
+
+#if defined(MBEDTLS_OID_C)
+ { -(MBEDTLS_ERR_OID_NOT_FOUND), "OID_NOT_FOUND" },
+ { -(MBEDTLS_ERR_OID_BUF_TOO_SMALL), "OID_BUF_TOO_SMALL" },
+#endif /* MBEDTLS_OID_C */
+
+#if defined(MBEDTLS_PADLOCK_C)
+ { -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED), "PADLOCK_DATA_MISALIGNED" },
+#endif /* MBEDTLS_PADLOCK_C */
+
+#if defined(MBEDTLS_PLATFORM_C)
+ { -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED), "PLATFORM_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED), "PLATFORM_FEATURE_UNSUPPORTED" },
+#endif /* MBEDTLS_PLATFORM_C */
+
+#if defined(MBEDTLS_POLY1305_C)
+ { -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA), "POLY1305_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE), "POLY1305_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED), "POLY1305_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_POLY1305_C */
+
+#if defined(MBEDTLS_RIPEMD160_C)
+ { -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED), "RIPEMD160_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_RIPEMD160_C */
+
+#if defined(MBEDTLS_SHA1_C)
+ { -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED), "SHA1_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA), "SHA1_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_SHA1_C */
+
+#if defined(MBEDTLS_SHA256_C)
+ { -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED), "SHA256_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA), "SHA256_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_SHA256_C */
+
+#if defined(MBEDTLS_SHA512_C)
+ { -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED), "SHA512_HW_ACCEL_FAILED" },
+ { -(MBEDTLS_ERR_SHA512_BAD_INPUT_DATA), "SHA512_BAD_INPUT_DATA" },
+#endif /* MBEDTLS_SHA512_C */
+
+#if defined(MBEDTLS_THREADING_C)
+ { -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE), "THREADING_FEATURE_UNAVAILABLE" },
+ { -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA), "THREADING_BAD_INPUT_DATA" },
+ { -(MBEDTLS_ERR_THREADING_MUTEX_ERROR), "THREADING_MUTEX_ERROR" },
+#endif /* MBEDTLS_THREADING_C */
+
+#if defined(MBEDTLS_XTEA_C)
+ { -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH), "XTEA_INVALID_INPUT_LENGTH" },
+ { -(MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED), "XTEA_HW_ACCEL_FAILED" },
+#endif /* MBEDTLS_XTEA_C */
+// END generated code
+};
+
+static const char *mbedtls_err_prefix = "MBEDTLS_ERR_";
+#define MBEDTLS_ERR_PREFIX_LEN ( sizeof("MBEDTLS_ERR_")-1 )
+
+// copy error text into buffer, ensure null termination, return strlen of result
+static size_t mbedtls_err_to_str(int err, const struct ssl_errs tab[], int tab_len, char *buf, size_t buflen) {
+ if (buflen == 0) return 0;
+
+ // prefix for all error names
+ strncpy(buf, mbedtls_err_prefix, buflen);
+ if (buflen <= MBEDTLS_ERR_PREFIX_LEN+1) {
+ buf[buflen-1] = 0;
+ return buflen-1;
+ }
+
+ // append error name from table
+ for (int i = 0; i < tab_len; i++) {
+ if (tab[i].errnum == err) {
+ strncpy(buf+MBEDTLS_ERR_PREFIX_LEN, tab[i].errstr, buflen-MBEDTLS_ERR_PREFIX_LEN);
+ buf[buflen-1] = 0;
+ return strlen(buf);
+ }
+ }
+
+ mbedtls_snprintf(buf+MBEDTLS_ERR_PREFIX_LEN, buflen-MBEDTLS_ERR_PREFIX_LEN, "UNKNOWN (0x%04X)",
+ err);
+ return strlen(buf);
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+void mbedtls_strerror(int ret, char *buf, size_t buflen) {
+ int use_ret;
+
+ if (buflen == 0) return;
+
+ buf[buflen-1] = 0;
+
+ if (ret < 0) ret = -ret;
+
+ //
+ // High-level error codes
+ //
+ uint8_t got_hl = (ret & 0xFF80) != 0;
+ if (got_hl) {
+ use_ret = ret & 0xFF80;
+
+ // special case
+#if defined(MBEDTLS_SSL_TLS_C)
+ if (use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)) {
+ strncpy(buf, "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE", buflen);
+ buf[buflen-1] = 0;
+ return;
+ }
+#endif
+
+ size_t len = mbedtls_err_to_str(use_ret, mbedtls_high_level_error_tab,
+ ARRAY_SIZE(mbedtls_high_level_error_tab), buf, buflen);
+
+ buf += len;
+ buflen -= len;
+ if (buflen == 0) return;
+ }
+
+ //
+ // Low-level error codes
+ //
+ use_ret = ret & ~0xFF80;
+
+ if (use_ret == 0) return;
+
+ // If high level code is present, make a concatenation between both error strings.
+ if (got_hl) {
+ if (buflen < 2) return;
+ *buf++ = '+';
+ buflen--;
+ }
+
+ mbedtls_err_to_str(use_ret, mbedtls_low_level_error_tab,
+ ARRAY_SIZE(mbedtls_low_level_error_tab), buf, buflen);
+}
+
+#else /* MBEDTLS_ERROR_C */
+
+#if defined(MBEDTLS_ERROR_STRERROR_DUMMY)
+
+/*
+ * Provide an non-function in case MBEDTLS_ERROR_C is not defined
+ */
+void mbedtls_strerror( int ret, char *buf, size_t buflen )
+{
+ ((void) ret);
+
+ if( buflen > 0 )
+ buf[0] = '\0';
+}
+
+#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */
+
+#endif /* MBEDTLS_ERROR_C */
diff --git a/lib/mbedtls_errors/generate_errors.diff b/lib/mbedtls_errors/generate_errors.diff
index ad24c372faed..bea47cd66fba 100644
--- a/lib/mbedtls_errors/generate_errors.diff
+++ b/lib/mbedtls_errors/generate_errors.diff
@@ -1,22 +1,29 @@
---- generate_errors_orig.pl 2020-06-20 08:40:38.819060379 -0700
-+++ generate_errors.pl 2020-06-20 08:47:26.511163591 -0700
-@@ -162,16 +162,12 @@
-
- if ($error_name eq "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE")
+--- generate_errors_orig.pl 2023-04-30 17:58:23.503070758 +1000
++++ generate_errors.py 2023-04-30 17:58:20.826338349 +1000
+@@ -162,7 +162,7 @@
{
-- ${$code_check} .= "${white_space}if( use_ret == -($error_name) )\n".
-- "${white_space}\{\n".
-- "${white_space} mbedtls_snprintf( buf, buflen, \"$module_name - $description\" );\n".
-- "${white_space} return;\n".
-- "${white_space}}\n"
-+ # no-op, this case is hard-coded in error.fmt
+ $code_check = \$ll_code_check;
+ $old_define = \$ll_old_define;
+- $white_space = ' ';
++ $white_space = ' ';
}
else
{
-- ${$code_check} .= "${white_space}if( use_ret == -($error_name) )\n".
-- "${white_space} mbedtls_snprintf( buf, buflen, \"$module_name - $description\" );\n"
-+ my $error_text = $error_name =~ s/^MBEDTLS_ERR_//r;
-+ ${$code_check} .= "${white_space}{ -($error_name), \"$error_text\" },\n"
+@@ -203,8 +203,15 @@
+ ${$old_define} = $define_name;
}
+
+- ${$code_check} .= "${white_space}case -($error_name):\n".
+- "${white_space} return( \"$module_name - $description\" );\n"
++ if ($error_name eq "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE")
++ {
++ # no-op, this case is hard-coded in error.fmt
++ }
++ else
++ {
++ my $error_text = $error_name =~ s/^MBEDTLS_ERR_//r;
++ ${$code_check} .= "${white_space}{ -($error_name), \"$error_text\" },\n"
++ }
};
+ if ($ll_old_define ne "")
diff --git a/lib/mbedtls_errors/mp_mbedtls_errors.c b/lib/mbedtls_errors/mp_mbedtls_errors.c
index 03a91f0dc949..fabbb15e4eb6 100644
--- a/lib/mbedtls_errors/mp_mbedtls_errors.c
+++ b/lib/mbedtls_errors/mp_mbedtls_errors.c
@@ -53,6 +53,10 @@
#include "mbedtls/aria.h"
#endif
+#if defined(MBEDTLS_ASN1_PARSE_C)
+#include "mbedtls/asn1.h"
+#endif
+
#if defined(MBEDTLS_BASE64_C)
#include "mbedtls/base64.h"
#endif
@@ -109,6 +113,10 @@
#include "mbedtls/entropy.h"
#endif
+#if defined(MBEDTLS_ERROR_C)
+#include "mbedtls/error.h"
+#endif
+
#if defined(MBEDTLS_GCM_C)
#include "mbedtls/gcm.h"
#endif
@@ -377,7 +385,10 @@ static const struct ssl_errs mbedtls_high_level_error_tab[] = {
{ -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING), "SSL_CONTINUE_PROCESSING" },
{ -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS), "SSL_ASYNC_IN_PROGRESS" },
{ -(MBEDTLS_ERR_SSL_EARLY_MESSAGE), "SSL_EARLY_MESSAGE" },
+ { -(MBEDTLS_ERR_SSL_UNEXPECTED_CID), "SSL_UNEXPECTED_CID" },
+ { -(MBEDTLS_ERR_SSL_VERSION_MISMATCH), "SSL_VERSION_MISMATCH" },
{ -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS), "SSL_CRYPTO_IN_PROGRESS" },
+ { -(MBEDTLS_ERR_SSL_BAD_CONFIG), "SSL_BAD_CONFIG" },
#endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
@@ -507,6 +518,11 @@ static const struct ssl_errs mbedtls_low_level_error_tab[] = {
{ -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR), "ENTROPY_FILE_IO_ERROR" },
#endif /* MBEDTLS_ENTROPY_C */
+#if defined(MBEDTLS_ERROR_C)
+ { -(MBEDTLS_ERR_ERROR_GENERIC_ERROR), "ERROR_GENERIC_ERROR" },
+ { -(MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED), "ERROR_CORRUPTION_DETECTED" },
+#endif /* MBEDTLS_ERROR_C */
+
#if defined(MBEDTLS_GCM_C)
{ -(MBEDTLS_ERR_GCM_AUTH_FAILED), "GCM_AUTH_FAILED" },
{ -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED), "GCM_HW_ACCEL_FAILED" },
@@ -650,7 +666,7 @@ void mbedtls_strerror(int ret, char *buf, size_t buflen) {
if (got_hl) {
use_ret = ret & 0xFF80;
- // special case
+ // special case, don't try to translate low level code
#if defined(MBEDTLS_SSL_TLS_C)
if (use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)) {
strncpy(buf, "MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE", buflen);
diff --git a/lib/micropython-lib b/lib/micropython-lib
index d0f97fc218f0..c11361176527 160000
--- a/lib/micropython-lib
+++ b/lib/micropython-lib
@@ -1 +1 @@
-Subproject commit d0f97fc218f07c381c835d9f632904c1ae1c9d6b
+Subproject commit c113611765278b2fc8dcf8b2f2c3513b35a69b39
diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c
index 0c9d04fe746f..eca5b45bda11 100644
--- a/lib/oofatfs/ff.c
+++ b/lib/oofatfs/ff.c
@@ -2821,7 +2821,7 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not
if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */
lfn[di++] = wc; /* Store the Unicode character */
}
- while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */
+ if (wc == '/' || wc == '\\') while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */
*path = p; /* Return pointer to the next segment */
cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
diff --git a/lib/pico-sdk b/lib/pico-sdk
index 2e6142b15b8a..6a7db34ff633 160000
--- a/lib/pico-sdk
+++ b/lib/pico-sdk
@@ -1 +1 @@
-Subproject commit 2e6142b15b8a75c1227dd3edbe839193b2bf9041
+Subproject commit 6a7db34ff63345a7badec79ebea3aaef1712f374
diff --git a/lib/re1.5/charclass.c b/lib/re1.5/charclass.c
index 7f6388c93d29..2553b40530c9 100644
--- a/lib/re1.5/charclass.c
+++ b/lib/re1.5/charclass.c
@@ -6,7 +6,15 @@ int _re1_5_classmatch(const char *pc, const char *sp)
int is_positive = (pc[-1] == Class);
int cnt = *pc++;
while (cnt--) {
- if (*sp >= *pc && *sp <= pc[1]) return is_positive;
+ if (*pc == RE15_CLASS_NAMED_CLASS_INDICATOR) {
+ if (_re1_5_namedclassmatch(pc + 1, sp)) {
+ return is_positive;
+ }
+ } else {
+ if (*sp >= *pc && *sp <= pc[1]) {
+ return is_positive;
+ }
+ }
pc += 2;
}
return !is_positive;
diff --git a/lib/re1.5/compilecode.c b/lib/re1.5/compilecode.c
index add4f6ac2085..513a155970ac 100644
--- a/lib/re1.5/compilecode.c
+++ b/lib/re1.5/compilecode.c
@@ -4,6 +4,9 @@
#include "re1.5.h"
+// Matches: DSWdsw
+#define MATCH_NAMED_CLASS_CHAR(c) (((c) | 0x20) == 'd' || ((c) | 0x24) == 'w')
+
#define INSERT_CODE(at, num, pc) \
((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num)
#define REL(at, to) (to - at - 2)
@@ -31,7 +34,7 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
case '\\':
re++;
if (!*re) return NULL; // Trailing backslash
- if ((*re | 0x20) == 'd' || (*re | 0x20) == 's' || (*re | 0x20) == 'w') {
+ if (MATCH_NAMED_CLASS_CHAR(*re)) {
term = PC;
EMIT(PC++, NamedClass);
EMIT(PC++, *re);
@@ -63,14 +66,21 @@ static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
PC++; // Skip # of pair byte
prog->len++;
for (cnt = 0; *re != ']'; re++, cnt++) {
- if (*re == '\\') {
+ char c = *re;
+ if (c == '\\') {
++re;
+ c = *re;
+ if (MATCH_NAMED_CLASS_CHAR(c)) {
+ c = RE15_CLASS_NAMED_CLASS_INDICATOR;
+ goto emit_char_pair;
+ }
}
- if (!*re) return NULL;
- EMIT(PC++, *re);
+ if (!c) return NULL;
if (re[1] == '-' && re[2] != ']') {
re += 2;
}
+ emit_char_pair:
+ EMIT(PC++, c);
EMIT(PC++, *re);
}
EMIT_CHECKED(term + 1, cnt);
diff --git a/lib/re1.5/re1.5.h b/lib/re1.5/re1.5.h
index 81f43ed7f5fd..b1ec01cbc586 100644
--- a/lib/re1.5/re1.5.h
+++ b/lib/re1.5/re1.5.h
@@ -138,6 +138,7 @@ struct Subject {
#define NON_ANCHORED_PREFIX 5
#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode))
+#define RE15_CLASS_NAMED_CLASS_INDICATOR 0
int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int);
int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int);
diff --git a/lib/stm32lib b/lib/stm32lib
index a9f8fee7bb0c..928df866e4d2 160000
--- a/lib/stm32lib
+++ b/lib/stm32lib
@@ -1 +1 @@
-Subproject commit a9f8fee7bb0cb4ac1b4ff719b6b5b285f613f352
+Subproject commit 928df866e4d287ebc3c60726151513ebee609128
diff --git a/lib/uzlib/adler32.c b/lib/uzlib/adler32.c
index 1f1759493bba..65fe1181b860 100644
--- a/lib/uzlib/adler32.c
+++ b/lib/uzlib/adler32.c
@@ -36,7 +36,7 @@
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
*/
-#include "tinf.h"
+#include "uzlib.h"
#define A32_BASE 65521
#define A32_NMAX 5552
diff --git a/lib/uzlib/crc32.c b/lib/uzlib/crc32.c
index e24c643b6acf..1e3b1756b383 100644
--- a/lib/uzlib/crc32.c
+++ b/lib/uzlib/crc32.c
@@ -36,7 +36,7 @@
* Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
*/
-#include "tinf.h"
+#include "uzlib.h"
static const unsigned int tinf_crc32tab[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190,
diff --git a/lib/uzlib/defl_static.c b/lib/uzlib/defl_static.c
new file mode 100644
index 000000000000..208e9ea5d2a5
--- /dev/null
+++ b/lib/uzlib/defl_static.c
@@ -0,0 +1,181 @@
+/*
+
+Routines in this file are based on:
+Zlib (RFC1950 / RFC1951) compression for PuTTY.
+
+PuTTY is copyright 1997-2014 Simon Tatham.
+
+Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
+Kuhn, Colin Watson, and CORE SDI S.A.
+
+Optimised for MicroPython:
+Copyright (c) 2023 by Jim Mussared
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include
+#include
+#include
+#include
+
+/* ----------------------------------------------------------------------
+ * Zlib compression. We always use the static Huffman tree option.
+ * Mostly this is because it's hard to scan a block in advance to
+ * work out better trees; dynamic trees are great when you're
+ * compressing a large file under no significant time constraint,
+ * but when you're compressing little bits in real time, things get
+ * hairier.
+ *
+ * I suppose it's possible that I could compute Huffman trees based
+ * on the frequencies in the _previous_ block, as a sort of
+ * heuristic, but I'm not confident that the gain would balance out
+ * having to transmit the trees.
+ */
+
+static void outbits(uzlib_lz77_state_t *state, unsigned long bits, int nbits)
+{
+ assert(state->noutbits + nbits <= 32);
+ state->outbits |= bits << state->noutbits;
+ state->noutbits += nbits;
+ while (state->noutbits >= 8) {
+ state->dest_write_cb(state->dest_write_data, state->outbits & 0xFF);
+ state->outbits >>= 8;
+ state->noutbits -= 8;
+ }
+}
+
+static const unsigned char mirrornibbles[16] = {
+ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
+};
+
+static unsigned int mirrorbyte(unsigned int b) {
+ return mirrornibbles[b & 0xf] << 4 | mirrornibbles[b >> 4];
+}
+
+static int int_log2(int x) {
+ int r = 0;
+ while (x >>= 1) {
+ ++r;
+ }
+ return r;
+}
+
+static void uzlib_literal(uzlib_lz77_state_t *state, unsigned char c)
+{
+ if (c <= 143) {
+ /* 0 through 143 are 8 bits long starting at 00110000. */
+ outbits(state, mirrorbyte(0x30 + c), 8);
+ } else {
+ /* 144 through 255 are 9 bits long starting at 110010000. */
+ outbits(state, 1 + 2 * mirrorbyte(0x90 - 144 + c), 9);
+ }
+}
+
+static void uzlib_match(uzlib_lz77_state_t *state, int distance, int len)
+{
+ assert(distance >= 1 && distance <= 32768);
+ distance -= 1;
+
+ while (len > 0) {
+ int thislen;
+
+ /*
+ * We can transmit matches of lengths 3 through 258
+ * inclusive. So if len exceeds 258, we must transmit in
+ * several steps, with 258 or less in each step.
+ *
+ * Specifically: if len >= 261, we can transmit 258 and be
+ * sure of having at least 3 left for the next step. And if
+ * len <= 258, we can just transmit len. But if len == 259
+ * or 260, we must transmit len-3.
+ */
+ thislen = (len > 260 ? 258 : len <= 258 ? len : len - 3);
+ len -= thislen;
+
+ assert(thislen >= 3 && thislen <= 258);
+
+ thislen -= 3;
+ int lcode = 28;
+ int x = int_log2(thislen);
+ int y;
+ if (thislen < 255) {
+ if (x) {
+ --x;
+ }
+ y = (thislen >> (x ? x - 1 : 0)) & 3;
+ lcode = x * 4 + y;
+ }
+
+ /*
+ * Transmit the length code. 256-279 are seven bits
+ * starting at 0000000; 280-287 are eight bits starting at
+ * 11000000.
+ */
+ if (lcode <= 22) {
+ outbits(state, mirrorbyte((lcode + 1) * 2), 7);
+ } else {
+ outbits(state, mirrorbyte(lcode + 169), 8);
+ }
+
+ /*
+ * Transmit the extra bits.
+ */
+ if (thislen < 255 && x > 1) {
+ int extrabits = x - 1;
+ int lmin = (thislen >> extrabits) << extrabits;
+ outbits(state, thislen - lmin, extrabits);
+ }
+
+ x = int_log2(distance);
+ y = (distance >> (x ? x - 1 : 0)) & 1;
+
+ /*
+ * Transmit the distance code. Five bits starting at 00000.
+ */
+ outbits(state, mirrorbyte((x * 2 + y) * 8), 5);
+
+ /*
+ * Transmit the extra bits.
+ */
+ if (x > 1) {
+ int dextrabits = x - 1;
+ int dmin = (distance >> dextrabits) << dextrabits;
+ outbits(state, distance - dmin, dextrabits);
+ }
+ }
+}
+
+void uzlib_start_block(uzlib_lz77_state_t *state)
+{
+ // Final block (0b1)
+ // Static huffman block (0b01)
+ outbits(state, 3, 3);
+}
+
+void uzlib_finish_block(uzlib_lz77_state_t *state)
+{
+ // Close block (0b0000000)
+ // Make sure all bits are flushed (0b0000000)
+ outbits(state, 0, 14);
+}
diff --git a/lib/uzlib/defl_static.h b/lib/uzlib/defl_static.h
deleted file mode 100644
index 292734d77324..000000000000
--- a/lib/uzlib/defl_static.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) uzlib authors
- *
- * This software is provided 'as-is', without any express
- * or implied warranty. In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- * misrepresented; you must not claim that you
- * wrote the original software. If you use this
- * software in a product, an acknowledgment in
- * the product documentation would be appreciated
- * but is not required.
- *
- * 2. Altered source versions must be plainly marked
- * as such, and must not be misrepresented as
- * being the original software.
- *
- * 3. This notice may not be removed or altered from
- * any source distribution.
- */
-
-/* This files contains type declaration and prototypes for defl_static.c.
- They may be altered/distinct from the originals used in PuTTY source
- code. */
-
-struct Outbuf {
- unsigned char *outbuf;
- int outlen, outsize;
- unsigned long outbits;
- int noutbits;
- int comp_disabled;
-};
-
-void outbits(struct Outbuf *out, unsigned long bits, int nbits);
-void zlib_start_block(struct Outbuf *ctx);
-void zlib_finish_block(struct Outbuf *ctx);
-void zlib_literal(struct Outbuf *ectx, unsigned char c);
-void zlib_match(struct Outbuf *ectx, int distance, int len);
diff --git a/lib/uzlib/header.c b/lib/uzlib/header.c
new file mode 100644
index 000000000000..edd2b08ab5a4
--- /dev/null
+++ b/lib/uzlib/header.c
@@ -0,0 +1,133 @@
+/*
+ * uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
+ *
+ * Copyright (c) 2003 by Joergen Ibsen / Jibz
+ * All Rights Reserved
+ *
+ * http://www.ibsensoftware.com/
+ *
+ * Copyright (c) 2014-2018 by Paul Sokolovsky
+ *
+ * Optimised for MicroPython:
+ * Copyright (c) 2023 by Jim Mussared
+ *
+ * This software is provided 'as-is', without any express
+ * or implied warranty. In no event will the authors be
+ * held liable for any damages arising from the use of
+ * this software.
+ *
+ * Permission is granted to anyone to use this software
+ * for any purpose, including commercial applications,
+ * and to alter it and redistribute it freely, subject to
+ * the following restrictions:
+ *
+ * 1. The origin of this software must not be
+ * misrepresented; you must not claim that you
+ * wrote the original software. If you use this
+ * software in a product, an acknowledgment in
+ * the product documentation would be appreciated
+ * but is not required.
+ *
+ * 2. Altered source versions must be plainly marked
+ * as such, and must not be misrepresented as
+ * being the original software.
+ *
+ * 3. This notice may not be removed or altered from
+ * any source distribution.
+ */
+
+#include "uzlib.h"
+
+#define FTEXT 1
+#define FHCRC 2
+#define FEXTRA 4
+#define FNAME 8
+#define FCOMMENT 16
+
+void tinf_skip_bytes(uzlib_uncomp_t *d, int num);
+uint16_t tinf_get_uint16(uzlib_uncomp_t *d);
+
+void tinf_skip_bytes(uzlib_uncomp_t *d, int num)
+{
+ while (num--) uzlib_get_byte(d);
+}
+
+uint16_t tinf_get_uint16(uzlib_uncomp_t *d)
+{
+ unsigned int v = uzlib_get_byte(d);
+ v = (uzlib_get_byte(d) << 8) | v;
+ return v;
+}
+
+int uzlib_parse_zlib_gzip_header(uzlib_uncomp_t *d, int *wbits)
+{
+ /* -- check format -- */
+ unsigned char cmf = uzlib_get_byte(d);
+ unsigned char flg = uzlib_get_byte(d);
+
+ /* check for gzip id bytes */
+ if (cmf == 0x1f && flg == 0x8b) {
+ /* check method is deflate */
+ if (uzlib_get_byte(d) != 8) return UZLIB_DATA_ERROR;
+
+ /* get flag byte */
+ flg = uzlib_get_byte(d);
+
+ /* check that reserved bits are zero */
+ if (flg & 0xe0) return UZLIB_DATA_ERROR;
+
+ /* -- find start of compressed data -- */
+
+ /* skip rest of base header of 10 bytes */
+ tinf_skip_bytes(d, 6);
+
+ /* skip extra data if present */
+ if (flg & FEXTRA)
+ {
+ unsigned int xlen = tinf_get_uint16(d);
+ tinf_skip_bytes(d, xlen);
+ }
+
+ /* skip file name if present */
+ if (flg & FNAME) { while (uzlib_get_byte(d)); }
+
+ /* skip file comment if present */
+ if (flg & FCOMMENT) { while (uzlib_get_byte(d)); }
+
+ /* check header crc if present */
+ if (flg & FHCRC)
+ {
+ /*unsigned int hcrc =*/ tinf_get_uint16(d);
+
+ // TODO: Check!
+ // if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff))
+ // return UZLIB_DATA_ERROR;
+ }
+
+ /* initialize for crc32 checksum */
+ d->checksum_type = UZLIB_CHKSUM_CRC;
+ d->checksum = ~0;
+
+ return UZLIB_HEADER_GZIP;
+ } else {
+ /* check checksum */
+ if ((256*cmf + flg) % 31) return UZLIB_DATA_ERROR;
+
+ /* check method is deflate */
+ if ((cmf & 0x0f) != 8) return UZLIB_DATA_ERROR;
+
+ /* check window size is valid */
+ if ((cmf >> 4) > 7) return UZLIB_DATA_ERROR;
+
+ /* check there is no preset dictionary */
+ if (flg & 0x20) return UZLIB_DATA_ERROR;
+
+ /* initialize for adler32 checksum */
+ d->checksum_type = UZLIB_CHKSUM_ADLER;
+ d->checksum = 1;
+
+ *wbits = (cmf >> 4) + 8;
+
+ return UZLIB_HEADER_ZLIB;
+ }
+}
diff --git a/lib/uzlib/lz77.c b/lib/uzlib/lz77.c
new file mode 100644
index 000000000000..117ce50f70f2
--- /dev/null
+++ b/lib/uzlib/lz77.c
@@ -0,0 +1,87 @@
+/*
+ * Simple LZ77 streaming compressor.
+ *
+ * The scheme implemented here doesn't use a hash table and instead does a brute
+ * force search in the history for a previous string. It is relatively slow
+ * (but still O(N)) but gives good compression and minimal memory usage. For a
+ * small history window (eg 256 bytes) it's not too slow and compresses well.
+ *
+ * MIT license; Copyright (c) 2021 Damien P. George
+ */
+
+#include "uzlib.h"
+
+#include "defl_static.c"
+
+#define MATCH_LEN_MIN (3)
+#define MATCH_LEN_MAX (258)
+
+// hist should be a preallocated buffer of hist_max size bytes.
+// hist_max should be greater than 0 a power of 2 (ie 1, 2, 4, 8, ...).
+// It's possible to pass in hist=NULL, and then the history window will be taken from the
+// src passed in to uzlib_lz77_compress (this is useful when not doing streaming compression).
+void uzlib_lz77_init(uzlib_lz77_state_t *state, uint8_t *hist, size_t hist_max) {
+ memset(state, 0, sizeof(uzlib_lz77_state_t));
+ state->hist_buf = hist;
+ state->hist_max = hist_max;
+ state->hist_start = 0;
+ state->hist_len = 0;
+}
+
+// Push the given byte to the history.
+// Search back in the history for the maximum match of the given src data,
+// with support for searching beyond the end of the history and into the src buffer
+// (effectively the history and src buffer are concatenated).
+static size_t uzlib_lz77_search_max_match(uzlib_lz77_state_t *state, const uint8_t *src, size_t len, size_t *longest_offset) {
+ size_t longest_len = 0;
+ for (size_t hist_search = 0; hist_search < state->hist_len; ++hist_search) {
+ size_t match_len;
+ for (match_len = 0; match_len <= MATCH_LEN_MAX && match_len < len; ++match_len) {
+ uint8_t hist;
+ if (hist_search + match_len < state->hist_len) {
+ hist = state->hist_buf[(state->hist_start + hist_search + match_len) & (state->hist_max - 1)];
+ } else {
+ hist = src[hist_search + match_len - state->hist_len];
+ }
+ if (src[match_len] != hist) {
+ break;
+ }
+ }
+ if (match_len >= MATCH_LEN_MIN && match_len > longest_len) {
+ longest_len = match_len;
+ *longest_offset = state->hist_len - hist_search;
+ }
+ }
+
+ return longest_len;
+}
+
+// Compress the given chunk of data.
+void uzlib_lz77_compress(uzlib_lz77_state_t *state, const uint8_t *src, unsigned len) {
+ const uint8_t *top = src + len;
+ while (src < top) {
+ // Look for a match in the history window.
+ size_t match_offset = 0;
+ size_t match_len = uzlib_lz77_search_max_match(state, src, top - src, &match_offset);
+
+ // Encode the literal byte or the match.
+ if (match_len == 0) {
+ uzlib_literal(state, *src);
+ match_len = 1;
+ } else {
+ uzlib_match(state, match_offset, match_len);
+ }
+
+ // Push the bytes into the history buffer.
+ size_t mask = state->hist_max - 1;
+ while (match_len--) {
+ uint8_t b = *src++;
+ state->hist_buf[(state->hist_start + state->hist_len) & mask] = b;
+ if (state->hist_len == state->hist_max) {
+ state->hist_start = (state->hist_start + 1) & mask;
+ } else {
+ ++state->hist_len;
+ }
+ }
+ }
+}
diff --git a/lib/uzlib/tinf.h b/lib/uzlib/tinf.h
deleted file mode 100644
index ae6e1c4073eb..000000000000
--- a/lib/uzlib/tinf.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* Compatibility header for the original tinf lib/older versions of uzlib.
- Note: may be removed in the future, please migrate to uzlib.h. */
-#include "uzlib.h"
diff --git a/lib/uzlib/tinf_compat.h b/lib/uzlib/tinf_compat.h
deleted file mode 100644
index f763804bd94b..000000000000
--- a/lib/uzlib/tinf_compat.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* This header contains compatibility defines for the original tinf API
- and uzlib 2.x and below API. These defines are deprecated and going
- to be removed in the future, so applications should migrate to new
- uzlib API. */
-#define TINF_DATA struct uzlib_uncomp
-
-#define destSize dest_size
-#define destStart dest_start
-#define readSource source_read_cb
diff --git a/lib/uzlib/tinfgzip.c b/lib/uzlib/tinfgzip.c
deleted file mode 100644
index 22b000df9aa2..000000000000
--- a/lib/uzlib/tinfgzip.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
- *
- * Copyright (c) 2003 by Joergen Ibsen / Jibz
- * All Rights Reserved
- *
- * http://www.ibsensoftware.com/
- *
- * Copyright (c) 2014-2018 by Paul Sokolovsky
- *
- * This software is provided 'as-is', without any express
- * or implied warranty. In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- * misrepresented; you must not claim that you
- * wrote the original software. If you use this
- * software in a product, an acknowledgment in
- * the product documentation would be appreciated
- * but is not required.
- *
- * 2. Altered source versions must be plainly marked
- * as such, and must not be misrepresented as
- * being the original software.
- *
- * 3. This notice may not be removed or altered from
- * any source distribution.
- */
-
-#include "tinf.h"
-
-#define FTEXT 1
-#define FHCRC 2
-#define FEXTRA 4
-#define FNAME 8
-#define FCOMMENT 16
-
-void tinf_skip_bytes(TINF_DATA *d, int num);
-uint16_t tinf_get_uint16(TINF_DATA *d);
-
-void tinf_skip_bytes(TINF_DATA *d, int num)
-{
- while (num--) uzlib_get_byte(d);
-}
-
-uint16_t tinf_get_uint16(TINF_DATA *d)
-{
- unsigned int v = uzlib_get_byte(d);
- v = (uzlib_get_byte(d) << 8) | v;
- return v;
-}
-
-int uzlib_gzip_parse_header(TINF_DATA *d)
-{
- unsigned char flg;
-
- /* -- check format -- */
-
- /* check id bytes */
- if (uzlib_get_byte(d) != 0x1f || uzlib_get_byte(d) != 0x8b) return TINF_DATA_ERROR;
-
- /* check method is deflate */
- if (uzlib_get_byte(d) != 8) return TINF_DATA_ERROR;
-
- /* get flag byte */
- flg = uzlib_get_byte(d);
-
- /* check that reserved bits are zero */
- if (flg & 0xe0) return TINF_DATA_ERROR;
-
- /* -- find start of compressed data -- */
-
- /* skip rest of base header of 10 bytes */
- tinf_skip_bytes(d, 6);
-
- /* skip extra data if present */
- if (flg & FEXTRA)
- {
- unsigned int xlen = tinf_get_uint16(d);
- tinf_skip_bytes(d, xlen);
- }
-
- /* skip file name if present */
- if (flg & FNAME) { while (uzlib_get_byte(d)); }
-
- /* skip file comment if present */
- if (flg & FCOMMENT) { while (uzlib_get_byte(d)); }
-
- /* check header crc if present */
- if (flg & FHCRC)
- {
- /*unsigned int hcrc =*/ tinf_get_uint16(d);
-
- // TODO: Check!
-// if (hcrc != (tinf_crc32(src, start - src) & 0x0000ffff))
-// return TINF_DATA_ERROR;
- }
-
- /* initialize for crc32 checksum */
- d->checksum_type = TINF_CHKSUM_CRC;
- d->checksum = ~0;
-
- return TINF_OK;
-}
diff --git a/lib/uzlib/tinflate.c b/lib/uzlib/tinflate.c
index 045952c7553a..53536272f329 100644
--- a/lib/uzlib/tinflate.c
+++ b/lib/uzlib/tinflate.c
@@ -7,6 +7,9 @@
*
* Copyright (c) 2014-2018 by Paul Sokolovsky
*
+ * Optimised for MicroPython:
+ * Copyright (c) 2023 by Jim Mussared
+ *
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
@@ -33,7 +36,7 @@
*/
#include
-#include "tinf.h"
+#include "uzlib.h"
#define UZLIB_DUMP_ARRAY(heading, arr, size) \
{ \
@@ -44,52 +47,52 @@
printf("\n"); \
}
-uint32_t tinf_get_le_uint32(TINF_DATA *d);
-uint32_t tinf_get_be_uint32(TINF_DATA *d);
+uint32_t tinf_get_le_uint32(uzlib_uncomp_t *d);
+uint32_t tinf_get_be_uint32(uzlib_uncomp_t *d);
/* --------------------------------------------------- *
* -- uninitialized global data (static structures) -- *
* --------------------------------------------------- */
-#ifdef RUNTIME_BITS_TABLES
-
-/* extra bits and base tables for length codes */
-unsigned char length_bits[30];
-unsigned short length_base[30];
-
-/* extra bits and base tables for distance codes */
-unsigned char dist_bits[30];
-unsigned short dist_base[30];
-
-#else
-
-const unsigned char length_bits[30] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4,
- 5, 5, 5, 5
+typedef struct {
+ unsigned char length_bits : 3;
+ unsigned short length_base : 9;
+ unsigned char dist_bits : 4;
+ unsigned short dist_base : 15;
+} lookup_table_entry_t;
+
+const lookup_table_entry_t lookup_table[30] = {
+ {0, 3, 0, 1},
+ {0, 4, 0, 2},
+ {0, 5, 0, 3},
+ {0, 6, 0, 4},
+ {0, 7, 1, 5},
+ {0, 8, 1, 7},
+ {0, 9, 2, 9},
+ {0, 10, 2, 13},
+ {1, 11, 3, 17},
+ {1, 13, 3, 25},
+ {1, 15, 4, 33},
+ {1, 17, 4, 49},
+ {2, 19, 5, 65},
+ {2, 23, 5, 97},
+ {2, 27, 6, 129},
+ {2, 31, 6, 193},
+ {3, 35, 7, 257},
+ {3, 43, 7, 385},
+ {3, 51, 8, 513},
+ {3, 59, 8, 769},
+ {4, 67, 9, 1025},
+ {4, 83, 9, 1537},
+ {4, 99, 10, 2049},
+ {4, 115, 10, 3073},
+ {5, 131, 11, 4097},
+ {5, 163, 11, 6145},
+ {5, 195, 12, 8193},
+ {5, 227, 12, 12289},
+ {0, 258, 13, 16385},
+ {0, 0, 13, 24577},
};
-const unsigned short length_base[30] = {
- 3, 4, 5, 6, 7, 8, 9, 10,
- 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115,
- 131, 163, 195, 227, 258
-};
-
-const unsigned char dist_bits[30] = {
- 0, 0, 0, 0, 1, 1, 2, 2,
- 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10,
- 11, 11, 12, 12, 13, 13
-};
-const unsigned short dist_base[30] = {
- 1, 2, 3, 4, 5, 7, 9, 13,
- 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073,
- 4097, 6145, 8193, 12289, 16385, 24577
-};
-
-#endif
/* special ordering of code length codes */
const unsigned char clcidx[] = {
@@ -102,25 +105,6 @@ const unsigned char clcidx[] = {
* -- utility functions -- *
* ----------------------- */
-#ifdef RUNTIME_BITS_TABLES
-/* build extra bits and base tables */
-static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first)
-{
- int i, sum;
-
- /* build bits table */
- for (i = 0; i < delta; ++i) bits[i] = 0;
- for (i = 0; i < 30 - delta; ++i) bits[i + delta] = i / delta;
-
- /* build base table */
- for (sum = first, i = 0; i < 30; ++i)
- {
- base[i] = sum;
- sum += 1 << bits[i];
- }
-}
-#endif
-
/* build the fixed huffman trees */
static void tinf_build_fixed_trees(TINF_TREE *lt, TINF_TREE *dt)
{
@@ -189,7 +173,7 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned
* -- decode functions -- *
* ---------------------- */
-unsigned char uzlib_get_byte(TINF_DATA *d)
+unsigned char uzlib_get_byte(uzlib_uncomp_t *d)
{
/* If end of source buffer is not reached, return next byte from source
buffer. */
@@ -200,14 +184,14 @@ unsigned char uzlib_get_byte(TINF_DATA *d)
/* Otherwise if there's callback and we haven't seen EOF yet, try to
read next byte using it. (Note: the callback can also update ->source
and ->source_limit). */
- if (d->readSource && !d->eof) {
- int val = d->readSource(d);
+ if (d->source_read_cb && !d->eof) {
+ int val = d->source_read_cb(d->source_read_data);
if (val >= 0) {
return (unsigned char)val;
}
}
- /* Otherwise, we hit EOF (either from ->readSource() or from exhaustion
+ /* Otherwise, we hit EOF (either from ->source_read_cb() or from exhaustion
of the buffer), and it will be "sticky", i.e. further calls to this
function will end up here too. */
d->eof = true;
@@ -215,7 +199,7 @@ unsigned char uzlib_get_byte(TINF_DATA *d)
return 0;
}
-uint32_t tinf_get_le_uint32(TINF_DATA *d)
+uint32_t tinf_get_le_uint32(uzlib_uncomp_t *d)
{
uint32_t val = 0;
int i;
@@ -225,7 +209,7 @@ uint32_t tinf_get_le_uint32(TINF_DATA *d)
return val;
}
-uint32_t tinf_get_be_uint32(TINF_DATA *d)
+uint32_t tinf_get_be_uint32(uzlib_uncomp_t *d)
{
uint32_t val = 0;
int i;
@@ -236,7 +220,7 @@ uint32_t tinf_get_be_uint32(TINF_DATA *d)
}
/* get one bit from source stream */
-static int tinf_getbit(TINF_DATA *d)
+static int tinf_getbit(uzlib_uncomp_t *d)
{
unsigned int bit;
@@ -256,7 +240,7 @@ static int tinf_getbit(TINF_DATA *d)
}
/* read a num bit value from a stream and add base */
-static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
+static unsigned int tinf_read_bits(uzlib_uncomp_t *d, int num, int base)
{
unsigned int val = 0;
@@ -274,7 +258,7 @@ static unsigned int tinf_read_bits(TINF_DATA *d, int num, int base)
}
/* given a data stream and a tree, decode a symbol */
-static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
+static int tinf_decode_symbol(uzlib_uncomp_t *d, TINF_TREE *t)
{
int sum = 0, cur = 0, len = 0;
@@ -284,7 +268,7 @@ static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
cur = 2*cur + tinf_getbit(d);
if (++len == TINF_ARRAY_SIZE(t->table)) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
sum += t->table[len];
@@ -295,7 +279,7 @@ static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
sum += cur;
#if UZLIB_CONF_PARANOID_CHECKS
if (sum < 0 || sum >= TINF_ARRAY_SIZE(t->trans)) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
#endif
@@ -303,7 +287,7 @@ static int tinf_decode_symbol(TINF_DATA *d, TINF_TREE *t)
}
/* given a data stream, decode dynamic trees from it */
-static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
+static int tinf_decode_trees(uzlib_uncomp_t *d, TINF_TREE *lt, TINF_TREE *dt)
{
/* code lengths for 288 literal/len symbols and 32 dist symbols */
unsigned char lengths[288+32];
@@ -348,7 +332,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
{
case 16:
/* copy previous code length 3-6 times (read 2 bits) */
- if (num == 0) return TINF_DATA_ERROR;
+ if (num == 0) return UZLIB_DATA_ERROR;
fill_value = lengths[num - 1];
lbits = 2;
break;
@@ -370,7 +354,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
/* special code length 16-18 are handled here */
length = tinf_read_bits(d, lbits, lbase);
- if (num + length > hlimit) return TINF_DATA_ERROR;
+ if (num + length > hlimit) return UZLIB_DATA_ERROR;
for (; length; --length)
{
lengths[num++] = fill_value;
@@ -387,7 +371,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
#if UZLIB_CONF_PARANOID_CHECKS
/* Check that there's "end of block" symbol */
if (lengths[256] == 0) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
#endif
@@ -395,7 +379,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
tinf_build_tree(lt, lengths, hlit);
tinf_build_tree(dt, lengths + hlit, hdist);
- return TINF_OK;
+ return UZLIB_OK;
}
/* ----------------------------- *
@@ -403,7 +387,7 @@ static int tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
* ----------------------------- */
/* given a stream and two trees, inflate next byte of output */
-static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
+static int tinf_inflate_block_data(uzlib_uncomp_t *d, TINF_TREE *lt, TINF_TREE *dt)
{
if (d->curlen == 0) {
unsigned int offs;
@@ -412,41 +396,41 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
//printf("huff sym: %02x\n", sym);
if (d->eof) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
/* literal byte */
if (sym < 256) {
TINF_PUT(d, sym);
- return TINF_OK;
+ return UZLIB_OK;
}
/* end of block */
if (sym == 256) {
- return TINF_DONE;
+ return UZLIB_DONE;
}
/* substring from sliding dictionary */
sym -= 257;
if (sym >= 29) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
/* possibly get more bits from length code */
- d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]);
+ d->curlen = tinf_read_bits(d, lookup_table[sym].length_bits, lookup_table[sym].length_base);
dist = tinf_decode_symbol(d, dt);
if (dist >= 30) {
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
/* possibly get more bits from distance code */
- offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]);
+ offs = tinf_read_bits(d, lookup_table[dist].dist_bits, lookup_table[dist].dist_base);
/* calculate and validate actual LZ offset to use */
if (d->dict_ring) {
if (offs > d->dict_size) {
- return TINF_DICT_ERROR;
+ return UZLIB_DICT_ERROR;
}
/* Note: unlike full-dest-in-memory case below, we don't
try to catch offset which points to not yet filled
@@ -464,8 +448,8 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
}
} else {
/* catch trying to point before the start of dest buffer */
- if (offs > (unsigned int)(d->dest - d->destStart)) {
- return TINF_DATA_ERROR;
+ if (offs > (unsigned int)(d->dest - d->dest_start)) {
+ return UZLIB_DATA_ERROR;
}
d->lzOff = -offs;
}
@@ -482,11 +466,11 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt)
d->dest++;
}
d->curlen--;
- return TINF_OK;
+ return UZLIB_OK;
}
/* inflate next byte from uncompressed block of data */
-static int tinf_inflate_uncompressed_block(TINF_DATA *d)
+static int tinf_inflate_uncompressed_block(uzlib_uncomp_t *d)
{
if (d->curlen == 0) {
unsigned int length, invlength;
@@ -498,9 +482,9 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d)
invlength = uzlib_get_byte(d);
invlength += 256 * uzlib_get_byte(d);
/* check length */
- if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR;
+ if (length != (~invlength & 0x0000ffff)) return UZLIB_DATA_ERROR;
- /* increment length to properly return TINF_DONE below, without
+ /* increment length to properly return UZLIB_DONE below, without
producing data at the same time */
d->curlen = length + 1;
@@ -509,34 +493,20 @@ static int tinf_inflate_uncompressed_block(TINF_DATA *d)
}
if (--d->curlen == 0) {
- return TINF_DONE;
+ return UZLIB_DONE;
}
unsigned char c = uzlib_get_byte(d);
TINF_PUT(d, c);
- return TINF_OK;
+ return UZLIB_OK;
}
/* ---------------------- *
* -- public functions -- *
* ---------------------- */
-/* initialize global (static) data */
-void uzlib_init(void)
-{
-#ifdef RUNTIME_BITS_TABLES
- /* build extra bits and base tables */
- tinf_build_bits_base(length_bits, length_base, 4, 3);
- tinf_build_bits_base(dist_bits, dist_base, 2, 1);
-
- /* fix a special case */
- length_bits[28] = 0;
- length_base[28] = 258;
-#endif
-}
-
/* initialize decompression structure */
-void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen)
+void uzlib_uncompress_init(uzlib_uncomp_t *d, void *dict, unsigned int dictLen)
{
d->eof = 0;
d->bitcount = 0;
@@ -549,7 +519,7 @@ void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen)
}
/* inflate next output bytes from compressed stream */
-int uzlib_uncompress(TINF_DATA *d)
+int uzlib_uncompress(uzlib_uncomp_t *d)
{
do {
int res;
@@ -572,7 +542,7 @@ int uzlib_uncompress(TINF_DATA *d)
} else if (d->btype == 2) {
/* decode trees from stream */
res = tinf_decode_trees(d, &d->ltree, &d->dtree);
- if (res != TINF_OK) {
+ if (res != UZLIB_OK) {
return res;
}
}
@@ -592,27 +562,27 @@ int uzlib_uncompress(TINF_DATA *d)
res = tinf_inflate_block_data(d, &d->ltree, &d->dtree);
break;
default:
- return TINF_DATA_ERROR;
+ return UZLIB_DATA_ERROR;
}
- if (res == TINF_DONE && !d->bfinal) {
+ if (res == UZLIB_DONE && !d->bfinal) {
/* the block has ended (without producing more data), but we
can't return without data, so start procesing next block */
goto next_blk;
}
- if (res != TINF_OK) {
+ if (res != UZLIB_OK) {
return res;
}
} while (d->dest < d->dest_limit);
- return TINF_OK;
+ return UZLIB_OK;
}
/* inflate next output bytes from compressed stream, updating
checksum, and at the end of stream, verify it */
-int uzlib_uncompress_chksum(TINF_DATA *d)
+int uzlib_uncompress_chksum(uzlib_uncomp_t *d)
{
int res;
unsigned char *data = d->dest;
@@ -623,31 +593,31 @@ int uzlib_uncompress_chksum(TINF_DATA *d)
switch (d->checksum_type) {
- case TINF_CHKSUM_ADLER:
+ case UZLIB_CHKSUM_ADLER:
d->checksum = uzlib_adler32(data, d->dest - data, d->checksum);
break;
- case TINF_CHKSUM_CRC:
+ case UZLIB_CHKSUM_CRC:
d->checksum = uzlib_crc32(data, d->dest - data, d->checksum);
break;
}
- if (res == TINF_DONE) {
+ if (res == UZLIB_DONE) {
unsigned int val;
switch (d->checksum_type) {
- case TINF_CHKSUM_ADLER:
+ case UZLIB_CHKSUM_ADLER:
val = tinf_get_be_uint32(d);
if (d->checksum != val) {
- return TINF_CHKSUM_ERROR;
+ return UZLIB_CHKSUM_ERROR;
}
break;
- case TINF_CHKSUM_CRC:
+ case UZLIB_CHKSUM_CRC:
val = tinf_get_le_uint32(d);
if (~d->checksum != val) {
- return TINF_CHKSUM_ERROR;
+ return UZLIB_CHKSUM_ERROR;
}
// Uncompressed size. TODO: Check
val = tinf_get_le_uint32(d);
diff --git a/lib/uzlib/tinfzlib.c b/lib/uzlib/tinfzlib.c
deleted file mode 100644
index 5cb8852fcc4f..000000000000
--- a/lib/uzlib/tinfzlib.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * uzlib - tiny deflate/inflate library (deflate, gzip, zlib)
- *
- * Copyright (c) 2003 by Joergen Ibsen / Jibz
- * All Rights Reserved
- *
- * http://www.ibsensoftware.com/
- *
- * Copyright (c) 2014-2018 by Paul Sokolovsky
- *
- * This software is provided 'as-is', without any express
- * or implied warranty. In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- * misrepresented; you must not claim that you
- * wrote the original software. If you use this
- * software in a product, an acknowledgment in
- * the product documentation would be appreciated
- * but is not required.
- *
- * 2. Altered source versions must be plainly marked
- * as such, and must not be misrepresented as
- * being the original software.
- *
- * 3. This notice may not be removed or altered from
- * any source distribution.
- */
-
-#include "tinf.h"
-
-int uzlib_zlib_parse_header(TINF_DATA *d)
-{
- unsigned char cmf, flg;
-
- /* -- get header bytes -- */
-
- cmf = uzlib_get_byte(d);
- flg = uzlib_get_byte(d);
-
- /* -- check format -- */
-
- /* check checksum */
- if ((256*cmf + flg) % 31) return TINF_DATA_ERROR;
-
- /* check method is deflate */
- if ((cmf & 0x0f) != 8) return TINF_DATA_ERROR;
-
- /* check window size is valid */
- if ((cmf >> 4) > 7) return TINF_DATA_ERROR;
-
- /* check there is no preset dictionary */
- if (flg & 0x20) return TINF_DATA_ERROR;
-
- /* initialize for adler32 checksum */
- d->checksum_type = TINF_CHKSUM_ADLER;
- d->checksum = 1;
-
- return cmf >> 4;
-}
diff --git a/lib/uzlib/uzlib.h b/lib/uzlib/uzlib.h
index 3a4a1ad160da..16984a77d3eb 100644
--- a/lib/uzlib/uzlib.h
+++ b/lib/uzlib/uzlib.h
@@ -7,6 +7,9 @@
*
* Copyright (c) 2014-2018 by Paul Sokolovsky
*
+ * Optimised for MicroPython:
+ * Copyright (c) 2023 by Jim Mussared
+ *
* This software is provided 'as-is', without any express
* or implied warranty. In no event will the authors be
* held liable for any damages arising from the use of
@@ -39,38 +42,27 @@
#include
#include
-#include "defl_static.h"
-
#include "uzlib_conf.h"
#if UZLIB_CONF_DEBUG_LOG
#include
#endif
-/* calling convention */
-#ifndef TINFCC
- #ifdef __WATCOMC__
- #define TINFCC __cdecl
- #else
- #define TINFCC
- #endif
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
/* ok status, more data produced */
-#define TINF_OK 0
+#define UZLIB_OK 0
/* end of compressed stream reached */
-#define TINF_DONE 1
-#define TINF_DATA_ERROR (-3)
-#define TINF_CHKSUM_ERROR (-4)
-#define TINF_DICT_ERROR (-5)
+#define UZLIB_DONE 1
+#define UZLIB_DATA_ERROR (-3)
+#define UZLIB_CHKSUM_ERROR (-4)
+#define UZLIB_DICT_ERROR (-5)
/* checksum types */
-#define TINF_CHKSUM_NONE 0
-#define TINF_CHKSUM_ADLER 1
-#define TINF_CHKSUM_CRC 2
+#define UZLIB_CHKSUM_NONE 0
+#define UZLIB_CHKSUM_ADLER 1
+#define UZLIB_CHKSUM_CRC 2
/* helper macros */
#define TINF_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
@@ -82,7 +74,7 @@ typedef struct {
unsigned short trans[288]; /* code -> symbol translation table */
} TINF_TREE;
-struct uzlib_uncomp {
+typedef struct _uzlib_uncomp_t {
/* Pointer to the next byte in the input buffer */
const unsigned char *source;
/* Pointer to the next byte past the input buffer (source_limit = source + len) */
@@ -92,7 +84,8 @@ struct uzlib_uncomp {
also return -1 in case of EOF (or irrecoverable error). Note that
besides returning the next byte, it may also update source and
source_limit fields, thus allowing for buffered operation. */
- int (*source_read_cb)(struct uzlib_uncomp *uncomp);
+ void *source_read_data;
+ int (*source_read_cb)(void *);
unsigned int tag;
unsigned int bitcount;
@@ -119,9 +112,7 @@ struct uzlib_uncomp {
TINF_TREE ltree; /* dynamic length/symbol tree */
TINF_TREE dtree; /* dynamic distance tree */
-};
-
-#include "tinf_compat.h"
+} uzlib_uncomp_t;
#define TINF_PUT(d, c) \
{ \
@@ -129,38 +120,43 @@ struct uzlib_uncomp {
if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \
}
-unsigned char TINFCC uzlib_get_byte(TINF_DATA *d);
+unsigned char uzlib_get_byte(uzlib_uncomp_t *d);
/* Decompression API */
-void TINFCC uzlib_init(void);
-void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen);
-int TINFCC uzlib_uncompress(TINF_DATA *d);
-int TINFCC uzlib_uncompress_chksum(TINF_DATA *d);
+void uzlib_uncompress_init(uzlib_uncomp_t *d, void *dict, unsigned int dictLen);
+int uzlib_uncompress(uzlib_uncomp_t *d);
+int uzlib_uncompress_chksum(uzlib_uncomp_t *d);
-int TINFCC uzlib_zlib_parse_header(TINF_DATA *d);
-int TINFCC uzlib_gzip_parse_header(TINF_DATA *d);
+#define UZLIB_HEADER_ZLIB 0
+#define UZLIB_HEADER_GZIP 1
+int uzlib_parse_zlib_gzip_header(uzlib_uncomp_t *d, int *wbits);
/* Compression API */
-typedef const uint8_t *uzlib_hash_entry_t;
-
-struct uzlib_comp {
- struct Outbuf out;
-
- uzlib_hash_entry_t *hash_table;
- unsigned int hash_bits;
- unsigned int dict_size;
-};
-
-void TINFCC uzlib_compress(struct uzlib_comp *c, const uint8_t *src, unsigned slen);
+typedef struct {
+ void *dest_write_data;
+ void (*dest_write_cb)(void *data, uint8_t byte);
+ unsigned long outbits;
+ int noutbits;
+ uint8_t *hist_buf;
+ size_t hist_max;
+ size_t hist_start;
+ size_t hist_len;
+} uzlib_lz77_state_t;
+
+void uzlib_lz77_init(uzlib_lz77_state_t *state, uint8_t *hist, size_t hist_max);
+void uzlib_lz77_compress(uzlib_lz77_state_t *state, const uint8_t *src, unsigned len);
+
+void uzlib_start_block(uzlib_lz77_state_t *state);
+void uzlib_finish_block(uzlib_lz77_state_t *state);
/* Checksum API */
/* prev_sum is previous value for incremental computation, 1 initially */
-uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
+uint32_t uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum);
/* crc is previous value for incremental computation, 0xffffffff initially */
-uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
+uint32_t uzlib_crc32(const void *data, unsigned int length, uint32_t crc);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/mpy-cross/main.c b/mpy-cross/main.c
index 4975c8ddb205..3ef77d436f85 100644
--- a/mpy-cross/main.c
+++ b/mpy-cross/main.c
@@ -48,6 +48,14 @@ mp_uint_t mp_verbose_flag = 0;
// Make it larger on a 64 bit machine, because pointers are larger.
long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
+STATIC void stdout_print_strn(void *env, const char *str, size_t len) {
+ (void)env;
+ ssize_t dummy = write(STDOUT_FILENO, str, len);
+ (void)dummy;
+}
+
+STATIC const mp_print_t mp_stdout_print = {NULL, stdout_print_strn};
+
STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
(void)env;
ssize_t dummy = write(STDERR_FILENO, str, len);
@@ -59,7 +67,12 @@ STATIC const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
STATIC int compile_and_save(const char *file, const char *output_file, const char *source_file) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
- mp_lexer_t *lex = mp_lexer_new_from_file(file);
+ mp_lexer_t *lex;
+ if (strcmp(file, "-") == 0) {
+ lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, STDIN_FILENO, false);
+ } else {
+ lex = mp_lexer_new_from_file(file);
+ }
qstr source_name;
if (source_file == NULL) {
@@ -73,20 +86,27 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
#endif
mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
- mp_module_context_t *ctx = m_new_obj(mp_module_context_t);
- mp_compiled_module_t cm = mp_compile_to_raw_code(&parse_tree, source_name, false, ctx);
-
- vstr_t vstr;
- vstr_init(&vstr, 16);
- if (output_file == NULL) {
- vstr_add_str(&vstr, file);
- vstr_cut_tail_bytes(&vstr, 2);
- vstr_add_str(&vstr, "mpy");
+ mp_compiled_module_t cm;
+ cm.context = m_new_obj(mp_module_context_t);
+ mp_compile_to_raw_code(&parse_tree, source_name, false, &cm);
+
+ if ((output_file != NULL && strcmp(output_file, "-") == 0) ||
+ (output_file == NULL && strcmp(file, "-") == 0)) {
+ mp_raw_code_save(&cm, (mp_print_t *)&mp_stdout_print);
} else {
- vstr_add_str(&vstr, output_file);
+ vstr_t vstr;
+ vstr_init(&vstr, 16);
+ if (output_file == NULL) {
+ vstr_add_str(&vstr, file);
+ vstr_cut_tail_bytes(&vstr, 2);
+ vstr_add_str(&vstr, "mpy");
+ } else {
+ vstr_add_str(&vstr, output_file);
+ }
+
+ mp_raw_code_save_file(&cm, vstr_null_terminated_str(&vstr));
+ vstr_clear(&vstr);
}
- mp_raw_code_save_file(&cm, vstr_null_terminated_str(&vstr));
- vstr_clear(&vstr);
nlr_pop();
return 0;
@@ -99,10 +119,10 @@ STATIC int compile_and_save(const char *file, const char *output_file, const cha
STATIC int usage(char **argv) {
printf(
- "usage: %s [] [-X ] \n"
+ "usage: %s [] [-X ] [--] \n"
"Options:\n"
"--version : show version information\n"
- "-o : output file for compiled bytecode (defaults to input with .mpy extension)\n"
+ "-o : output file for compiled bytecode (defaults to input filename with .mpy extension, or stdout if input is stdin)\n"
"-s : source filename to embed in the compiled bytecode (defaults to input file)\n"
"-v : verbose (trace various operations); can be multiple\n"
"-O[N] : apply bytecode optimizations of level N\n"
@@ -181,6 +201,15 @@ STATIC void pre_process_options(int argc, char **argv) {
}
}
+STATIC char *backslash_to_forwardslash(char *path) {
+ for (char *p = path; p != NULL && *p != '\0'; ++p) {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ }
+ return path;
+}
+
MP_NOINLINE int main_(int argc, char **argv) {
mp_stack_set_limit(40000 * (sizeof(void *) / 4));
@@ -203,27 +232,18 @@ MP_NOINLINE int main_(int argc, char **argv) {
// set default compiler configuration
mp_dynamic_compiler.small_int_bits = 31;
- #if defined(__i386__)
- mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
- mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
- #elif defined(__x86_64__)
- mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
- mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
- #elif defined(__arm__) && !defined(__thumb2__)
- mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
- mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
- #else
+ // don't support native emitter unless -march is specified
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE;
mp_dynamic_compiler.nlr_buf_num_regs = 0;
- #endif
const char *input_file = NULL;
const char *output_file = NULL;
const char *source_file = NULL;
+ bool option_parsing_active = true;
// parse main options
for (int a = 1; a < argc; a++) {
- if (argv[a][0] == '-') {
+ if (option_parsing_active && argv[a][0] == '-' && argv[a][1] != '\0') {
if (strcmp(argv[a], "-X") == 0) {
a += 1;
} else if (strcmp(argv[a], "--version") == 0) {
@@ -251,7 +271,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
exit(usage(argv));
}
a += 1;
- source_file = argv[a];
+ source_file = backslash_to_forwardslash(argv[a]);
} else if (strncmp(argv[a], "-msmall-int-bits=", sizeof("-msmall-int-bits=") - 1) == 0) {
char *end;
mp_dynamic_compiler.small_int_bits =
@@ -292,9 +312,25 @@ MP_NOINLINE int main_(int argc, char **argv) {
} else if (strcmp(arch, "xtensawin") == 0) {
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN;
mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN;
+ } else if (strcmp(arch, "host") == 0) {
+ #if defined(__i386__) || defined(_M_IX86)
+ mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86;
+ mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_X86;
+ #elif defined(__x86_64__) || defined(_M_X64)
+ mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X64;
+ mp_dynamic_compiler.nlr_buf_num_regs = MAX(MICROPY_NLR_NUM_REGS_X64, MICROPY_NLR_NUM_REGS_X64_WIN);
+ #elif defined(__arm__) && !defined(__thumb2__)
+ mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6;
+ mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP;
+ #else
+ mp_printf(&mp_stderr_print, "unable to determine host architecture for -march=host\n");
+ exit(1);
+ #endif
} else {
return usage(argv);
}
+ } else if (strcmp(argv[a], "--") == 0) {
+ option_parsing_active = false;
} else {
return usage(argv);
}
@@ -303,7 +339,7 @@ MP_NOINLINE int main_(int argc, char **argv) {
mp_printf(&mp_stderr_print, "multiple input files\n");
exit(1);
}
- input_file = argv[a];
+ input_file = backslash_to_forwardslash(argv[a]);
}
}
@@ -330,7 +366,7 @@ int main(int argc, char **argv) {
return main_(argc, argv);
}
-uint mp_import_stat(const char *path) {
+mp_import_stat_t mp_import_stat(const char *path) {
(void)path;
return MP_IMPORT_STAT_NO_EXIST;
}
diff --git a/mpy-cross/mpy-cross.vcxproj b/mpy-cross/mpy-cross.vcxproj
index 53cb0fa1fec7..322d8c25d109 100644
--- a/mpy-cross/mpy-cross.vcxproj
+++ b/mpy-cross/mpy-cross.vcxproj
@@ -24,7 +24,6 @@
True
$(MSBuildThisFileDirectory)build\
$(MSBuildThisFileDirectory)
- $(MSBuildThisFileDirectory)
$(MSBuildThisFileDirectory)..\ports\windows\msvc\
diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk
index 428367d66adf..5021e4ff3cb1 100644
--- a/ports/cc3200/application.mk
+++ b/ports/cc3200/application.mk
@@ -78,10 +78,9 @@ APP_MISC_SRC_C = $(addprefix misc/,\
APP_MODS_SRC_C = $(addprefix mods/,\
modmachine.c \
modnetwork.c \
- moduos.c \
- modusocket.c \
- modussl.c \
- modutime.c \
+ modos.c \
+ modsocket.c \
+ modssl.c \
modwipy.c \
modwlan.c \
pybadc.c \
@@ -162,7 +161,7 @@ APP_STM_SRC_C = $(addprefix ports/stm32/,\
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(APP_FATFS_SRC_C:.c=.o) $(APP_RTOS_SRC_C:.c=.o) $(APP_FTP_SRC_C:.c=.o) $(APP_HAL_SRC_C:.c=.o) $(APP_MISC_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(APP_MODS_SRC_C:.c=.o) $(APP_CC3100_SRC_C:.c=.o) $(APP_SL_SRC_C:.c=.o) $(APP_TELNET_SRC_C:.c=.o) $(APP_UTIL_SRC_C:.c=.o) $(APP_UTIL_SRC_S:.s=.o))
OBJ += $(addprefix $(BUILD)/, $(APP_MAIN_SRC_C:.c=.o) $(APP_SHARED_SRC_C:.c=.o) $(APP_LIB_SRC_C:.c=.o) $(APP_STM_SRC_C:.c=.o))
-OBJ += $(BUILD)/shared/runtime/gchelper_m3.o
+OBJ += $(BUILD)/shared/runtime/gchelper_thumb2.o
OBJ += $(BUILD)/pins.o
# List of sources for qstr extraction
diff --git a/ports/cc3200/boards/make-pins.py b/ports/cc3200/boards/make-pins.py
index 0cf0d565606f..6608be438a21 100644
--- a/ports/cc3200/boards/make-pins.py
+++ b/ports/cc3200/boards/make-pins.py
@@ -124,7 +124,7 @@ def parse_af_file(self, filename, pin_col, pinname_col, af_start_col):
continue
if not row[pin_col].isdigit():
raise ValueError(
- "Invalid pin number {:s} in row {:s}".format(row[pin_col]), row
+ "Invalid pin number {:s} in row {:s}".format(row[pin_col], row)
)
# Pin numbers must start from 0 when used with the TI API
pin_num = int(row[pin_col]) - 1
diff --git a/ports/cc3200/bootmgr/main.c b/ports/cc3200/bootmgr/main.c
index cfb8dec21d38..6feeec79a3b8 100644
--- a/ports/cc3200/bootmgr/main.c
+++ b/ports/cc3200/bootmgr/main.c
@@ -256,7 +256,7 @@ static bool wait_while_blinking (uint32_t wait_time, uint32_t period, bool force
_u32 count;
for (count = 0; (force_wait || MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN)) &&
((period * count) < wait_time); count++) {
- // toogle the led
+ // toggle the led
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
UtilsDelay(UTILS_DELAY_US_TO_COUNT(period * 1000));
}
diff --git a/ports/cc3200/fatfs/src/drivers/sd_diskio.c b/ports/cc3200/fatfs/src/drivers/sd_diskio.c
index 0a1379181b45..329ae04b9910 100644
--- a/ports/cc3200/fatfs/src/drivers/sd_diskio.c
+++ b/ports/cc3200/fatfs/src/drivers/sd_diskio.c
@@ -269,7 +269,7 @@ DSTATUS sd_disk_init (void) {
// Fill in the RCA
sd_disk_info.usRCA = (ulResp[0] >> 16);
- // Get tha card capacity
+ // Get the card capacity
CardCapacityGet(&sd_disk_info);
}
diff --git a/ports/cc3200/ftp/ftp.c b/ports/cc3200/ftp/ftp.c
index d999e810d9e0..5d4fc6fb5f2d 100644
--- a/ports/cc3200/ftp/ftp.c
+++ b/ports/cc3200/ftp/ftp.c
@@ -42,13 +42,13 @@
#include "simplelink.h"
#include "modnetwork.h"
#include "modwlan.h"
-#include "modusocket.h"
+#include "modsocket.h"
#include "debug.h"
#include "serverstask.h"
#include "fifo.h"
#include "socketfifo.h"
#include "updater.h"
-#include "moduos.h"
+#include "modos.h"
/******************************************************************************
DEFINE PRIVATE CONSTANTS
@@ -97,7 +97,7 @@ typedef enum {
typedef struct {
bool uservalid : 1;
bool passvalid : 1;
-} ftp_loggin_t;
+} ftp_login_t;
typedef enum {
E_FTP_NOTHING_OPEN = 0,
@@ -127,8 +127,8 @@ typedef struct {
uint8_t state;
uint8_t substate;
uint8_t txRetries;
- uint8_t logginRetries;
- ftp_loggin_t loggin;
+ uint8_t loginRetries;
+ ftp_login_t login;
uint8_t e_open;
bool closechild;
bool enabled;
@@ -329,10 +329,10 @@ void ftp_run (void) {
if (ftp_data.c_sd < 0 && ftp_data.substate == E_FTP_STE_SUB_DISCONNECTED) {
if (E_FTP_RESULT_OK == ftp_wait_for_connection(ftp_data.lc_sd, &ftp_data.c_sd)) {
ftp_data.txRetries = 0;
- ftp_data.logginRetries = 0;
+ ftp_data.loginRetries = 0;
ftp_data.ctimeout = 0;
- ftp_data.loggin.uservalid = false;
- ftp_data.loggin.passvalid = false;
+ ftp_data.login.uservalid = false;
+ ftp_data.login.passvalid = false;
strcpy (ftp_path, "/");
ftp_send_reply (220, "MicroPython FTP Server");
break;
@@ -684,7 +684,7 @@ static void ftp_process_cmd (void) {
if (E_FTP_RESULT_OK == (result = ftp_recv_non_blocking(ftp_data.c_sd, ftp_cmd_buffer, FTP_MAX_PARAM_SIZE + FTP_CMD_SIZE_MAX, &len))) {
// bufptr is moved as commands are being popped
ftp_cmd_index_t cmd = ftp_pop_command(&bufptr);
- if (!ftp_data.loggin.passvalid && (cmd != E_FTP_CMD_USER && cmd != E_FTP_CMD_PASS && cmd != E_FTP_CMD_QUIT && cmd != E_FTP_CMD_FEAT)) {
+ if (!ftp_data.login.passvalid && (cmd != E_FTP_CMD_USER && cmd != E_FTP_CMD_PASS && cmd != E_FTP_CMD_QUIT && cmd != E_FTP_CMD_FEAT)) {
ftp_send_reply(332, NULL);
return;
}
@@ -754,16 +754,16 @@ static void ftp_process_cmd (void) {
case E_FTP_CMD_USER:
ftp_pop_param (&bufptr, ftp_scratch_buffer);
if (!memcmp(ftp_scratch_buffer, servers_user, MAX(strlen(ftp_scratch_buffer), strlen(servers_user)))) {
- ftp_data.loggin.uservalid = true && (strlen(servers_user) == strlen(ftp_scratch_buffer));
+ ftp_data.login.uservalid = true && (strlen(servers_user) == strlen(ftp_scratch_buffer));
}
ftp_send_reply(331, NULL);
break;
case E_FTP_CMD_PASS:
ftp_pop_param (&bufptr, ftp_scratch_buffer);
if (!memcmp(ftp_scratch_buffer, servers_pass, MAX(strlen(ftp_scratch_buffer), strlen(servers_pass))) &&
- ftp_data.loggin.uservalid) {
- ftp_data.loggin.passvalid = true && (strlen(servers_pass) == strlen(ftp_scratch_buffer));
- if (ftp_data.loggin.passvalid) {
+ ftp_data.login.uservalid) {
+ ftp_data.login.passvalid = true && (strlen(servers_pass) == strlen(ftp_scratch_buffer));
+ if (ftp_data.login.passvalid) {
ftp_send_reply(230, NULL);
break;
}
diff --git a/ports/cc3200/hal/cc3200_hal.c b/ports/cc3200/hal/cc3200_hal.c
index 4694235eebf6..4d9d7647d3de 100644
--- a/ports/cc3200/hal/cc3200_hal.c
+++ b/ports/cc3200/hal/cc3200_hal.c
@@ -49,7 +49,7 @@
#include "pybuart.h"
#include "utils.h"
#include "irq.h"
-#include "moduos.h"
+#include "modos.h"
#ifdef USE_FREERTOS
#include "FreeRTOS.h"
diff --git a/ports/cc3200/hal/cc3200_hal.h b/ports/cc3200/hal/cc3200_hal.h
index 3d0d632d519b..9e57d39e2e70 100644
--- a/ports/cc3200/hal/cc3200_hal.h
+++ b/ports/cc3200/hal/cc3200_hal.h
@@ -67,3 +67,4 @@ extern void mp_hal_set_interrupt_char (int c);
#define mp_hal_stdio_poll(poll_flags) (0) // not implemented
#define mp_hal_delay_us(usec) UtilsDelay(UTILS_DELAY_US_TO_COUNT(usec))
#define mp_hal_ticks_cpu() (SysTickPeriodGet() - SysTickValueGet())
+#define mp_hal_time_ns() (0) // not implemented
diff --git a/ports/cc3200/misc/help.c b/ports/cc3200/misc/help.c
index ea0c9501dbce..213950c8ed6b 100644
--- a/ports/cc3200/misc/help.c
+++ b/ports/cc3200/misc/help.c
@@ -28,5 +28,5 @@
#include "py/builtin.h"
const char cc3200_help_text[] = "Welcome to MicroPython!\n"
- "For online help please visit http://micropython.org/help/.\n"
+ "For online docs please visit http://docs.micropython.org/\n"
"For further help on a specific object, type help(obj)\n";
diff --git a/ports/cc3200/misc/mperror.c b/ports/cc3200/misc/mperror.c
index 082d940e2f3a..6d6c0ff0bae8 100644
--- a/ports/cc3200/misc/mperror.c
+++ b/ports/cc3200/misc/mperror.c
@@ -127,7 +127,7 @@ void mperror_deinit_sfe_pin (void) {
void mperror_signal_error (void) {
uint32_t count = 0;
while ((MPERROR_TOOGLE_MS * count++) < MPERROR_SIGNAL_ERROR_MS) {
- // toogle the led
+ // toggle the led
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
UtilsDelay(UTILS_DELAY_US_TO_COUNT(MPERROR_TOOGLE_MS * 1000));
}
diff --git a/ports/cc3200/mods/modhashlib.c b/ports/cc3200/mods/modhashlib.c
new file mode 100644
index 000000000000..de56e114af79
--- /dev/null
+++ b/ports/cc3200/mods/modhashlib.c
@@ -0,0 +1,209 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Paul Sokolovsky
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/mpconfig.h"
+#include MICROPY_HAL_H
+#include "py/runtime.h"
+#include "inc/hw_types.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_shamd5.h"
+#include "inc/hw_dthe.h"
+#include "hw_memmap.h"
+#include "rom_map.h"
+#include "prcm.h"
+#include "shamd5.h"
+#include "cryptohash.h"
+
+
+/******************************************************************************
+ DEFINE PRIVATE TYPES
+ ******************************************************************************/
+typedef struct _mp_obj_hash_t {
+ mp_obj_base_t base;
+ uint8_t *buffer;
+ uint32_t b_size;
+ uint32_t c_size;
+ uint8_t algo;
+ uint8_t h_size;
+ bool fixedlen;
+ bool digested;
+ uint8_t hash[32];
+} mp_obj_hash_t;
+
+/******************************************************************************
+ DECLARE PRIVATE FUNCTIONS
+ ******************************************************************************/
+STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest);
+STATIC mp_obj_t hash_read (mp_obj_t self_in);
+
+/******************************************************************************
+ DEFINE PRIVATE FUNCTIONS
+ ******************************************************************************/
+STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) {
+ mp_obj_hash_t *self = self_in;
+ mp_buffer_info_t bufinfo;
+
+ if (data) {
+ mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
+ }
+
+ if (digest) {
+ CRYPTOHASH_SHAMD5Start (self->algo, self->b_size);
+ }
+
+ if (self->c_size < self->b_size || !data || !self->fixedlen) {
+ if (digest || self->fixedlen) {
+ // no data means we want to process our internal buffer
+ CRYPTOHASH_SHAMD5Update (data ? bufinfo.buf : self->buffer, data ? bufinfo.len : self->b_size);
+ self->c_size += data ? bufinfo.len : 0;
+ } else {
+ self->buffer = m_renew(byte, self->buffer, self->b_size, self->b_size + bufinfo.len);
+ mp_seq_copy((byte*)self->buffer + self->b_size, bufinfo.buf, bufinfo.len, byte);
+ self->b_size += bufinfo.len;
+ self->digested = false;
+ }
+ } else {
+ mp_raise_OSError(MP_EPERM);
+ }
+}
+
+STATIC mp_obj_t hash_read (mp_obj_t self_in) {
+ mp_obj_hash_t *self = self_in;
+
+ if (!self->fixedlen) {
+ if (!self->digested) {
+ hash_update_internal(self, MP_OBJ_NULL, true);
+ }
+ } else if (self->c_size < self->b_size) {
+ // it's a fixed len block which is still incomplete
+ mp_raise_OSError(MP_EPERM);
+ }
+
+ if (!self->digested) {
+ CRYPTOHASH_SHAMD5Read ((uint8_t *)self->hash);
+ self->digested = true;
+ }
+ return mp_obj_new_bytes(self->hash, self->h_size);
+}
+
+/******************************************************************************/
+// MicroPython bindings
+
+/// \classmethod \constructor([data[, block_size]])
+/// initial data must be given if block_size wants to be passed
+STATIC mp_obj_t hash_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 2, false);
+ mp_obj_hash_t *self = m_new0(mp_obj_hash_t, 1);
+ self->base.type = type_in;
+ if (self->base.type->name == MP_QSTR_sha1) {
+ self->algo = SHAMD5_ALGO_SHA1;
+ self->h_size = 20;
+ } else /* if (self->base.type->name == MP_QSTR_sha256) */ {
+ self->algo = SHAMD5_ALGO_SHA256;
+ self->h_size = 32;
+ } /* else {
+ self->algo = SHAMD5_ALGO_MD5;
+ self->h_size = 32;
+ } */
+
+ if (n_args) {
+ // CPython extension to avoid buffering the data before digesting it
+ // Note: care must be taken to provide all intermediate blocks as multiple
+ // of four bytes, otherwise the resulting hash will be incorrect.
+ // the final block can be of any length
+ if (n_args > 1) {
+ // block size given, we will feed the data directly into the hash engine
+ self->fixedlen = true;
+ self->b_size = mp_obj_get_int(args[1]);
+ hash_update_internal(self, args[0], true);
+ } else {
+ hash_update_internal(self, args[0], false);
+ }
+ }
+ return self;
+}
+
+STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = self_in;
+ hash_update_internal(self, arg, false);
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
+
+STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
+ return hash_read(self_in);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
+
+STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table);
+
+//STATIC const mp_obj_type_t md5_type = {
+// { &mp_type_type },
+// .name = MP_QSTR_md5,
+// .make_new = hash_make_new,
+// .locals_dict = (mp_obj_t)&hash_locals_dict,
+//};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ sha1_type,
+ MP_QSTR_sha1,
+ MP_TYPE_FLAG_NONE,
+ make_new, hash_make_new,
+ locals_dict, &hash_locals_dict
+ );
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ sha256_type,
+ MP_QSTR_sha256,
+ MP_TYPE_FLAG_NONE,
+ make_new, hash_make_new,
+ locals_dict, &hash_locals_dict
+ );
+
+STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) },
+ //{ MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&md5_type) },
+ { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) },
+ { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
+
+const mp_obj_module_t mp_module_hashlib = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
+};
+
diff --git a/ports/cc3200/mods/modmachine.c b/ports/cc3200/mods/modmachine.c
index 3e483e0a23d2..bdf963c31a60 100644
--- a/ports/cc3200/mods/modmachine.c
+++ b/ports/cc3200/mods/modmachine.c
@@ -43,7 +43,7 @@
#include "simplelink.h"
#include "modnetwork.h"
#include "modwlan.h"
-#include "moduos.h"
+#include "modos.h"
#include "FreeRTOS.h"
#include "portable.h"
#include "task.h"
@@ -162,7 +162,7 @@ STATIC mp_obj_t machine_wake_reason (void) {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason);
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
#ifdef DEBUG
@@ -214,5 +214,5 @@ const mp_obj_module_t mp_module_machine = {
.globals = (mp_obj_dict_t*)&machine_module_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_umachine, mp_module_machine);
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
MP_REGISTER_ROOT_POINTER(mp_obj_t machine_config_main);
diff --git a/ports/cc3200/mods/modnetwork.h b/ports/cc3200/mods/modnetwork.h
index c15a6467f278..9bc2c71c2933 100644
--- a/ports/cc3200/mods/modnetwork.h
+++ b/ports/cc3200/mods/modnetwork.h
@@ -35,11 +35,6 @@
/******************************************************************************
DEFINE TYPES
******************************************************************************/
-typedef struct _mod_network_nic_type_t {
- // Ensure that this struct is big enough to hold any type size.
- mp_obj_full_type_t base;
-} mod_network_nic_type_t;
-
typedef struct _mod_network_socket_base_t {
union {
struct {
@@ -64,7 +59,7 @@ typedef struct _mod_network_socket_obj_t {
/******************************************************************************
EXPORTED DATA
******************************************************************************/
-extern const mod_network_nic_type_t mod_network_nic_type_wlan;
+extern const mp_obj_type_t mod_network_nic_type_wlan;
/******************************************************************************
DECLARE FUNCTIONS
diff --git a/ports/cc3200/mods/modos.c b/ports/cc3200/mods/modos.c
new file mode 100644
index 000000000000..1a854750f234
--- /dev/null
+++ b/ports/cc3200/mods/modos.c
@@ -0,0 +1,183 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "shared/timeutils/timeutils.h"
+#include "lib/oofatfs/ff.h"
+#include "lib/oofatfs/diskio.h"
+#include "genhdr/mpversion.h"
+#include "modos.h"
+#include "sflash_diskio.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "random.h"
+#include "version.h"
+#include "pybsd.h"
+#include "pybuart.h"
+
+/// \module os - basic "operating system" services
+///
+/// The `os` module contains functions for filesystem access and `urandom`.
+///
+/// The filesystem has `/` as the root directory, and the available physical
+/// drives are accessible from here. They are currently:
+///
+/// /flash -- the serial flash filesystem
+///
+/// On boot up, the current directory is `/flash`.
+
+/******************************************************************************
+ DECLARE PRIVATE DATA
+ ******************************************************************************/
+STATIC os_term_dup_obj_t os_term_dup_obj;
+
+/******************************************************************************
+ DEFINE PUBLIC FUNCTIONS
+ ******************************************************************************/
+
+void osmount_unmount_all (void) {
+ //TODO
+ /*
+ for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
+ os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
+ unmount(mount_obj);
+ }
+ */
+}
+
+/******************************************************************************/
+// MicroPython bindings
+//
+
+STATIC const qstr os_uname_info_fields[] = {
+ MP_QSTR_sysname, MP_QSTR_nodename,
+ MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
+};
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, WIPY_SW_VERSION_NUMBER);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
+STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
+STATIC MP_DEFINE_ATTRTUPLE(
+ os_uname_info_obj,
+ os_uname_info_fields,
+ 5,
+ (mp_obj_t)&os_uname_info_sysname_obj,
+ (mp_obj_t)&os_uname_info_nodename_obj,
+ (mp_obj_t)&os_uname_info_release_obj,
+ (mp_obj_t)&os_uname_info_version_obj,
+ (mp_obj_t)&os_uname_info_machine_obj
+);
+
+STATIC mp_obj_t os_uname(void) {
+ return (mp_obj_t)&os_uname_info_obj;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
+
+STATIC mp_obj_t os_sync(void) {
+ sflash_disk_flush();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
+
+STATIC mp_obj_t os_urandom(mp_obj_t num) {
+ mp_int_t n = mp_obj_get_int(num);
+ vstr_t vstr;
+ vstr_init_len(&vstr, n);
+ for (int i = 0; i < n; i++) {
+ vstr.buf[i] = rng_get();
+ }
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
+
+STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
+ return mp_const_none;
+ } else {
+ return MP_STATE_PORT(os_term_dup_obj)->stream_o;
+ }
+ } else {
+ mp_obj_t stream_o = args[0];
+ if (stream_o == mp_const_none) {
+ MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
+ } else {
+ if (!mp_obj_is_type(stream_o, &pyb_uart_type)) {
+ // must be a stream-like object providing at least read and write methods
+ mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
+ mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
+ }
+ os_term_dup_obj.stream_o = stream_o;
+ MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
+
+STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_os) },
+
+ { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
+
+ { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&os_sync_obj) },
+ { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
+
+ // MicroPython additions
+ // removed: mkfs
+ // renamed: unmount -> umount
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
+ { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
+
+const mp_obj_module_t mp_module_os = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&os_module_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_os, mp_module_os);
diff --git a/ports/cc3200/mods/modos.h b/ports/cc3200/mods/modos.h
new file mode 100644
index 000000000000..5fa2a967d434
--- /dev/null
+++ b/ports/cc3200/mods/modos.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_CC3200_MODS_MODOS_H
+#define MICROPY_INCLUDED_CC3200_MODS_MODOS_H
+
+#include "py/obj.h"
+
+/******************************************************************************
+ DEFINE PUBLIC TYPES
+ ******************************************************************************/
+
+typedef struct _os_term_dup_obj_t {
+ mp_obj_t stream_o;
+ mp_obj_t read[3];
+ mp_obj_t write[3];
+} os_term_dup_obj_t;
+
+/******************************************************************************
+ DECLARE PUBLIC FUNCTIONS
+ ******************************************************************************/
+void osmount_unmount_all (void);
+
+#endif // MICROPY_INCLUDED_CC3200_MODS_MODOS_H
diff --git a/ports/cc3200/mods/modsocket.c b/ports/cc3200/mods/modsocket.c
new file mode 100644
index 000000000000..a107fa712073
--- /dev/null
+++ b/ports/cc3200/mods/modsocket.c
@@ -0,0 +1,821 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+
+#include "simplelink.h"
+#include "py/mpconfig.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/mphal.h"
+#include "shared/netutils/netutils.h"
+#include "modnetwork.h"
+#include "modsocket.h"
+
+/******************************************************************************/
+// The following set of macros and functions provide a glue between the CC3100
+// simplelink layer and the functions/methods provided by the socket module.
+// They were historically in a separate file because socket was designed to
+// work with multiple NICs, and the wlan_XXX functions just provided one
+// particular NIC implementation (that of the CC3100). But the CC3200 port only
+// supports a single NIC (being the CC3100) so it's unnecessary and inefficient
+// to provide an intermediate wrapper layer. Hence the wlan_XXX functions
+// are provided below as static functions so they can be inlined directly by
+// the corresponding socket calls.
+
+#define WLAN_MAX_RX_SIZE 16000
+#define WLAN_MAX_TX_SIZE 1476
+
+#define MAKE_SOCKADDR(addr, ip, port) SlSockAddr_t addr; \
+ addr.sa_family = SL_AF_INET; \
+ addr.sa_data[0] = port >> 8; \
+ addr.sa_data[1] = port; \
+ addr.sa_data[2] = ip[3]; \
+ addr.sa_data[3] = ip[2]; \
+ addr.sa_data[4] = ip[1]; \
+ addr.sa_data[5] = ip[0];
+
+#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
+ ip[0] = addr.sa_data[5]; \
+ ip[1] = addr.sa_data[4]; \
+ ip[2] = addr.sa_data[3]; \
+ ip[3] = addr.sa_data[2];
+
+#define SOCKET_TIMEOUT_QUANTA_MS (20)
+
+STATIC int convert_sl_errno(int sl_errno) {
+ return -sl_errno;
+}
+
+// This function is left as non-static so it's not inlined.
+int check_timedout(mod_network_socket_obj_t *s, int ret, uint32_t *timeout_ms, int *_errno) {
+ if (*timeout_ms == 0 || ret != SL_EAGAIN) {
+ if (s->sock_base.timeout_ms > 0 && ret == SL_EAGAIN) {
+ *_errno = MP_ETIMEDOUT;
+ } else {
+ *_errno = convert_sl_errno(ret);
+ }
+ return -1;
+ }
+ mp_hal_delay_ms(SOCKET_TIMEOUT_QUANTA_MS);
+ if (*timeout_ms < SOCKET_TIMEOUT_QUANTA_MS) {
+ *timeout_ms = 0;
+ } else {
+ *timeout_ms -= SOCKET_TIMEOUT_QUANTA_MS;
+ }
+ return 0;
+}
+
+STATIC int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) {
+ uint32_t ip;
+ int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family);
+ out_ip[0] = ip;
+ out_ip[1] = ip >> 8;
+ out_ip[2] = ip >> 16;
+ out_ip[3] = ip >> 24;
+ return result;
+}
+
+STATIC int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) {
+ int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto);
+ if (sd < 0) {
+ *_errno = sd;
+ return -1;
+ }
+ s->sock_base.sd = sd;
+ return 0;
+}
+
+STATIC void wlan_socket_close(mod_network_socket_obj_t *s) {
+ // this is to prevent the finalizer to close a socket that failed when being created
+ if (s->sock_base.sd >= 0) {
+ modusocket_socket_delete(s->sock_base.sd);
+ sl_Close(s->sock_base.sd);
+ s->sock_base.sd = -1;
+ }
+}
+
+STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) {
+ int ret = sl_Listen(s->sock_base.sd, backlog);
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) {
+ // accept incoming connection
+ int16_t sd;
+ SlSockAddr_t addr;
+ SlSocklen_t addr_len = sizeof(addr);
+
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+ for (;;) {
+ sd = sl_Accept(s->sock_base.sd, &addr, &addr_len);
+ if (sd >= 0) {
+ // save the socket descriptor
+ s2->sock_base.sd = sd;
+ // return ip and port
+ UNPACK_SOCKADDR(addr, ip, *port);
+ return 0;
+ }
+ if (check_timedout(s, sd, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+
+ // For a non-blocking connect the CC3100 will return SL_EALREADY while the
+ // connection is in progress.
+
+ for (;;) {
+ int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr));
+ if (ret == 0) {
+ return 0;
+ }
+
+ // Check if we are in non-blocking mode and the connection is in progress
+ if (s->sock_base.timeout_ms == 0 && ret == SL_EALREADY) {
+ // To match BSD we return EINPROGRESS here
+ *_errno = MP_EINPROGRESS;
+ return -1;
+ }
+
+ // We are in blocking mode, so if the connection isn't in progress then error out
+ if (ret != SL_EALREADY) {
+ *_errno = convert_sl_errno(ret);
+ return -1;
+ }
+
+ if (check_timedout(s, SL_EAGAIN, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
+ if (len == 0) {
+ return 0;
+ }
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+ for (;;) {
+ int ret = sl_Send(s->sock_base.sd, (const void *)buf, len, 0);
+ if (ret > 0) {
+ return ret;
+ }
+ if (check_timedout(s, ret, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+ for (;;) {
+ int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0);
+ if (ret >= 0) {
+ return ret;
+ }
+ if (check_timedout(s, ret, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+ for (;;) {
+ int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr));
+ if (ret >= 0) {
+ return ret;
+ }
+ if (check_timedout(s, ret, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ SlSockAddr_t addr;
+ SlSocklen_t addr_len = sizeof(addr);
+ uint32_t timeout_ms = s->sock_base.timeout_ms;
+ for (;;) {
+ int ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len);
+ if (ret >= 0) {
+ UNPACK_SOCKADDR(addr, ip, *port);
+ return ret;
+ }
+ if (check_timedout(s, ret, &timeout_ms, _errno)) {
+ return -1;
+ }
+ }
+}
+
+STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
+ int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen);
+ if (ret < 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) {
+ SlSockNonblocking_t option;
+ if (timeout_s == 0 || timeout_s == -1) {
+ if (timeout_s == 0) {
+ // set non-blocking mode
+ option.NonblockingEnabled = 1;
+ } else {
+ // set blocking mode
+ option.NonblockingEnabled = 0;
+ }
+ timeout_s = 0;
+ } else {
+ // synthesize timeout via non-blocking behaviour with a loop
+ option.NonblockingEnabled = 1;
+ }
+
+ int ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option));
+ if (ret != 0) {
+ *_errno = convert_sl_errno(ret);
+ return -1;
+ }
+
+ s->sock_base.timeout_ms = timeout_s * 1000;
+ return 0;
+}
+
+STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ mp_int_t ret;
+ if (request == MP_STREAM_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ int32_t sd = s->sock_base.sd;
+
+ // init fds
+ SlFdSet_t rfds, wfds, xfds;
+ SL_FD_ZERO(&rfds);
+ SL_FD_ZERO(&wfds);
+ SL_FD_ZERO(&xfds);
+
+ // set fds if needed
+ if (flags & MP_STREAM_POLL_RD) {
+ SL_FD_SET(sd, &rfds);
+ }
+ if (flags & MP_STREAM_POLL_WR) {
+ SL_FD_SET(sd, &wfds);
+ }
+ if (flags & MP_STREAM_POLL_HUP) {
+ SL_FD_SET(sd, &xfds);
+ }
+
+ // call simplelink's select with minimum timeout
+ SlTimeval_t tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
+
+ // check for errors
+ if (nfds == -1) {
+ *_errno = nfds;
+ return -1;
+ }
+
+ // check return of select
+ if (SL_FD_ISSET(sd, &rfds)) {
+ ret |= MP_STREAM_POLL_RD;
+ }
+ if (SL_FD_ISSET(sd, &wfds)) {
+ ret |= MP_STREAM_POLL_WR;
+ }
+ if (SL_FD_ISSET(sd, &xfds)) {
+ ret |= MP_STREAM_POLL_HUP;
+ }
+ } else if (request == MP_STREAM_CLOSE) {
+ wlan_socket_close(s);
+ ret = 0;
+ } else {
+ *_errno = MP_EINVAL;
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+/******************************************************************************
+ DEFINE PRIVATE CONSTANTS
+ ******************************************************************************/
+#define MOD_NETWORK_MAX_SOCKETS 10
+
+/******************************************************************************
+ DEFINE PRIVATE TYPES
+ ******************************************************************************/
+typedef struct {
+ int16_t sd;
+ bool user;
+} modusocket_sock_t;
+
+/******************************************************************************
+ DEFINE PRIVATE DATA
+ ******************************************************************************/
+STATIC const mp_obj_type_t socket_type;
+STATIC OsiLockObj_t modusocket_LockObj;
+STATIC modusocket_sock_t modusocket_sockets[MOD_NETWORK_MAX_SOCKETS] = {{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1},
+ {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}};
+
+/******************************************************************************
+ DEFINE PUBLIC FUNCTIONS
+ ******************************************************************************/
+__attribute__ ((section (".boot")))
+void modusocket_pre_init (void) {
+ // create the wlan lock
+ ASSERT(OSI_OK == sl_LockObjCreate(&modusocket_LockObj, "SockLock"));
+ sl_LockObjUnlock (&modusocket_LockObj);
+}
+
+void modusocket_socket_add (int16_t sd, bool user) {
+ sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
+ for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
+ if (modusocket_sockets[i].sd < 0) {
+ modusocket_sockets[i].sd = sd;
+ modusocket_sockets[i].user = user;
+ break;
+ }
+ }
+ sl_LockObjUnlock (&modusocket_LockObj);
+}
+
+void modusocket_socket_delete (int16_t sd) {
+ sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
+ for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
+ if (modusocket_sockets[i].sd == sd) {
+ modusocket_sockets[i].sd = -1;
+ break;
+ }
+ }
+ sl_LockObjUnlock (&modusocket_LockObj);
+}
+
+void modusocket_enter_sleep (void) {
+ SlFdSet_t socketset;
+ int16_t maxfd = 0;
+
+ for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
+ int16_t sd;
+ if ((sd = modusocket_sockets[i].sd) >= 0) {
+ SL_FD_SET(sd, &socketset);
+ maxfd = (maxfd > sd) ? maxfd : sd;
+ }
+ }
+
+ if (maxfd > 0) {
+ // wait for any of the sockets to become ready...
+ sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
+ }
+}
+
+void modusocket_close_all_user_sockets (void) {
+ sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
+ for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
+ if (modusocket_sockets[i].sd >= 0 && modusocket_sockets[i].user) {
+ sl_Close(modusocket_sockets[i].sd);
+ modusocket_sockets[i].sd = -1;
+ }
+ }
+ sl_LockObjUnlock (&modusocket_LockObj);
+}
+
+/******************************************************************************/
+// socket class
+
+// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None)
+STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 4, false);
+
+ // create socket object
+ mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ s->base.type = (mp_obj_t)&socket_type;
+ s->sock_base.u_param.domain = SL_AF_INET;
+ s->sock_base.u_param.type = SL_SOCK_STREAM;
+ s->sock_base.u_param.proto = SL_IPPROTO_TCP;
+ s->sock_base.u_param.fileno = -1;
+ s->sock_base.timeout_ms = 0;
+ s->sock_base.cert_req = false;
+
+ if (n_args > 0) {
+ s->sock_base.u_param.domain = mp_obj_get_int(args[0]);
+ if (n_args > 1) {
+ s->sock_base.u_param.type = mp_obj_get_int(args[1]);
+ if (n_args > 2) {
+ s->sock_base.u_param.proto = mp_obj_get_int(args[2]);
+ if (n_args > 3) {
+ s->sock_base.u_param.fileno = mp_obj_get_int(args[3]);
+ }
+ }
+ }
+ }
+
+ // create the socket
+ int _errno;
+ if (wlan_socket_socket(s, &_errno) != 0) {
+ mp_raise_OSError(-_errno);
+ }
+ // add the socket to the list
+ modusocket_socket_add(s->sock_base.sd, true);
+ return s;
+}
+
+// method socket.bind(address)
+STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
+
+ // call the NIC to bind the socket
+ int _errno = 0;
+ if (wlan_socket_bind(self, ip, port, &_errno) != 0) {
+ mp_raise_OSError(-_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
+
+// method socket.listen([backlog])
+STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = args[0];
+
+ int32_t backlog = MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT;
+ if (n_args > 1) {
+ backlog = mp_obj_get_int(args[1]);
+ backlog = (backlog < 0) ? 0 : backlog;
+ }
+
+ int _errno;
+ if (wlan_socket_listen(self, backlog, &_errno) != 0) {
+ mp_raise_OSError(-_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
+
+// method socket.accept()
+STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // create new socket object
+ mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ // the new socket inherits all properties from its parent
+ memcpy (socket2, self, sizeof(mod_network_socket_obj_t));
+
+ // accept the incoming connection
+ uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
+ mp_uint_t port = 0;
+ int _errno = 0;
+ if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+
+ // add the socket to the list
+ modusocket_socket_add(socket2->sock_base.sd, true);
+
+ // make the return value
+ mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
+ client->items[0] = socket2;
+ client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
+ return client;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
+
+// method socket.connect(address)
+STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
+
+ // connect the socket
+ int _errno;
+ if (wlan_socket_connect(self, ip, port, &_errno) != 0) {
+ if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) {
+ return mp_const_none;
+ }
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
+
+// method socket.send(bytes)
+STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ mod_network_socket_obj_t *self = self_in;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ int _errno;
+ mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret < 0) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_obj_new_int_from_uint(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
+
+// method socket.recv(bufsize)
+STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ mp_int_t len = mp_obj_get_int(len_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, len);
+ int _errno;
+ mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
+ if (ret < 0) {
+ mp_raise_OSError(_errno);
+ }
+ if (ret == 0) {
+ return mp_const_empty_bytes;
+ }
+ vstr.len = ret;
+ vstr.buf[vstr.len] = '\0';
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
+
+// method socket.sendto(bytes, address)
+STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get the data
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
+ mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
+
+ // call the nic to sendto
+ int _errno = 0;
+ mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
+ if (ret < 0) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
+
+// method socket.recvfrom(bufsize)
+STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ vstr_t vstr;
+ vstr_init_len(&vstr, mp_obj_get_int(len_in));
+ byte ip[4];
+ mp_uint_t port = 0;
+ int _errno = 0;
+ mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno);
+ if (ret < 0) {
+ mp_raise_OSError(_errno);
+ }
+ mp_obj_t tuple[2];
+ if (ret == 0) {
+ tuple[0] = mp_const_empty_bytes;
+ } else {
+ vstr.len = ret;
+ vstr.buf[vstr.len] = '\0';
+ tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
+ }
+ tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
+
+// method socket.setsockopt(level, optname, value)
+STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = args[0];
+
+ mp_int_t level = mp_obj_get_int(args[1]);
+ mp_int_t opt = mp_obj_get_int(args[2]);
+
+ const void *optval;
+ mp_uint_t optlen;
+ mp_int_t val;
+ if (mp_obj_is_integer(args[3])) {
+ val = mp_obj_get_int_truncated(args[3]);
+ optval = &val;
+ optlen = sizeof(val);
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ optval = bufinfo.buf;
+ optlen = bufinfo.len;
+ }
+
+ int _errno;
+ if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
+ mp_raise_OSError(-_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+
+// method socket.settimeout(value)
+// timeout=0 means non-blocking
+// timeout=None means blocking
+// otherwise, timeout is in seconds
+STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ mod_network_socket_obj_t *self = self_in;
+ mp_uint_t timeout;
+ if (timeout_in == mp_const_none) {
+ timeout = -1;
+ } else {
+ timeout = mp_obj_get_int(timeout_in);
+ }
+ int _errno = 0;
+ if (wlan_socket_settimeout(self, timeout, &_errno) != 0) {
+ mp_raise_OSError(_errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
+
+// method socket.setblocking(flag)
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ if (mp_obj_is_true(blocking)) {
+ return socket_settimeout(self_in, mp_const_none);
+ } else {
+ return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
+STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return args[0];
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
+
+STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
+ { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
+ { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
+ { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
+ { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
+ { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
+
+ // stream methods
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read1_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+};
+
+MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
+
+STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
+ mod_network_socket_obj_t *self = self_in;
+ mp_int_t ret = wlan_socket_recv(self, buf, size, errcode);
+ if (ret < 0) {
+ // we need to ignore the socket closed error here because a read() without params
+ // only returns when the socket is closed by the other end
+ if (*errcode != -SL_ESECCLOSED) {
+ ret = MP_STREAM_ERROR;
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
+ mod_network_socket_obj_t *self = self_in;
+ mp_int_t ret = wlan_socket_send(self, buf, size, errcode);
+ if (ret < 0) {
+ ret = MP_STREAM_ERROR;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ mod_network_socket_obj_t *self = self_in;
+ return wlan_socket_ioctl(self, request, arg, errcode);
+}
+
+const mp_stream_p_t socket_stream_p = {
+ .read = socket_read,
+ .write = socket_write,
+ .ioctl = socket_ioctl,
+ .is_text = false,
+};
+
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ socket_type,
+ MP_QSTR_socket,
+ MP_TYPE_FLAG_NONE,
+ make_new, socket_make_new,
+ protocol, &socket_stream_p,
+ locals_dict, &socket_locals_dict
+ );
+
+/******************************************************************************/
+// socket module
+
+// function socket.getaddrinfo(host, port)
+/// \function getaddrinfo(host, port)
+STATIC mp_obj_t mod_socket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
+ size_t hlen;
+ const char *host = mp_obj_str_get_data(host_in, &hlen);
+ mp_int_t port = mp_obj_get_int(port_in);
+
+ // ipv4 only
+ uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
+ int32_t result = wlan_gethostbyname(host, hlen, out_ip, SL_AF_INET);
+ if (result < 0) {
+ mp_raise_OSError(-result);
+ }
+ mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
+ tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SL_AF_INET);
+ tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SL_SOCK_STREAM);
+ tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
+ tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_LITTLE);
+ return mp_obj_new_list(1, (mp_obj_t*)&tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_socket_getaddrinfo_obj, mod_socket_getaddrinfo);
+
+STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_socket) },
+
+ { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
+ { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_socket_getaddrinfo_obj) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(SL_AF_INET) },
+
+ { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SL_SOCK_STREAM) },
+ { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SL_SOCK_DGRAM) },
+
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_SEC), MP_ROM_INT(SL_SEC_SOCKET) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(SL_IPPROTO_TCP) },
+ { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(SL_IPPROTO_UDP) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
+
+const mp_obj_module_t mp_module_socket = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_socket_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_socket);
diff --git a/ports/cc3200/mods/modsocket.h b/ports/cc3200/mods/modsocket.h
new file mode 100644
index 000000000000..8eb4cb50ac6a
--- /dev/null
+++ b/ports/cc3200/mods/modsocket.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_CC3200_MODS_MODSOCKET_H
+#define MICROPY_INCLUDED_CC3200_MODS_MODSOCKET_H
+
+#include "py/stream.h"
+
+extern const mp_obj_dict_t socket_locals_dict;
+extern const mp_stream_p_t socket_stream_p;
+
+extern void modusocket_pre_init (void);
+extern void modusocket_socket_add (int16_t sd, bool user);
+extern void modusocket_socket_delete (int16_t sd);
+extern void modusocket_enter_sleep (void);
+extern void modusocket_close_all_user_sockets (void);
+
+#endif // MICROPY_INCLUDED_CC3200_MODS_MODSOCKET_H
diff --git a/ports/cc3200/mods/modssl.c b/ports/cc3200/mods/modssl.c
new file mode 100644
index 000000000000..15c825fcf4dc
--- /dev/null
+++ b/ports/cc3200/mods/modssl.c
@@ -0,0 +1,163 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "simplelink.h"
+#include "py/mpconfig.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/runtime.h"
+#include "modnetwork.h"
+#include "modsocket.h"
+
+/******************************************************************************
+ DEFINE CONSTANTS
+ ******************************************************************************/
+#define SSL_CERT_NONE (0)
+#define SSL_CERT_OPTIONAL (1)
+#define SSL_CERT_REQUIRED (2)
+
+/******************************************************************************
+ DEFINE TYPES
+ ******************************************************************************/
+typedef struct _mp_obj_ssl_socket_t {
+ mp_obj_base_t base;
+ mod_network_socket_base_t sock_base;
+ mp_obj_t o_sock;
+} mp_obj_ssl_socket_t;
+
+/******************************************************************************
+ DECLARE PRIVATE DATA
+ ******************************************************************************/
+STATIC const mp_obj_type_t ssl_socket_type;
+
+/******************************************************************************/
+// MicroPython bindings; SSL class
+
+// ssl sockets inherit from normal socket, so we take its
+// locals and stream methods
+STATIC MP_DEFINE_CONST_OBJ_TYPE(
+ ssl_socket_type,
+ MP_QSTR_ssl,
+ MP_TYPE_FLAG_NONE,
+ protocol, &socket_stream_p,
+ locals_dict, &socket_locals_dict
+ );
+
+STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ STATIC const mp_arg_t allowed_args[] = {
+ { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_OBJ, },
+ { MP_QSTR_keyfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
+ { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} },
+ { MP_QSTR_ssl_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SO_SEC_METHOD_TLSV1} },
+ { MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // parse arguments
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // check if ca validation is required
+ if (args[4].u_int != SSL_CERT_NONE && args[6].u_obj == mp_const_none) {
+ goto arg_error;
+ }
+
+ // retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
+ const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
+ const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
+ const char *cafile = (args[6].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
+ NULL : &(mp_obj_str_get_str(args[6].u_obj)[6]);
+
+ // server side requires both certfile and keyfile
+ if (args[3].u_bool && (!keyfile || !certfile)) {
+ goto arg_error;
+ }
+
+ _i16 _errno;
+ _i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
+
+ // set the requested SSL method
+ _u8 method = args[5].u_int;
+ if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) {
+ goto socket_error;
+ }
+ if (keyfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, keyfile, strlen(keyfile))) < 0) {
+ goto socket_error;
+ }
+ if (certfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, certfile, strlen(certfile))) < 0) {
+ goto socket_error;
+ }
+ if (cafile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, cafile, strlen(cafile))) < 0) {
+ goto socket_error;
+ }
+
+ // create the ssl socket
+ mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
+ // ssl sockets inherit all properties from the original socket
+ memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
+ ssl_sock->base.type = &ssl_socket_type;
+ ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
+ ssl_sock->o_sock = args[0].u_obj;
+
+ return ssl_sock;
+
+socket_error:
+ mp_raise_OSError(_errno);
+
+arg_error:
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid argument(s) value"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
+
+STATIC const mp_rom_map_elem_t mp_module_ssl_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ssl) },
+ { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
+
+ // class exceptions
+ { MP_ROM_QSTR(MP_QSTR_SSLError), MP_ROM_PTR(&mp_type_OSError) },
+
+ // class constants
+ { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(SSL_CERT_NONE) },
+ { MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(SSL_CERT_OPTIONAL) },
+ { MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(SSL_CERT_REQUIRED) },
+
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_SSLv3), MP_ROM_INT(SL_SO_SEC_METHOD_SSLV3) },
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1) },
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_1) },
+ { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_2), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_2) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(mp_module_ssl_globals, mp_module_ssl_globals_table);
+
+const mp_obj_module_t mp_module_ssl = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&mp_module_ssl_globals,
+};
+
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_ssl, mp_module_ssl);
diff --git a/ports/cc3200/mods/modtime.c b/ports/cc3200/mods/modtime.c
new file mode 100644
index 000000000000..6fa98296d2fb
--- /dev/null
+++ b/ports/cc3200/mods/modtime.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2023 Damien P. George
+ * Copyright (c) 2015 Daniel Campora
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "shared/timeutils/timeutils.h"
+#include "pybrtc.h"
+
+// Return the localtime as an 8-tuple.
+STATIC mp_obj_t mp_time_localtime_get(void) {
+ timeutils_struct_time_t tm;
+
+ // get the seconds from the RTC
+ timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(tm.tm_year),
+ mp_obj_new_int(tm.tm_mon),
+ mp_obj_new_int(tm.tm_mday),
+ mp_obj_new_int(tm.tm_hour),
+ mp_obj_new_int(tm.tm_min),
+ mp_obj_new_int(tm.tm_sec),
+ mp_obj_new_int(tm.tm_wday),
+ mp_obj_new_int(tm.tm_yday)
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+
+// Returns the number of seconds, as an integer, since the Epoch.
+STATIC mp_obj_t mp_time_time_get(void) {
+ return mp_obj_new_int(pyb_rtc_get_seconds());
+}
diff --git a/ports/cc3200/mods/moduhashlib.c b/ports/cc3200/mods/moduhashlib.c
deleted file mode 100644
index 302ff335ff86..000000000000
--- a/ports/cc3200/mods/moduhashlib.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Paul Sokolovsky
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/mpconfig.h"
-#include MICROPY_HAL_H
-#include "py/runtime.h"
-#include "inc/hw_types.h"
-#include "inc/hw_ints.h"
-#include "inc/hw_nvic.h"
-#include "inc/hw_shamd5.h"
-#include "inc/hw_dthe.h"
-#include "hw_memmap.h"
-#include "rom_map.h"
-#include "prcm.h"
-#include "shamd5.h"
-#include "cryptohash.h"
-
-
-/******************************************************************************
- DEFINE PRIVATE TYPES
- ******************************************************************************/
-typedef struct _mp_obj_hash_t {
- mp_obj_base_t base;
- uint8_t *buffer;
- uint32_t b_size;
- uint32_t c_size;
- uint8_t algo;
- uint8_t h_size;
- bool fixedlen;
- bool digested;
- uint8_t hash[32];
-} mp_obj_hash_t;
-
-/******************************************************************************
- DECLARE PRIVATE FUNCTIONS
- ******************************************************************************/
-STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest);
-STATIC mp_obj_t hash_read (mp_obj_t self_in);
-
-/******************************************************************************
- DEFINE PRIVATE FUNCTIONS
- ******************************************************************************/
-STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) {
- mp_obj_hash_t *self = self_in;
- mp_buffer_info_t bufinfo;
-
- if (data) {
- mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
- }
-
- if (digest) {
- CRYPTOHASH_SHAMD5Start (self->algo, self->b_size);
- }
-
- if (self->c_size < self->b_size || !data || !self->fixedlen) {
- if (digest || self->fixedlen) {
- // no data means we want to process our internal buffer
- CRYPTOHASH_SHAMD5Update (data ? bufinfo.buf : self->buffer, data ? bufinfo.len : self->b_size);
- self->c_size += data ? bufinfo.len : 0;
- } else {
- self->buffer = m_renew(byte, self->buffer, self->b_size, self->b_size + bufinfo.len);
- mp_seq_copy((byte*)self->buffer + self->b_size, bufinfo.buf, bufinfo.len, byte);
- self->b_size += bufinfo.len;
- self->digested = false;
- }
- } else {
- mp_raise_OSError(MP_EPERM);
- }
-}
-
-STATIC mp_obj_t hash_read (mp_obj_t self_in) {
- mp_obj_hash_t *self = self_in;
-
- if (!self->fixedlen) {
- if (!self->digested) {
- hash_update_internal(self, MP_OBJ_NULL, true);
- }
- } else if (self->c_size < self->b_size) {
- // it's a fixed len block which is still incomplete
- mp_raise_OSError(MP_EPERM);
- }
-
- if (!self->digested) {
- CRYPTOHASH_SHAMD5Read ((uint8_t *)self->hash);
- self->digested = true;
- }
- return mp_obj_new_bytes(self->hash, self->h_size);
-}
-
-/******************************************************************************/
-// MicroPython bindings
-
-/// \classmethod \constructor([data[, block_size]])
-/// initial data must be given if block_size wants to be passed
-STATIC mp_obj_t hash_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 2, false);
- mp_obj_hash_t *self = m_new0(mp_obj_hash_t, 1);
- self->base.type = type_in;
- if (self->base.type->name == MP_QSTR_sha1) {
- self->algo = SHAMD5_ALGO_SHA1;
- self->h_size = 20;
- } else /* if (self->base.type->name == MP_QSTR_sha256) */ {
- self->algo = SHAMD5_ALGO_SHA256;
- self->h_size = 32;
- } /* else {
- self->algo = SHAMD5_ALGO_MD5;
- self->h_size = 32;
- } */
-
- if (n_args) {
- // CPython extension to avoid buffering the data before digesting it
- // Note: care must be taken to provide all intermediate blocks as multiple
- // of four bytes, otherwise the resulting hash will be incorrect.
- // the final block can be of any length
- if (n_args > 1) {
- // block size given, we will feed the data directly into the hash engine
- self->fixedlen = true;
- self->b_size = mp_obj_get_int(args[1]);
- hash_update_internal(self, args[0], true);
- } else {
- hash_update_internal(self, args[0], false);
- }
- }
- return self;
-}
-
-STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
- mp_obj_hash_t *self = self_in;
- hash_update_internal(self, arg, false);
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
-
-STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
- return hash_read(self_in);
-}
-MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
-
-STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table);
-
-//STATIC const mp_obj_type_t md5_type = {
-// { &mp_type_type },
-// .name = MP_QSTR_md5,
-// .make_new = hash_make_new,
-// .locals_dict = (mp_obj_t)&hash_locals_dict,
-//};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- sha1_type,
- MP_QSTR_sha1,
- MP_TYPE_FLAG_NONE,
- make_new, hash_make_new,
- locals_dict, &hash_locals_dict
- );
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- sha256_type,
- MP_QSTR_sha256,
- MP_TYPE_FLAG_NONE,
- make_new, hash_make_new,
- locals_dict, &hash_locals_dict
- );
-
-STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uhashlib) },
- //{ MP_ROM_QSTR(MP_QSTR_md5), MP_ROM_PTR(&md5_type) },
- { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) },
- { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
-
-const mp_obj_module_t mp_module_uhashlib = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
-};
-
diff --git a/ports/cc3200/mods/moduos.c b/ports/cc3200/mods/moduos.c
deleted file mode 100644
index e284e9eb1ffb..000000000000
--- a/ports/cc3200/mods/moduos.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/objtuple.h"
-#include "py/objstr.h"
-#include "py/runtime.h"
-#include "shared/timeutils/timeutils.h"
-#include "lib/oofatfs/ff.h"
-#include "lib/oofatfs/diskio.h"
-#include "genhdr/mpversion.h"
-#include "moduos.h"
-#include "sflash_diskio.h"
-#include "extmod/vfs.h"
-#include "extmod/vfs_fat.h"
-#include "random.h"
-#include "version.h"
-#include "pybsd.h"
-#include "pybuart.h"
-
-/// \module os - basic "operating system" services
-///
-/// The `os` module contains functions for filesystem access and `urandom`.
-///
-/// The filesystem has `/` as the root directory, and the available physical
-/// drives are accessible from here. They are currently:
-///
-/// /flash -- the serial flash filesystem
-///
-/// On boot up, the current directory is `/flash`.
-
-/******************************************************************************
- DECLARE PRIVATE DATA
- ******************************************************************************/
-STATIC os_term_dup_obj_t os_term_dup_obj;
-
-/******************************************************************************
- DEFINE PUBLIC FUNCTIONS
- ******************************************************************************/
-
-void osmount_unmount_all (void) {
- //TODO
- /*
- for (mp_uint_t i = 0; i < MP_STATE_PORT(mount_obj_list).len; i++) {
- os_fs_mount_t *mount_obj = ((os_fs_mount_t *)(MP_STATE_PORT(mount_obj_list).items[i]));
- unmount(mount_obj);
- }
- */
-}
-
-/******************************************************************************/
-// MicroPython bindings
-//
-
-STATIC const qstr os_uname_info_fields[] = {
- MP_QSTR_sysname, MP_QSTR_nodename,
- MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine
-};
-STATIC const MP_DEFINE_STR_OBJ(os_uname_info_sysname_obj, MICROPY_PY_SYS_PLATFORM);
-STATIC const MP_DEFINE_STR_OBJ(os_uname_info_nodename_obj, MICROPY_PY_SYS_PLATFORM);
-STATIC const MP_DEFINE_STR_OBJ(os_uname_info_release_obj, WIPY_SW_VERSION_NUMBER);
-STATIC const MP_DEFINE_STR_OBJ(os_uname_info_version_obj, MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE);
-STATIC const MP_DEFINE_STR_OBJ(os_uname_info_machine_obj, MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME);
-STATIC MP_DEFINE_ATTRTUPLE(
- os_uname_info_obj,
- os_uname_info_fields,
- 5,
- (mp_obj_t)&os_uname_info_sysname_obj,
- (mp_obj_t)&os_uname_info_nodename_obj,
- (mp_obj_t)&os_uname_info_release_obj,
- (mp_obj_t)&os_uname_info_version_obj,
- (mp_obj_t)&os_uname_info_machine_obj
-);
-
-STATIC mp_obj_t os_uname(void) {
- return (mp_obj_t)&os_uname_info_obj;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname);
-
-STATIC mp_obj_t os_sync(void) {
- sflash_disk_flush();
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_sync_obj, os_sync);
-
-STATIC mp_obj_t os_urandom(mp_obj_t num) {
- mp_int_t n = mp_obj_get_int(num);
- vstr_t vstr;
- vstr_init_len(&vstr, n);
- for (int i = 0; i < n; i++) {
- vstr.buf[i] = rng_get();
- }
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom);
-
-STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
- if (n_args == 0) {
- if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
- return mp_const_none;
- } else {
- return MP_STATE_PORT(os_term_dup_obj)->stream_o;
- }
- } else {
- mp_obj_t stream_o = args[0];
- if (stream_o == mp_const_none) {
- MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
- } else {
- if (!mp_obj_is_type(stream_o, &pyb_uart_type)) {
- // must be a stream-like object providing at least read and write methods
- mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
- mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
- }
- os_term_dup_obj.stream_o = stream_o;
- MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
- }
- return mp_const_none;
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
-
-STATIC const mp_rom_map_elem_t os_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uos) },
-
- { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) },
- { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&mp_vfs_ilistdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&mp_vfs_mkdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&mp_vfs_rename_obj) },
- { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&mp_vfs_remove_obj) },
- { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&mp_vfs_rmdir_obj) },
- { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&mp_vfs_stat_obj) },
- { MP_ROM_QSTR(MP_QSTR_unlink), MP_ROM_PTR(&mp_vfs_remove_obj) }, // unlink aliases to remove
-
- { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&os_sync_obj) },
- { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) },
-
- // MicroPython additions
- // removed: mkfs
- // renamed: unmount -> umount
- { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) },
- { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_vfs_umount_obj) },
- { MP_ROM_QSTR(MP_QSTR_VfsFat), MP_ROM_PTR(&mp_fat_vfs_type) },
- { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
-
-const mp_obj_module_t mp_module_uos = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&os_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_uos, mp_module_uos);
diff --git a/ports/cc3200/mods/moduos.h b/ports/cc3200/mods/moduos.h
deleted file mode 100644
index f183715c907c..000000000000
--- a/ports/cc3200/mods/moduos.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUOS_H
-#define MICROPY_INCLUDED_CC3200_MODS_MODUOS_H
-
-#include "py/obj.h"
-
-/******************************************************************************
- DEFINE PUBLIC TYPES
- ******************************************************************************/
-
-typedef struct _os_term_dup_obj_t {
- mp_obj_t stream_o;
- mp_obj_t read[3];
- mp_obj_t write[3];
-} os_term_dup_obj_t;
-
-/******************************************************************************
- DECLARE PUBLIC FUNCTIONS
- ******************************************************************************/
-void osmount_unmount_all (void);
-
-#endif // MICROPY_INCLUDED_CC3200_MODS_MODUOS_H
diff --git a/ports/cc3200/mods/modusocket.c b/ports/cc3200/mods/modusocket.c
deleted file mode 100644
index cd1489fb4ae5..000000000000
--- a/ports/cc3200/mods/modusocket.c
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "simplelink.h"
-#include "py/mpconfig.h"
-#include "py/obj.h"
-#include "py/objstr.h"
-#include "py/runtime.h"
-#include "py/stream.h"
-#include "py/mphal.h"
-#include "shared/netutils/netutils.h"
-#include "modnetwork.h"
-#include "modusocket.h"
-
-/******************************************************************************/
-// The following set of macros and functions provide a glue between the CC3100
-// simplelink layer and the functions/methods provided by the usocket module.
-// They were historically in a separate file because usocket was designed to
-// work with multiple NICs, and the wlan_XXX functions just provided one
-// particular NIC implementation (that of the CC3100). But the CC3200 port only
-// supports a single NIC (being the CC3100) so it's unnecessary and inefficient
-// to provide an intermediate wrapper layer. Hence the wlan_XXX functions
-// are provided below as static functions so they can be inlined directly by
-// the corresponding usocket calls.
-
-#define WLAN_MAX_RX_SIZE 16000
-#define WLAN_MAX_TX_SIZE 1476
-
-#define MAKE_SOCKADDR(addr, ip, port) SlSockAddr_t addr; \
- addr.sa_family = SL_AF_INET; \
- addr.sa_data[0] = port >> 8; \
- addr.sa_data[1] = port; \
- addr.sa_data[2] = ip[3]; \
- addr.sa_data[3] = ip[2]; \
- addr.sa_data[4] = ip[1]; \
- addr.sa_data[5] = ip[0];
-
-#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
- ip[0] = addr.sa_data[5]; \
- ip[1] = addr.sa_data[4]; \
- ip[2] = addr.sa_data[3]; \
- ip[3] = addr.sa_data[2];
-
-#define SOCKET_TIMEOUT_QUANTA_MS (20)
-
-STATIC int convert_sl_errno(int sl_errno) {
- return -sl_errno;
-}
-
-// This function is left as non-static so it's not inlined.
-int check_timedout(mod_network_socket_obj_t *s, int ret, uint32_t *timeout_ms, int *_errno) {
- if (*timeout_ms == 0 || ret != SL_EAGAIN) {
- if (s->sock_base.timeout_ms > 0 && ret == SL_EAGAIN) {
- *_errno = MP_ETIMEDOUT;
- } else {
- *_errno = convert_sl_errno(ret);
- }
- return -1;
- }
- mp_hal_delay_ms(SOCKET_TIMEOUT_QUANTA_MS);
- if (*timeout_ms < SOCKET_TIMEOUT_QUANTA_MS) {
- *timeout_ms = 0;
- } else {
- *timeout_ms -= SOCKET_TIMEOUT_QUANTA_MS;
- }
- return 0;
-}
-
-STATIC int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) {
- uint32_t ip;
- int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family);
- out_ip[0] = ip;
- out_ip[1] = ip >> 8;
- out_ip[2] = ip >> 16;
- out_ip[3] = ip >> 24;
- return result;
-}
-
-STATIC int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) {
- int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto);
- if (sd < 0) {
- *_errno = sd;
- return -1;
- }
- s->sock_base.sd = sd;
- return 0;
-}
-
-STATIC void wlan_socket_close(mod_network_socket_obj_t *s) {
- // this is to prevent the finalizer to close a socket that failed when being created
- if (s->sock_base.sd >= 0) {
- modusocket_socket_delete(s->sock_base.sd);
- sl_Close(s->sock_base.sd);
- s->sock_base.sd = -1;
- }
-}
-
-STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
- MAKE_SOCKADDR(addr, ip, port)
- int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr));
- if (ret != 0) {
- *_errno = ret;
- return -1;
- }
- return 0;
-}
-
-STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) {
- int ret = sl_Listen(s->sock_base.sd, backlog);
- if (ret != 0) {
- *_errno = ret;
- return -1;
- }
- return 0;
-}
-
-STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) {
- // accept incoming connection
- int16_t sd;
- SlSockAddr_t addr;
- SlSocklen_t addr_len = sizeof(addr);
-
- uint32_t timeout_ms = s->sock_base.timeout_ms;
- for (;;) {
- sd = sl_Accept(s->sock_base.sd, &addr, &addr_len);
- if (sd >= 0) {
- // save the socket descriptor
- s2->sock_base.sd = sd;
- // return ip and port
- UNPACK_SOCKADDR(addr, ip, *port);
- return 0;
- }
- if (check_timedout(s, sd, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) {
- MAKE_SOCKADDR(addr, ip, port)
- uint32_t timeout_ms = s->sock_base.timeout_ms;
-
- // For a non-blocking connect the CC3100 will return SL_EALREADY while the
- // connection is in progress.
-
- for (;;) {
- int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr));
- if (ret == 0) {
- return 0;
- }
-
- // Check if we are in non-blocking mode and the connection is in progress
- if (s->sock_base.timeout_ms == 0 && ret == SL_EALREADY) {
- // To match BSD we return EINPROGRESS here
- *_errno = MP_EINPROGRESS;
- return -1;
- }
-
- // We are in blocking mode, so if the connection isn't in progress then error out
- if (ret != SL_EALREADY) {
- *_errno = convert_sl_errno(ret);
- return -1;
- }
-
- if (check_timedout(s, SL_EAGAIN, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) {
- if (len == 0) {
- return 0;
- }
- uint32_t timeout_ms = s->sock_base.timeout_ms;
- for (;;) {
- int ret = sl_Send(s->sock_base.sd, (const void *)buf, len, 0);
- if (ret > 0) {
- return ret;
- }
- if (check_timedout(s, ret, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) {
- uint32_t timeout_ms = s->sock_base.timeout_ms;
- for (;;) {
- int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0);
- if (ret >= 0) {
- return ret;
- }
- if (check_timedout(s, ret, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
- MAKE_SOCKADDR(addr, ip, port)
- uint32_t timeout_ms = s->sock_base.timeout_ms;
- for (;;) {
- int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr));
- if (ret >= 0) {
- return ret;
- }
- if (check_timedout(s, ret, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
- SlSockAddr_t addr;
- SlSocklen_t addr_len = sizeof(addr);
- uint32_t timeout_ms = s->sock_base.timeout_ms;
- for (;;) {
- int ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len);
- if (ret >= 0) {
- UNPACK_SOCKADDR(addr, ip, *port);
- return ret;
- }
- if (check_timedout(s, ret, &timeout_ms, _errno)) {
- return -1;
- }
- }
-}
-
-STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) {
- int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen);
- if (ret < 0) {
- *_errno = ret;
- return -1;
- }
- return 0;
-}
-
-STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) {
- SlSockNonblocking_t option;
- if (timeout_s == 0 || timeout_s == -1) {
- if (timeout_s == 0) {
- // set non-blocking mode
- option.NonblockingEnabled = 1;
- } else {
- // set blocking mode
- option.NonblockingEnabled = 0;
- }
- timeout_s = 0;
- } else {
- // synthesize timeout via non-blocking behaviour with a loop
- option.NonblockingEnabled = 1;
- }
-
- int ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option));
- if (ret != 0) {
- *_errno = convert_sl_errno(ret);
- return -1;
- }
-
- s->sock_base.timeout_ms = timeout_s * 1000;
- return 0;
-}
-
-STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) {
- mp_int_t ret;
- if (request == MP_STREAM_POLL) {
- mp_uint_t flags = arg;
- ret = 0;
- int32_t sd = s->sock_base.sd;
-
- // init fds
- SlFdSet_t rfds, wfds, xfds;
- SL_FD_ZERO(&rfds);
- SL_FD_ZERO(&wfds);
- SL_FD_ZERO(&xfds);
-
- // set fds if needed
- if (flags & MP_STREAM_POLL_RD) {
- SL_FD_SET(sd, &rfds);
- }
- if (flags & MP_STREAM_POLL_WR) {
- SL_FD_SET(sd, &wfds);
- }
- if (flags & MP_STREAM_POLL_HUP) {
- SL_FD_SET(sd, &xfds);
- }
-
- // call simplelink's select with minimum timeout
- SlTimeval_t tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv);
-
- // check for errors
- if (nfds == -1) {
- *_errno = nfds;
- return -1;
- }
-
- // check return of select
- if (SL_FD_ISSET(sd, &rfds)) {
- ret |= MP_STREAM_POLL_RD;
- }
- if (SL_FD_ISSET(sd, &wfds)) {
- ret |= MP_STREAM_POLL_WR;
- }
- if (SL_FD_ISSET(sd, &xfds)) {
- ret |= MP_STREAM_POLL_HUP;
- }
- } else if (request == MP_STREAM_CLOSE) {
- wlan_socket_close(s);
- ret = 0;
- } else {
- *_errno = MP_EINVAL;
- ret = MP_STREAM_ERROR;
- }
- return ret;
-}
-
-/******************************************************************************
- DEFINE PRIVATE CONSTANTS
- ******************************************************************************/
-#define MOD_NETWORK_MAX_SOCKETS 10
-
-/******************************************************************************
- DEFINE PRIVATE TYPES
- ******************************************************************************/
-typedef struct {
- int16_t sd;
- bool user;
-} modusocket_sock_t;
-
-/******************************************************************************
- DEFINE PRIVATE DATA
- ******************************************************************************/
-STATIC const mp_obj_type_t socket_type;
-STATIC OsiLockObj_t modusocket_LockObj;
-STATIC modusocket_sock_t modusocket_sockets[MOD_NETWORK_MAX_SOCKETS] = {{.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1},
- {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}, {.sd = -1}};
-
-/******************************************************************************
- DEFINE PUBLIC FUNCTIONS
- ******************************************************************************/
-__attribute__ ((section (".boot")))
-void modusocket_pre_init (void) {
- // create the wlan lock
- ASSERT(OSI_OK == sl_LockObjCreate(&modusocket_LockObj, "SockLock"));
- sl_LockObjUnlock (&modusocket_LockObj);
-}
-
-void modusocket_socket_add (int16_t sd, bool user) {
- sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
- for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
- if (modusocket_sockets[i].sd < 0) {
- modusocket_sockets[i].sd = sd;
- modusocket_sockets[i].user = user;
- break;
- }
- }
- sl_LockObjUnlock (&modusocket_LockObj);
-}
-
-void modusocket_socket_delete (int16_t sd) {
- sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
- for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
- if (modusocket_sockets[i].sd == sd) {
- modusocket_sockets[i].sd = -1;
- break;
- }
- }
- sl_LockObjUnlock (&modusocket_LockObj);
-}
-
-void modusocket_enter_sleep (void) {
- SlFdSet_t socketset;
- int16_t maxfd = 0;
-
- for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
- int16_t sd;
- if ((sd = modusocket_sockets[i].sd) >= 0) {
- SL_FD_SET(sd, &socketset);
- maxfd = (maxfd > sd) ? maxfd : sd;
- }
- }
-
- if (maxfd > 0) {
- // wait for any of the sockets to become ready...
- sl_Select(maxfd + 1, &socketset, NULL, NULL, NULL);
- }
-}
-
-void modusocket_close_all_user_sockets (void) {
- sl_LockObjLock (&modusocket_LockObj, SL_OS_WAIT_FOREVER);
- for (int i = 0; i < MOD_NETWORK_MAX_SOCKETS; i++) {
- if (modusocket_sockets[i].sd >= 0 && modusocket_sockets[i].user) {
- sl_Close(modusocket_sockets[i].sd);
- modusocket_sockets[i].sd = -1;
- }
- }
- sl_LockObjUnlock (&modusocket_LockObj);
-}
-
-/******************************************************************************/
-// socket class
-
-// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None)
-STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- mp_arg_check_num(n_args, n_kw, 0, 4, false);
-
- // create socket object
- mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
- s->base.type = (mp_obj_t)&socket_type;
- s->sock_base.u_param.domain = SL_AF_INET;
- s->sock_base.u_param.type = SL_SOCK_STREAM;
- s->sock_base.u_param.proto = SL_IPPROTO_TCP;
- s->sock_base.u_param.fileno = -1;
- s->sock_base.timeout_ms = 0;
- s->sock_base.cert_req = false;
-
- if (n_args > 0) {
- s->sock_base.u_param.domain = mp_obj_get_int(args[0]);
- if (n_args > 1) {
- s->sock_base.u_param.type = mp_obj_get_int(args[1]);
- if (n_args > 2) {
- s->sock_base.u_param.proto = mp_obj_get_int(args[2]);
- if (n_args > 3) {
- s->sock_base.u_param.fileno = mp_obj_get_int(args[3]);
- }
- }
- }
- }
-
- // create the socket
- int _errno;
- if (wlan_socket_socket(s, &_errno) != 0) {
- mp_raise_OSError(-_errno);
- }
- // add the socket to the list
- modusocket_socket_add(s->sock_base.sd, true);
- return s;
-}
-
-// method socket.bind(address)
-STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = self_in;
-
- // get address
- uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
-
- // call the NIC to bind the socket
- int _errno = 0;
- if (wlan_socket_bind(self, ip, port, &_errno) != 0) {
- mp_raise_OSError(-_errno);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
-
-// method socket.listen([backlog])
-STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
- mod_network_socket_obj_t *self = args[0];
-
- int32_t backlog = MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT;
- if (n_args > 1) {
- backlog = mp_obj_get_int(args[1]);
- backlog = (backlog < 0) ? 0 : backlog;
- }
-
- int _errno;
- if (wlan_socket_listen(self, backlog, &_errno) != 0) {
- mp_raise_OSError(-_errno);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
-
-// method socket.accept()
-STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
- mod_network_socket_obj_t *self = self_in;
-
- // create new socket object
- mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
- // the new socket inherits all properties from its parent
- memcpy (socket2, self, sizeof(mod_network_socket_obj_t));
-
- // accept the incoming connection
- uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
- mp_uint_t port = 0;
- int _errno = 0;
- if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
-
- // add the socket to the list
- modusocket_socket_add(socket2->sock_base.sd, true);
-
- // make the return value
- mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
- client->items[0] = socket2;
- client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
- return client;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
-
-// method socket.connect(address)
-STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = self_in;
-
- // get address
- uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
-
- // connect the socket
- int _errno;
- if (wlan_socket_connect(self, ip, port, &_errno) != 0) {
- if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) {
- return mp_const_none;
- }
- mp_raise_OSError(_errno);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
-
-// method socket.send(bytes)
-STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
- mod_network_socket_obj_t *self = self_in;
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
- int _errno;
- mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno);
- if (ret < 0) {
- mp_raise_OSError(_errno);
- }
- return mp_obj_new_int_from_uint(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
-
-// method socket.recv(bufsize)
-STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
- mod_network_socket_obj_t *self = self_in;
- mp_int_t len = mp_obj_get_int(len_in);
- vstr_t vstr;
- vstr_init_len(&vstr, len);
- int _errno;
- mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno);
- if (ret < 0) {
- mp_raise_OSError(_errno);
- }
- if (ret == 0) {
- return mp_const_empty_bytes;
- }
- vstr.len = ret;
- vstr.buf[vstr.len] = '\0';
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
-
-// method socket.sendto(bytes, address)
-STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
- mod_network_socket_obj_t *self = self_in;
-
- // get the data
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
-
- // get address
- uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_LITTLE);
-
- // call the nic to sendto
- int _errno = 0;
- mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
- if (ret < 0) {
- mp_raise_OSError(_errno);
- }
- return mp_obj_new_int(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
-
-// method socket.recvfrom(bufsize)
-STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
- mod_network_socket_obj_t *self = self_in;
- vstr_t vstr;
- vstr_init_len(&vstr, mp_obj_get_int(len_in));
- byte ip[4];
- mp_uint_t port = 0;
- int _errno = 0;
- mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno);
- if (ret < 0) {
- mp_raise_OSError(_errno);
- }
- mp_obj_t tuple[2];
- if (ret == 0) {
- tuple[0] = mp_const_empty_bytes;
- } else {
- vstr.len = ret;
- vstr.buf[vstr.len] = '\0';
- tuple[0] = mp_obj_new_bytes_from_vstr(&vstr);
- }
- tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE);
- return mp_obj_new_tuple(2, tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
-
-// method socket.setsockopt(level, optname, value)
-STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
- mod_network_socket_obj_t *self = args[0];
-
- mp_int_t level = mp_obj_get_int(args[1]);
- mp_int_t opt = mp_obj_get_int(args[2]);
-
- const void *optval;
- mp_uint_t optlen;
- mp_int_t val;
- if (mp_obj_is_integer(args[3])) {
- val = mp_obj_get_int_truncated(args[3]);
- optval = &val;
- optlen = sizeof(val);
- } else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
- optval = bufinfo.buf;
- optlen = bufinfo.len;
- }
-
- int _errno;
- if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
- mp_raise_OSError(-_errno);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
-
-// method socket.settimeout(value)
-// timeout=0 means non-blocking
-// timeout=None means blocking
-// otherwise, timeout is in seconds
-STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
- mod_network_socket_obj_t *self = self_in;
- mp_uint_t timeout;
- if (timeout_in == mp_const_none) {
- timeout = -1;
- } else {
- timeout = mp_obj_get_int(timeout_in);
- }
- int _errno = 0;
- if (wlan_socket_settimeout(self, timeout, &_errno) != 0) {
- mp_raise_OSError(_errno);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
-
-// method socket.setblocking(flag)
-STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
- if (mp_obj_is_true(blocking)) {
- return socket_settimeout(self_in, mp_const_none);
- } else {
- return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-
-STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
- (void)n_args;
- return args[0];
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
-
-STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
- { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
- { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
- { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
- { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
- { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_send_obj) },
- { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
- { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
- { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
- { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
- { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
- { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
-
- // stream methods
- { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read1_obj) },
- { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
- { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
- { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
-};
-
-MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
-
-STATIC mp_uint_t socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
- mod_network_socket_obj_t *self = self_in;
- mp_int_t ret = wlan_socket_recv(self, buf, size, errcode);
- if (ret < 0) {
- // we need to ignore the socket closed error here because a read() without params
- // only returns when the socket is closed by the other end
- if (*errcode != -SL_ESECCLOSED) {
- ret = MP_STREAM_ERROR;
- } else {
- ret = 0;
- }
- }
- return ret;
-}
-
-STATIC mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
- mod_network_socket_obj_t *self = self_in;
- mp_int_t ret = wlan_socket_send(self, buf, size, errcode);
- if (ret < 0) {
- ret = MP_STREAM_ERROR;
- }
- return ret;
-}
-
-STATIC mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
- mod_network_socket_obj_t *self = self_in;
- return wlan_socket_ioctl(self, request, arg, errcode);
-}
-
-const mp_stream_p_t socket_stream_p = {
- .read = socket_read,
- .write = socket_write,
- .ioctl = socket_ioctl,
- .is_text = false,
-};
-
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- socket_type,
- MP_QSTR_socket,
- MP_TYPE_FLAG_NONE,
- make_new, socket_make_new,
- protocol, &socket_stream_p,
- locals_dict, &socket_locals_dict
- );
-
-/******************************************************************************/
-// usocket module
-
-// function usocket.getaddrinfo(host, port)
-/// \function getaddrinfo(host, port)
-STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
- size_t hlen;
- const char *host = mp_obj_str_get_data(host_in, &hlen);
- mp_int_t port = mp_obj_get_int(port_in);
-
- // ipv4 only
- uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE];
- int32_t result = wlan_gethostbyname(host, hlen, out_ip, SL_AF_INET);
- if (result < 0) {
- mp_raise_OSError(-result);
- }
- mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
- tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SL_AF_INET);
- tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SL_SOCK_STREAM);
- tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
- tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
- tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_LITTLE);
- return mp_obj_new_list(1, (mp_obj_t*)&tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo);
-
-STATIC const mp_rom_map_elem_t mp_module_usocket_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
-
- { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
- { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) },
-
- // class constants
- { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(SL_AF_INET) },
-
- { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SL_SOCK_STREAM) },
- { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SL_SOCK_DGRAM) },
-
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_SEC), MP_ROM_INT(SL_SEC_SOCKET) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(SL_IPPROTO_TCP) },
- { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(SL_IPPROTO_UDP) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
-
-const mp_obj_module_t mp_module_usocket = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_usocket, mp_module_usocket);
diff --git a/ports/cc3200/mods/modusocket.h b/ports/cc3200/mods/modusocket.h
deleted file mode 100644
index aaee04ce1927..000000000000
--- a/ports/cc3200/mods/modusocket.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
-#define MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
-
-#include "py/stream.h"
-
-extern const mp_obj_dict_t socket_locals_dict;
-extern const mp_stream_p_t socket_stream_p;
-
-extern void modusocket_pre_init (void);
-extern void modusocket_socket_add (int16_t sd, bool user);
-extern void modusocket_socket_delete (int16_t sd);
-extern void modusocket_enter_sleep (void);
-extern void modusocket_close_all_user_sockets (void);
-
-#endif // MICROPY_INCLUDED_CC3200_MODS_MODUSOCKET_H
diff --git a/ports/cc3200/mods/modussl.c b/ports/cc3200/mods/modussl.c
deleted file mode 100644
index 118cbd06f8fa..000000000000
--- a/ports/cc3200/mods/modussl.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-
-#include "simplelink.h"
-#include "py/mpconfig.h"
-#include "py/obj.h"
-#include "py/objstr.h"
-#include "py/runtime.h"
-#include "modnetwork.h"
-#include "modusocket.h"
-
-/******************************************************************************
- DEFINE CONSTANTS
- ******************************************************************************/
-#define SSL_CERT_NONE (0)
-#define SSL_CERT_OPTIONAL (1)
-#define SSL_CERT_REQUIRED (2)
-
-/******************************************************************************
- DEFINE TYPES
- ******************************************************************************/
-typedef struct _mp_obj_ssl_socket_t {
- mp_obj_base_t base;
- mod_network_socket_base_t sock_base;
- mp_obj_t o_sock;
-} mp_obj_ssl_socket_t;
-
-/******************************************************************************
- DECLARE PRIVATE DATA
- ******************************************************************************/
-STATIC const mp_obj_type_t ssl_socket_type;
-
-/******************************************************************************/
-// MicroPython bindings; SSL class
-
-// ssl sockets inherit from normal socket, so we take its
-// locals and stream methods
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
- ssl_socket_type,
- MP_QSTR_ussl,
- MP_TYPE_FLAG_NONE,
- protocol, &socket_stream_p,
- locals_dict, &socket_locals_dict
- );
-
-STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- STATIC const mp_arg_t allowed_args[] = {
- { MP_QSTR_sock, MP_ARG_REQUIRED | MP_ARG_OBJ, },
- { MP_QSTR_keyfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
- { MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} },
- { MP_QSTR_ssl_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SO_SEC_METHOD_TLSV1} },
- { MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- };
-
- // parse arguments
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- // check if ca validation is required
- if (args[4].u_int != SSL_CERT_NONE && args[6].u_obj == mp_const_none) {
- goto arg_error;
- }
-
- // retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
- const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
- const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
- const char *cafile = (args[6].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
- NULL : &(mp_obj_str_get_str(args[6].u_obj)[6]);
-
- // server side requires both certfile and keyfile
- if (args[3].u_bool && (!keyfile || !certfile)) {
- goto arg_error;
- }
-
- _i16 _errno;
- _i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
-
- // set the requested SSL method
- _u8 method = args[5].u_int;
- if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) {
- goto socket_error;
- }
- if (keyfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME, keyfile, strlen(keyfile))) < 0) {
- goto socket_error;
- }
- if (certfile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME, certfile, strlen(certfile))) < 0) {
- goto socket_error;
- }
- if (cafile && (_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECURE_FILES_CA_FILE_NAME, cafile, strlen(cafile))) < 0) {
- goto socket_error;
- }
-
- // create the ssl socket
- mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
- // ssl sockets inherit all properties from the original socket
- memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
- ssl_sock->base.type = &ssl_socket_type;
- ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
- ssl_sock->o_sock = args[0].u_obj;
-
- return ssl_sock;
-
-socket_error:
- mp_raise_OSError(_errno);
-
-arg_error:
- mp_raise_ValueError(MP_ERROR_TEXT("invalid argument(s) value"));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
-
-STATIC const mp_rom_map_elem_t mp_module_ussl_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ussl) },
- { MP_ROM_QSTR(MP_QSTR_wrap_socket), MP_ROM_PTR(&mod_ssl_wrap_socket_obj) },
-
- // class exceptions
- { MP_ROM_QSTR(MP_QSTR_SSLError), MP_ROM_PTR(&mp_type_OSError) },
-
- // class constants
- { MP_ROM_QSTR(MP_QSTR_CERT_NONE), MP_ROM_INT(SSL_CERT_NONE) },
- { MP_ROM_QSTR(MP_QSTR_CERT_OPTIONAL), MP_ROM_INT(SSL_CERT_OPTIONAL) },
- { MP_ROM_QSTR(MP_QSTR_CERT_REQUIRED), MP_ROM_INT(SSL_CERT_REQUIRED) },
-
- { MP_ROM_QSTR(MP_QSTR_PROTOCOL_SSLv3), MP_ROM_INT(SL_SO_SEC_METHOD_SSLV3) },
- { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1) },
- { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_1), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_1) },
- { MP_ROM_QSTR(MP_QSTR_PROTOCOL_TLSv1_2), MP_ROM_INT(SL_SO_SEC_METHOD_TLSV1_2) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_ussl_globals, mp_module_ussl_globals_table);
-
-const mp_obj_module_t mp_module_ussl = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&mp_module_ussl_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_ussl, mp_module_ussl);
diff --git a/ports/cc3200/mods/modutime.c b/ports/cc3200/mods/modutime.c
deleted file mode 100644
index 237a80065057..000000000000
--- a/ports/cc3200/mods/modutime.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2015 Daniel Campora
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/mpconfig.h"
-#include "py/runtime.h"
-#include "py/obj.h"
-#include "py/smallint.h"
-#include "py/mphal.h"
-#include "shared/timeutils/timeutils.h"
-#include "extmod/utime_mphal.h"
-#include "inc/hw_types.h"
-#include "inc/hw_ints.h"
-#include "inc/hw_memmap.h"
-#include "rom_map.h"
-#include "prcm.h"
-#include "systick.h"
-#include "pybrtc.h"
-#include "utils.h"
-
-/// \module time - time related functions
-///
-/// The `time` module provides functions for getting the current time and date,
-/// and for sleeping.
-
-/******************************************************************************/
-// MicroPython bindings
-
-/// \function localtime([secs])
-/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
-/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
-/// If secs is not provided or None, then the current time from the RTC is used.
-/// year includes the century (for example 2015)
-/// month is 1-12
-/// mday is 1-31
-/// hour is 0-23
-/// minute is 0-59
-/// second is 0-59
-/// weekday is 0-6 for Mon-Sun.
-/// yearday is 1-366
-STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
- if (n_args == 0 || args[0] == mp_const_none) {
- timeutils_struct_time_t tm;
-
- // get the seconds from the RTC
- timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
- mp_obj_t tuple[8] = {
- mp_obj_new_int(tm.tm_year),
- mp_obj_new_int(tm.tm_mon),
- mp_obj_new_int(tm.tm_mday),
- mp_obj_new_int(tm.tm_hour),
- mp_obj_new_int(tm.tm_min),
- mp_obj_new_int(tm.tm_sec),
- mp_obj_new_int(tm.tm_wday),
- mp_obj_new_int(tm.tm_yday)
- };
- return mp_obj_new_tuple(8, tuple);
- } else {
- mp_int_t seconds = mp_obj_get_int(args[0]);
- timeutils_struct_time_t tm;
- timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
- mp_obj_t tuple[8] = {
- tuple[0] = mp_obj_new_int(tm.tm_year),
- tuple[1] = mp_obj_new_int(tm.tm_mon),
- tuple[2] = mp_obj_new_int(tm.tm_mday),
- tuple[3] = mp_obj_new_int(tm.tm_hour),
- tuple[4] = mp_obj_new_int(tm.tm_min),
- tuple[5] = mp_obj_new_int(tm.tm_sec),
- tuple[6] = mp_obj_new_int(tm.tm_wday),
- tuple[7] = mp_obj_new_int(tm.tm_yday),
- };
- return mp_obj_new_tuple(8, tuple);
- }
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
-
-STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
- size_t len;
- mp_obj_t *elem;
-
- mp_obj_get_array(tuple, &len, &elem);
-
- // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
- if (len < 8 || len > 9) {
- mp_raise_TypeError(MP_ERROR_TEXT("invalid argument(s) num/type"));
- }
-
- return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]),
- mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
-}
-MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
-
-STATIC mp_obj_t time_time(void) {
- return mp_obj_new_int(pyb_rtc_get_seconds());
-}
-MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
-
-STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) {
- int32_t sleep_s = mp_obj_get_int(seconds_o);
- if (sleep_s > 0) {
- mp_hal_delay_ms(sleep_s * 1000);
- }
- return mp_const_none;
-}
-MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep);
-
-STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
-
- { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
- { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&time_sleep_obj) },
-
- // MicroPython additions
- { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
-
-const mp_obj_module_t mp_module_utime = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&time_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_utime, mp_module_utime);
diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c
index 6cf1cbee4e41..8d98dd0421de 100644
--- a/ports/cc3200/mods/modwlan.c
+++ b/ports/cc3200/mods/modwlan.c
@@ -38,7 +38,7 @@
#include "shared/timeutils/timeutils.h"
#include "shared/netutils/netutils.h"
#include "modnetwork.h"
-#include "modusocket.h"
+#include "modsocket.h"
#include "modwlan.h"
#include "pybrtc.h"
#include "debug.h"
@@ -432,7 +432,7 @@ void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth
// switch to the requested mode
wlan_set_mode(mode);
- // stop and start again (we need to in the propper mode from now on)
+ // stop and start again (we need to be in the proper mode from now on)
wlan_reenable(mode);
// Set Tx power level for station or AP mode
@@ -608,7 +608,7 @@ STATIC void wlan_set_ssid (const char *ssid, uint8_t len, bool add_mac) {
// save the ssid
memcpy(&wlan_obj.ssid, ssid, len);
// append the last 2 bytes of the MAC address, since the use of this functionality is under our control
- // we can assume that the lenght of the ssid is less than (32 - 5)
+ // we can assume that the length of the ssid is less than (32 - 5)
if (add_mac) {
snprintf((char *)&wlan_obj.ssid[len], sizeof(wlan_obj.ssid) - len, "-%02x%02x", wlan_obj.mac[4], wlan_obj.mac[5]);
len += 5;
@@ -1285,18 +1285,14 @@ STATIC const mp_rom_map_elem_t wlan_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(wlan_locals_dict, wlan_locals_dict_table);
-STATIC MP_DEFINE_CONST_OBJ_FULL_TYPE(
- mod_network_nic_type_wlan_base,
+MP_DEFINE_CONST_OBJ_TYPE(
+ mod_network_nic_type_wlan,
MP_QSTR_WLAN,
MP_TYPE_FLAG_NONE,
make_new, wlan_make_new,
locals_dict, &wlan_locals_dict
);
-const mod_network_nic_type_t mod_network_nic_type_wlan = {
- .base = mod_network_nic_type_wlan_base,
-};
-
STATIC const mp_irq_methods_t wlan_irq_methods = {
.init = wlan_irq,
.enable = wlan_lpds_irq_enable,
diff --git a/ports/cc3200/mods/pybpin.c b/ports/cc3200/mods/pybpin.c
index f04ca756540e..6d10abab570f 100644
--- a/ports/cc3200/mods/pybpin.c
+++ b/ports/cc3200/mods/pybpin.c
@@ -113,7 +113,7 @@ STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] =
DEFINE PUBLIC FUNCTIONS
******************************************************************************/
void pin_init0(void) {
-// this initalization also reconfigures the JTAG/SWD pins
+// this initialization also reconfigures the JTAG/SWD pins
#ifndef DEBUG
// assign all pins to the GPIO module so that peripherals can be connected to any
// pins without conflicts after a soft reset
@@ -560,7 +560,7 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, size_t n_args, const mp_obj
}
}
- // get the strenght
+ // get the strength
uint strength = args[3].u_int;
pin_validate_drive(strength);
diff --git a/ports/cc3200/mods/pybrtc.c b/ports/cc3200/mods/pybrtc.c
index 21e729dbf175..e79fb29d00d0 100644
--- a/ports/cc3200/mods/pybrtc.c
+++ b/ports/cc3200/mods/pybrtc.c
@@ -76,7 +76,7 @@ STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
******************************************************************************/
__attribute__ ((section (".boot")))
void pyb_rtc_pre_init(void) {
- // only if comming out of a power-on reset
+ // only if coming out of a power-on reset
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
// Mark the RTC in use first
MAP_PRCMRTCInUseSet();
@@ -118,7 +118,7 @@ void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
pyb_rtc_get_time(&c_seconds, &c_mseconds);
- // substract the time elapsed between waking up and setting up the alarm again
+ // subtract the time elapsed between waking up and setting up the alarm again
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
int32_t next_alarm = self->alarm_ms - wake_ms;
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
diff --git a/ports/cc3200/mods/pybsd.c b/ports/cc3200/mods/pybsd.c
index 209c3b5a85ec..952a117c4580 100644
--- a/ports/cc3200/mods/pybsd.c
+++ b/ports/cc3200/mods/pybsd.c
@@ -71,7 +71,7 @@ STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in);
/******************************************************************************
DEFINE PRIVATE FUNCTIONS
******************************************************************************/
-/// Initalizes the sd card hardware driver
+/// Initializes the sd card hardware driver
STATIC void pyb_sd_hw_init (pybsd_obj_t *self) {
if (self->pin_clk) {
// Configure the clock pin as output only
diff --git a/ports/cc3200/mods/pybsleep.c b/ports/cc3200/mods/pybsleep.c
index ffb281e6b13d..ea2642c26094 100644
--- a/ports/cc3200/mods/pybsleep.c
+++ b/ports/cc3200/mods/pybsleep.c
@@ -160,13 +160,13 @@ void pyb_sleep_init0 (void) {
// register and enable the PRCM interrupt
osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
- // disable all LPDS and hibernate wake up sources (WLAN is disabed/enabled before entering LDPS mode)
+ // disable all LPDS and hibernate wake up sources (WLAN is disabled/enabled before entering LDPS mode)
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
- // check the reset casue (if it's soft reset, leave it as it is)
+ // check the reset cause (if it's soft reset, leave it as it is)
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
switch (MAP_PRCMSysResetCauseGet()) {
case PRCM_POWER_ON:
diff --git a/ports/cc3200/mods/pybuart.c b/ports/cc3200/mods/pybuart.c
index 424ca251ec79..5d6ad075275d 100644
--- a/ports/cc3200/mods/pybuart.c
+++ b/ports/cc3200/mods/pybuart.c
@@ -50,7 +50,7 @@
#include "pin.h"
#include "pybpin.h"
#include "pins.h"
-#include "moduos.h"
+#include "modos.h"
/// \moduleref pyb
/// \class UART - duplex serial communication bus
diff --git a/ports/cc3200/mpconfigport.h b/ports/cc3200/mpconfigport.h
index 93fc291c1a4c..b6b412f178f3 100644
--- a/ports/cc3200/mpconfigport.h
+++ b/ports/cc3200/mpconfigport.h
@@ -71,7 +71,6 @@
#define MICROPY_FATFS_SYNC_T SemaphoreHandle_t
#define MICROPY_STREAMS_NON_BLOCK (1)
-#define MICROPY_MODULE_WEAK_LINKS (1)
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
#define MICROPY_USE_INTERNAL_ERRNO (1)
#define MICROPY_VFS (1)
@@ -105,26 +104,29 @@
#define MICROPY_PY_SYS_STDFILES (1)
#define MICROPY_PY_CMATH (0)
#define MICROPY_PY_IO (1)
-#define MICROPY_PY_UERRNO (1)
-#define MICROPY_PY_UERRNO_ERRORCODE (0)
+#define MICROPY_PY_ERRNO (1)
+#define MICROPY_PY_ERRNO_ERRORCODE (0)
#define MICROPY_PY_THREAD (1)
#define MICROPY_PY_THREAD_GIL (1)
-#define MICROPY_PY_UBINASCII (1)
+#define MICROPY_PY_BINASCII (1)
#define MICROPY_PY_UCTYPES (0)
-#define MICROPY_PY_UZLIB (0)
-#define MICROPY_PY_UJSON (1)
-#define MICROPY_PY_URE (1)
-#define MICROPY_PY_UHEAPQ (0)
-#define MICROPY_PY_UHASHLIB (0)
-#define MICROPY_PY_USELECT (1)
-#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_DEFLATE (0)
+#define MICROPY_PY_JSON (1)
+#define MICROPY_PY_RE (1)
+#define MICROPY_PY_HEAPQ (0)
+#define MICROPY_PY_HASHLIB (0)
+#define MICROPY_PY_SELECT (1)
+#define MICROPY_PY_TIME (1)
+#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
+#define MICROPY_PY_TIME_TIME_TIME_NS (1)
+#define MICROPY_PY_TIME_INCLUDEFILE "ports/cc3200/mods/modtime.c"
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (0)
#define MICROPY_KBD_EXCEPTION (1)
-// We define our own list of errno constants to include in uerrno module
-#define MICROPY_PY_UERRNO_LIST \
+// We define our own list of errno constants to include in errno module
+#define MICROPY_PY_ERRNO_LIST \
X(EPERM) \
X(EIO) \
X(ENODEV) \
@@ -133,7 +135,7 @@
// extra constants
#define MICROPY_PORT_CONSTANTS \
- { MP_ROM_QSTR(MP_QSTR_umachine), MP_ROM_PTR(&mp_module_machine) }, \
+ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
#define MP_STATE_PORT MP_STATE_VM
diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c
index 81f00e5384f0..abf8484b0d42 100644
--- a/ports/cc3200/mptask.c
+++ b/ports/cc3200/mptask.c
@@ -55,7 +55,7 @@
#include "mperror.h"
#include "simplelink.h"
#include "modnetwork.h"
-#include "modusocket.h"
+#include "modsocket.h"
#include "modwlan.h"
#include "serverstask.h"
#include "telnet.h"
@@ -70,7 +70,7 @@
#include "cryptohash.h"
#include "mpirq.h"
#include "updater.h"
-#include "moduos.h"
+#include "modos.h"
#include "antenna.h"
#include "task.h"
@@ -158,7 +158,7 @@ void TASK_MicroPython(void *pvParameters) {
// to enable simplelink and leave it as is
wlan_first_start();
} else {
- // only if not comming out of hibernate or a soft reset
+ // only if not coming out of hibernate or a soft reset
mptask_enter_ap_mode();
}
@@ -315,7 +315,7 @@ STATIC void mptask_init_sflash_filesystem(void) {
// create empty main.py
mptask_create_main_py();
} else if (res == FR_OK) {
- // mount sucessful
+ // mount successful
if (FR_OK != f_stat(&vfs_fat->fatfs, "/main.py", &fno)) {
// create empty main.py
mptask_create_main_py();
diff --git a/ports/cc3200/serverstask.c b/ports/cc3200/serverstask.c
index 03eed8eeb0cf..de782f5e7acd 100644
--- a/ports/cc3200/serverstask.c
+++ b/ports/cc3200/serverstask.c
@@ -37,7 +37,7 @@
#include "telnet.h"
#include "ftp.h"
#include "pybwdt.h"
-#include "modusocket.h"
+#include "modsocket.h"
#include "modnetwork.h"
#include "modwlan.h"
@@ -111,7 +111,7 @@ void TASK_Servers(void *pvParameters) {
ftp_reset();
}
// and we should also close all user sockets. We do it here
- // for convinience and to save on code size.
+ // for convenience and to save on code size.
modusocket_close_all_user_sockets();
}
diff --git a/ports/cc3200/telnet/telnet.c b/ports/cc3200/telnet/telnet.c
index c4daac3426d1..86843c78f6c9 100644
--- a/ports/cc3200/telnet/telnet.c
+++ b/ports/cc3200/telnet/telnet.c
@@ -33,7 +33,7 @@
#include "simplelink.h"
#include "modnetwork.h"
#include "modwlan.h"
-#include "modusocket.h"
+#include "modsocket.h"
#include "debug.h"
#include "serverstask.h"
#include "genhdr/mpversion.h"
@@ -407,7 +407,7 @@ static void telnet_process (void) {
_i16 rxLen;
_i16 maxLen = (telnet_data.rxWindex >= telnet_data.rxRindex) ? (TELNET_RX_BUFFER_SIZE - telnet_data.rxWindex) :
((telnet_data.rxRindex - telnet_data.rxWindex) - 1);
- // to avoid an overrrun
+ // to avoid an overrun
maxLen = (telnet_data.rxRindex == 0) ? (maxLen - 1) : maxLen;
if (maxLen > 0) {
diff --git a/ports/cc3200/tools/uniflash.py b/ports/cc3200/tools/uniflash.py
index 0ce9d0703a79..83445a12d343 100644
--- a/ports/cc3200/tools/uniflash.py
+++ b/ports/cc3200/tools/uniflash.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
-"""
+r"""
Flash the WiPy (format, update service pack and program).
Example:
diff --git a/ports/cc3200/tools/update-wipy.py b/ports/cc3200/tools/update-wipy.py
index e0e1266f7a37..7f5527a52bb5 100644
--- a/ports/cc3200/tools/update-wipy.py
+++ b/ports/cc3200/tools/update-wipy.py
@@ -45,7 +45,7 @@ def transfer_file(args):
if "250" in ftp.cwd("/flash"):
if not ftp_directory_exists(ftp, "sys"):
print("/flash/sys directory does not exist")
- if not "550" in ftp.mkd("sys"):
+ if "550" not in ftp.mkd("sys"):
print("/flash/sys directory created")
else:
print("Error: cannot create /flash/sys directory")
@@ -109,7 +109,7 @@ def reset_board(args):
finally:
try:
tn.close()
- except Exception as e:
+ except Exception:
pass
return success
@@ -167,7 +167,7 @@ def find_tag(tag):
finally:
try:
tn.close()
- except Exception as e:
+ except Exception:
pass
return success
diff --git a/ports/cc3200/util/cryptohash.c b/ports/cc3200/util/cryptohash.c
index 909dadc8cf40..ebf12e6e36fe 100644
--- a/ports/cc3200/util/cryptohash.c
+++ b/ports/cc3200/util/cryptohash.c
@@ -59,7 +59,7 @@ void CRYPTOHASH_SHAMD5Start (uint32_t algo, uint32_t blocklen) {
HWREG(SHAMD5_BASE + SHAMD5_O_MODE) |= SHAMD5_MODE_CLOSE_HASH;
}
- // set the lenght
+ // set the length
HWREG(SHAMD5_BASE + SHAMD5_O_LENGTH) = blocklen;
}
diff --git a/ports/embed/README.md b/ports/embed/README.md
new file mode 100644
index 000000000000..556cfc749d37
--- /dev/null
+++ b/ports/embed/README.md
@@ -0,0 +1,18 @@
+MicroPython embed port
+======================
+
+This is a port of MicroPython that outputs a set of .c and .h files for embedding
+into a wider project. This port essentially targets the C language, instead of a
+particular hardware architecture or platform.
+
+To use this port in a project there are three main steps:
+
+1. Provide configuration for the project via an `mpconfigport.h` file.
+
+2. Build this embed port against that configuration, using the provided `embed.mk`.
+ The output is a set of self-contained source files for building MicroPython.
+ These files can be placed outside this repository.
+
+3. Build the project. This requires compiling all .c files from the above step.
+
+See `examples/embedding` for an example.
diff --git a/ports/embed/embed.mk b/ports/embed/embed.mk
new file mode 100644
index 000000000000..84d45accd2d7
--- /dev/null
+++ b/ports/embed/embed.mk
@@ -0,0 +1,65 @@
+# This file is part of the MicroPython project, http://micropython.org/
+# The MIT License (MIT)
+# Copyright (c) 2022-2023 Damien P. George
+#
+# This file is intended to be included by a Makefile in a custom project.
+
+# Set the build output directory for the generated files.
+BUILD = build-embed
+
+# Include the core environment definitions; this will set $(TOP).
+include $(MICROPYTHON_TOP)/py/mkenv.mk
+
+# Include py core make definitions.
+include $(TOP)/py/py.mk
+
+# Set the location of the MicroPython embed port.
+MICROPYTHON_EMBED_PORT = $(MICROPYTHON_TOP)/ports/embed
+
+# Set default makefile-level MicroPython feature configurations.
+MICROPY_ROM_TEXT_COMPRESSION ?= 0
+
+# Set CFLAGS for the MicroPython build.
+CFLAGS += -I. -I$(TOP) -I$(BUILD) -I$(MICROPYTHON_EMBED_PORT)
+CFLAGS += -Wall -Werror -std=c99
+
+# Define the required generated header files.
+GENHDR_OUTPUT = $(addprefix $(BUILD)/genhdr/, \
+ moduledefs.h \
+ mpversion.h \
+ qstrdefs.generated.h \
+ root_pointers.h \
+ )
+
+# Define the top-level target, the generated output files.
+.PHONY: all
+all: micropython-embed-package
+
+clean: clean-micropython-embed-package
+
+.PHONY: clean-micropython-embed-package
+clean-micropython-embed-package:
+ $(RM) -rf $(PACKAGE_DIR)
+
+PACKAGE_DIR ?= micropython_embed
+PACKAGE_DIR_LIST = $(addprefix $(PACKAGE_DIR)/,py extmod shared/runtime genhdr port)
+
+.PHONY: micropython-embed-package
+micropython-embed-package: $(GENHDR_OUTPUT)
+ $(ECHO) "Generate micropython_embed output:"
+ $(Q)$(RM) -rf $(PACKAGE_DIR_LIST)
+ $(Q)$(MKDIR) -p $(PACKAGE_DIR_LIST)
+ $(ECHO) "- py"
+ $(Q)$(CP) $(TOP)/py/*.[ch] $(PACKAGE_DIR)/py
+ $(ECHO) "- extmod"
+ $(Q)$(CP) $(TOP)/extmod/modplatform.h $(PACKAGE_DIR)/extmod
+ $(ECHO) "- shared"
+ $(Q)$(CP) $(TOP)/shared/runtime/gchelper.h $(PACKAGE_DIR)/shared/runtime
+ $(Q)$(CP) $(TOP)/shared/runtime/gchelper_generic.c $(PACKAGE_DIR)/shared/runtime
+ $(ECHO) "- genhdr"
+ $(Q)$(CP) $(GENHDR_OUTPUT) $(PACKAGE_DIR)/genhdr
+ $(ECHO) "- port"
+ $(Q)$(CP) $(MICROPYTHON_EMBED_PORT)/port/*.[ch] $(PACKAGE_DIR)/port
+
+# Include remaining core make rules.
+include $(TOP)/py/mkrules.mk
diff --git a/ports/embed/port/embed_util.c b/ports/embed/port/embed_util.c
new file mode 100644
index 000000000000..14f50897705e
--- /dev/null
+++ b/ports/embed/port/embed_util.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/compile.h"
+#include "py/gc.h"
+#include "py/persistentcode.h"
+#include "py/runtime.h"
+#include "py/stackctrl.h"
+#include "shared/runtime/gchelper.h"
+#include "port/micropython_embed.h"
+
+// Initialise the runtime.
+void mp_embed_init(void *gc_heap, size_t gc_heap_size) {
+ mp_stack_ctrl_init();
+ gc_init(gc_heap, (uint8_t *)gc_heap + gc_heap_size);
+ mp_init();
+}
+
+#if MICROPY_ENABLE_COMPILER
+// Compile and execute the given source script (Python text).
+void mp_embed_exec_str(const char *src) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ // Compile, parse and execute the given string.
+ mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
+ qstr source_name = lex->source_name;
+ mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT);
+ mp_obj_t module_fun = mp_compile(&parse_tree, source_name, true);
+ mp_call_function_0(module_fun);
+ nlr_pop();
+ } else {
+ // Uncaught exception: print it out.
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
+ }
+}
+#endif
+
+#if MICROPY_PERSISTENT_CODE_LOAD
+void mp_embed_exec_mpy(const uint8_t *mpy, size_t len) {
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ // Execute the given .mpy data.
+ mp_module_context_t *ctx = m_new_obj(mp_module_context_t);
+ ctx->module.globals = mp_globals_get();
+ mp_compiled_module_t cm;
+ cm.context = ctx;
+ mp_raw_code_load_mem(mpy, len, &cm);
+ mp_obj_t f = mp_make_function_from_raw_code(cm.rc, ctx, MP_OBJ_NULL);
+ mp_call_function_0(f);
+ nlr_pop();
+ } else {
+ // Uncaught exception: print it out.
+ mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
+ }
+}
+#endif
+
+// Deinitialise the runtime.
+void mp_embed_deinit(void) {
+ mp_deinit();
+}
+
+#if MICROPY_ENABLE_GC
+// Run a garbage collection cycle.
+void gc_collect(void) {
+ gc_collect_start();
+ gc_helper_collect_regs_and_stack();
+ gc_collect_end();
+}
+#endif
+
+// Called if an exception is raised outside all C exception-catching handlers.
+void nlr_jump_fail(void *val) {
+ for (;;) {
+ }
+}
+
+#ifndef NDEBUG
+// Used when debugging is enabled.
+void __assert_func(const char *file, int line, const char *func, const char *expr) {
+ for (;;) {
+ }
+}
+#endif
diff --git a/ports/embed/port/micropython_embed.h b/ports/embed/port/micropython_embed.h
new file mode 100644
index 000000000000..bf55d9b2b445
--- /dev/null
+++ b/ports/embed/port/micropython_embed.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_MICROPYTHON_EMBED_H
+#define MICROPY_INCLUDED_MICROPYTHON_EMBED_H
+
+#include
+#include
+
+void mp_embed_init(void *gc_heap, size_t gc_heap_size);
+void mp_embed_deinit(void);
+
+// Only available if MICROPY_ENABLE_COMPILER is enabled.
+void mp_embed_exec_str(const char *src);
+
+// Only available if MICROPY_PERSISTENT_CODE_LOAD is enabled.
+void mp_embed_exec_mpy(const uint8_t *mpy, size_t len);
+
+#endif // MICROPY_INCLUDED_MICROPYTHON_EMBED_H
diff --git a/ports/embed/port/mpconfigport_common.h b/ports/embed/port/mpconfigport_common.h
new file mode 100644
index 000000000000..69216a758268
--- /dev/null
+++ b/ports/embed/port/mpconfigport_common.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+// Type definitions for the specific machine
+
+typedef intptr_t mp_int_t; // must be pointer size
+typedef uintptr_t mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+
+// Need to provide a declaration/definition of alloca()
+#include
+
+#define MICROPY_MPHALPORT_H "port/mphalport.h"
diff --git a/ports/embed/port/mphalport.c b/ports/embed/port/mphalport.c
new file mode 100644
index 000000000000..8e76a8e22e1b
--- /dev/null
+++ b/ports/embed/port/mphalport.c
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/mphal.h"
+
+// Send string of given length to stdout, converting \n to \r\n.
+void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) {
+ printf("%.*s", (int)len, str);
+}
diff --git a/ports/embed/port/mphalport.h b/ports/embed/port/mphalport.h
new file mode 100644
index 000000000000..49928e154da3
--- /dev/null
+++ b/ports/embed/port/mphalport.h
@@ -0,0 +1,2 @@
+// Define so there's no dependency on extmod/virtpin.h
+#define mp_hal_pin_obj_t
diff --git a/ports/esp32/.gitignore b/ports/esp32/.gitignore
new file mode 100644
index 000000000000..a78ecd0191c9
--- /dev/null
+++ b/ports/esp32/.gitignore
@@ -0,0 +1,2 @@
+dependencies.lock
+managed_components/
diff --git a/ports/esp32/CMakeLists.txt b/ports/esp32/CMakeLists.txt
index 7209dd96da4a..4e29e9610945 100644
--- a/ports/esp32/CMakeLists.txt
+++ b/ports/esp32/CMakeLists.txt
@@ -2,9 +2,6 @@
cmake_minimum_required(VERSION 3.12)
-# Set the location of this port's directory.
-set(MICROPY_PORT_DIR ${CMAKE_SOURCE_DIR})
-
# Set the board if it's not already set.
if(NOT MICROPY_BOARD)
set(MICROPY_BOARD GENERIC)
@@ -12,22 +9,21 @@ endif()
# Set the board directory and check that it exists.
if(NOT MICROPY_BOARD_DIR)
- set(MICROPY_BOARD_DIR ${MICROPY_PORT_DIR}/boards/${MICROPY_BOARD})
+ set(MICROPY_BOARD_DIR ${CMAKE_CURRENT_LIST_DIR}/boards/${MICROPY_BOARD})
endif()
if(NOT EXISTS ${MICROPY_BOARD_DIR}/mpconfigboard.cmake)
message(FATAL_ERROR "Invalid MICROPY_BOARD specified: ${MICROPY_BOARD}")
endif()
-# Include main IDF cmake file.
-include($ENV{IDF_PATH}/tools/cmake/project.cmake)
-
# Define the output sdkconfig so it goes in the build directory.
set(SDKCONFIG ${CMAKE_BINARY_DIR}/sdkconfig)
# Save the manifest file set from the cmake command line.
set(MICROPY_USER_FROZEN_MANIFEST ${MICROPY_FROZEN_MANIFEST})
-# Include board config; this is expected to set SDKCONFIG_DEFAULTS (among other options).
+# Include board config; this is expected to set (among other options):
+# - SDKCONFIG_DEFAULTS
+# - IDF_TARGET
include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake)
# Set the frozen manifest file. Note if MICROPY_FROZEN_MANIFEST is set from the cmake
@@ -35,14 +31,7 @@ include(${MICROPY_BOARD_DIR}/mpconfigboard.cmake)
if (MICROPY_USER_FROZEN_MANIFEST)
set(MICROPY_FROZEN_MANIFEST ${MICROPY_USER_FROZEN_MANIFEST})
elseif (NOT MICROPY_FROZEN_MANIFEST)
- set(MICROPY_FROZEN_MANIFEST ${MICROPY_PORT_DIR}/boards/manifest.py)
-endif()
-
-# Add sdkconfig fragments that depend on the IDF version.
-if(IDF_VERSION_MAJOR EQUAL 4 AND IDF_VERSION_MINOR LESS 2)
- set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/sdkconfig.nimble_core0)
-else()
- set(SDKCONFIG_DEFAULTS ${SDKCONFIG_DEFAULTS} boards/sdkconfig.nimble_core1)
+ set(MICROPY_FROZEN_MANIFEST ${CMAKE_CURRENT_LIST_DIR}/boards/manifest.py)
endif()
# Concatenate all sdkconfig files into a combined one for the IDF to use.
@@ -54,5 +43,11 @@ endforeach()
configure_file(${CMAKE_BINARY_DIR}/sdkconfig.combined.in ${CMAKE_BINARY_DIR}/sdkconfig.combined COPYONLY)
set(SDKCONFIG_DEFAULTS ${CMAKE_BINARY_DIR}/sdkconfig.combined)
+# Include main IDF cmake file.
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+
+# Set the location of the main component for the project (one per target).
+list(APPEND EXTRA_COMPONENT_DIRS main_${IDF_TARGET})
+
# Define the project.
project(micropython)
diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile
index e43cad751b21..7c8c225dfb6e 100644
--- a/ports/esp32/Makefile
+++ b/ports/esp32/Makefile
@@ -2,8 +2,20 @@
#
# This is a simple, convenience wrapper around idf.py (which uses cmake).
-# Select the board to build for, defaulting to GENERIC.
+# Select the board to build for:
+ifdef BOARD_DIR
+# Custom board path - remove trailing slash and get the final component of
+# the path as the board name.
+BOARD ?= $(notdir $(BOARD_DIR:/=))
+else
+# If not given on the command line, then default to GENERIC.
BOARD ?= GENERIC
+BOARD_DIR ?= boards/$(BOARD)
+endif
+
+ifeq ($(wildcard $(BOARD_DIR)/.),)
+$(error Invalid BOARD specified: $(BOARD_DIR))
+endif
# If the build directory is not given, make it reflect the board name.
BUILD ?= build-$(BOARD)
@@ -28,7 +40,7 @@ ifdef USER_C_MODULES
CMAKE_ARGS += -DUSER_C_MODULES=${USER_C_MODULES}
endif
-IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -B $(BUILD) $(CMAKE_ARGS)
+IDFPY_FLAGS += -D MICROPY_BOARD=$(BOARD) -D MICROPY_BOARD_DIR=$(abspath $(BOARD_DIR)) -B $(BUILD) $(CMAKE_ARGS)
ifdef FROZEN_MANIFEST
IDFPY_FLAGS += -D MICROPY_FROZEN_MANIFEST=$(FROZEN_MANIFEST)
@@ -36,6 +48,10 @@ endif
HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m"
+define RUN_IDF_PY
+ idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) $(1)
+endef
+
all:
idf.py $(IDFPY_FLAGS) build || (echo -e $(HELP_BUILD_ERROR); false)
@$(PYTHON) makeimg.py \
@@ -49,13 +65,25 @@ all:
$(BUILD)/bootloader/bootloader.bin $(BUILD)/partition_table/partition-table.bin $(BUILD)/micropython.bin: FORCE
clean:
- idf.py $(IDFPY_FLAGS) fullclean
+ $(call RUN_IDF_PY,fullclean)
deploy:
- idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) flash
+ $(call RUN_IDF_PY,flash)
erase:
- idf.py $(IDFPY_FLAGS) -p $(PORT) -b $(BAUD) erase_flash
+ $(call RUN_IDF_PY,erase-flash)
+
+monitor:
+ $(call RUN_IDF_PY,monitor)
+
+size:
+ $(call RUN_IDF_PY,size)
+
+size-components:
+ $(call RUN_IDF_PY,size-components)
+
+size-files:
+ $(call RUN_IDF_PY,size-files)
submodules:
$(MAKE) -f ../../py/mkrules.mk GIT_SUBMODULES="$(GIT_SUBMODULES)" submodules
diff --git a/ports/esp32/README.md b/ports/esp32/README.md
index c37213b30310..2d5b05b9266a 100644
--- a/ports/esp32/README.md
+++ b/ports/esp32/README.md
@@ -22,14 +22,13 @@ Initial development of this ESP32 port was sponsored in part by Microbric Pty Lt
Setting up ESP-IDF and the build environment
--------------------------------------------
-MicroPython on ESP32 requires the Espressif IDF version 4 (IoT development
+MicroPython on ESP32 requires the Espressif IDF version 5 (IoT development
framework, aka SDK). The ESP-IDF includes the libraries and RTOS needed to
manage the ESP32 microcontroller, as well as a way to manage the required
build environment and toolchains needed to build the firmware.
The ESP-IDF changes quickly and MicroPython only supports certain versions.
-Currently MicroPython supports v4.0.2, v4.1.1, v4.2.2, v4.3.2 and v4.4,
-although other IDF v4 versions may also work.
+Currently MicroPython supports only v5.0.2.
To install the ESP-IDF the full instructions can be found at the
[Espressif Getting Started guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#installation-step-by-step).
@@ -47,10 +46,10 @@ The steps to take are summarised below.
To check out a copy of the IDF use git clone:
```bash
-$ git clone -b v4.0.2 --recursive https://github.com/espressif/esp-idf.git
+$ git clone -b v5.0.2 --recursive https://github.com/espressif/esp-idf.git
```
-You can replace `v4.0.2` with `v4.2.2` or `v4.4` or any other supported version.
+You can replace `v5.0.2` with any other supported version.
(You don't need a full recursive clone; see the `ci_esp32_setup` function in
`tools/ci.sh` in this repository for more detailed set-up commands.)
@@ -59,7 +58,7 @@ MicroPython and update the submodules using:
```bash
$ cd esp-idf
-$ git checkout v4.2
+$ git checkout v5.0.2
$ git submodule update --init --recursive
```
@@ -75,11 +74,6 @@ $ source export.sh # (or export.bat on Windows)
The `install.sh` step only needs to be done once. You will need to source
`export.sh` for every new session.
-**Note:** If you are building MicroPython for the ESP32-S2, ESP32-C3 or ESP32-S3,
-please ensure you are using the following required IDF versions:
-- ESP32-S3 currently requires `v4.4` or later.
-- ESP32-S2 and ESP32-C3 require `v4.3.1` or later.
-
Building the firmware
---------------------
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json
new file mode 100644
index 000000000000..afb24e10494b
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board.json
@@ -0,0 +1,20 @@
+{
+ "deploy": [
+ "deploy.md"
+ ],
+ "docs": "",
+ "features": [
+ "BLE",
+ "WiFi",
+ "USB-C",
+ "RGB LED"
+ ],
+ "images": [
+ "ABX00092_01.iso_1000x750.jpg"
+ ],
+ "mcu": "esp32s3",
+ "product": "Arduino Nano ESP32",
+ "thumbnail": "",
+ "url": "https://store.arduino.cc/products/arduino-nano-esp32",
+ "vendor": "Arduino"
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c
new file mode 100644
index 000000000000..ab03139d9055
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/mphal.h"
+
+#include
+#include
+#include
+
+#include "double_tap.h"
+#include "usb.h"
+
+#include "tinyusb.h"
+#include "tusb_cdc_acm.h"
+
+#define LED_RED GPIO_NUM_46
+#define LED_GREEN GPIO_NUM_0
+#define LED_BLUE GPIO_NUM_45
+#define DELAY_US 60000
+
+static bool _recovery_marker_found; // double tap detected
+static bool _recovery_active; // running from factory partition
+
+static void rgb_pulse_delay() {
+ // initialize RGB signals from weak pinstraps
+ mp_hal_pin_output(LED_RED);
+ mp_hal_pin_output(LED_GREEN);
+ mp_hal_pin_output(LED_BLUE);
+
+ static const uint8_t SEQ[] = { 1, 3, 2, 6, 7, 5, 4, 5, 7, 6, 2, 3, 1 };
+ for (int idx = 0; idx < sizeof(SEQ); ++idx) {
+ int v = SEQ[idx & 7];
+ mp_hal_pin_write(LED_RED, !(v & 1));
+ mp_hal_pin_write(LED_GREEN, !(v & 2));
+ mp_hal_pin_write(LED_BLUE, !(v & 4));
+
+ // busy wait, we can't use task delay yet
+ mp_hal_delay_us_fast(DELAY_US);
+ }
+
+ // reset pins to digital HIGH before leaving
+ mp_hal_pin_write(LED_RED, 1);
+ mp_hal_pin_write(LED_GREEN, 1);
+ mp_hal_pin_write(LED_BLUE, 1);
+}
+
+void NANO_ESP32_enter_bootloader(void) {
+ if (!_recovery_active) {
+ // check for valid partition scheme
+ const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL);
+ const esp_partition_t *fact_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
+ if (ota_part && fact_part) {
+ // set tokens so the recovery FW will find them
+ double_tap_mark();
+ // invalidate other OTA image
+ esp_partition_erase_range(ota_part, 0, 4096);
+ // activate factory partition
+ esp_ota_set_boot_partition(fact_part);
+ }
+ }
+
+ esp_restart();
+}
+
+void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event_in) {
+ extern void mp_usbd_line_state_cb(uint8_t itf, bool dtr, bool rts);
+ cdcacm_event_t *event = event_in;
+ mp_usbd_line_state_cb(itf, event->line_state_changed_data.dtr, event->line_state_changed_data.rts);
+}
+
+void NANO_ESP32_board_startup(void) {
+ boardctrl_startup();
+
+ // mark current partition as valid
+ const esp_partition_t *running = esp_ota_get_running_partition();
+ esp_ota_img_states_t ota_state;
+ if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
+ if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
+ esp_ota_mark_app_valid_cancel_rollback();
+ }
+ }
+
+ const esp_partition_t *part = esp_ota_get_running_partition();
+ _recovery_active = (part->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY);
+
+ double_tap_init();
+
+ _recovery_marker_found = double_tap_check_match();
+ if (_recovery_marker_found && !_recovery_active) {
+ // double tap detected in user application, reboot to factory
+ NANO_ESP32_enter_bootloader();
+ }
+
+ // delay with mark set then proceed
+ // - for normal startup, to detect first double tap
+ // - in recovery mode, to ignore several short presses
+ double_tap_mark();
+ rgb_pulse_delay();
+ double_tap_invalidate();
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md
new file mode 100644
index 000000000000..b600a55b64e2
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/deploy.md
@@ -0,0 +1,8 @@
+### Via dfu-util
+
+This board can programmed via DFU bootloader, using e.g. [dfu-util](http://dfu-util.sourceforge.net/).
+To enter the DFU bootloader, double tap the reset (blue) button, or you can use `machine.bootloader()` from the MicroPython REPL.
+
+```bash
+dfu-util -d 0x2341:0x0070 -R -D build-ARDUINO_NANO_ESP32/micropython.bin
+```
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c
new file mode 100644
index 000000000000..8f50a3272271
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.c
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/mphal.h"
+
+#include
+
+// for get_extram_data_high()
+#include
+#include
+
+#include "double_tap.h"
+
+#define NUM_TOKENS 3
+static const uint32_t MAGIC_TOKENS[NUM_TOKENS] = {
+ 0xf01681de, 0xbd729b29, 0xd359be7a,
+};
+
+static void *magic_area;
+static uint32_t backup_area[NUM_TOKENS];
+
+// Current IDF does not map external RAM to a fixed address.
+// The actual VMA depends on other enabled devices, so the precise
+// location must be discovered.
+static uintptr_t get_extram_data_high(void) {
+ // get a pointer into SRAM area (only the address is useful)
+ void *psram_ptr = heap_caps_malloc(16, MALLOC_CAP_SPIRAM);
+ heap_caps_free(psram_ptr);
+
+ // keep moving backwards until leaving PSRAM area
+ uintptr_t psram_base_addr = (uintptr_t)psram_ptr;
+ psram_base_addr &= ~(CONFIG_MMU_PAGE_SIZE - 1); // align to start of page
+ while (esp_psram_check_ptr_addr((void *)psram_base_addr)) {
+ psram_base_addr -= CONFIG_MMU_PAGE_SIZE;
+ }
+
+ // offset is one page from start of PSRAM
+ return psram_base_addr + CONFIG_MMU_PAGE_SIZE + esp_psram_get_size();
+}
+
+void double_tap_init(void) {
+ // magic location block ends 0x20 bytes from end of PSRAM
+ magic_area = (void *)(get_extram_data_high() - 0x20 - sizeof(MAGIC_TOKENS));
+}
+
+void double_tap_mark() {
+ memcpy(backup_area, magic_area, sizeof(MAGIC_TOKENS));
+ memcpy(magic_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS));
+ Cache_WriteBack_Addr((uintptr_t)magic_area, sizeof(MAGIC_TOKENS));
+}
+
+void double_tap_invalidate() {
+ if (memcmp(backup_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS))) {
+ // different contents: restore backup
+ memcpy(magic_area, backup_area, sizeof(MAGIC_TOKENS));
+ } else {
+ // clear memory
+ memset(magic_area, 0, sizeof(MAGIC_TOKENS));
+ }
+ Cache_WriteBack_Addr((uintptr_t)magic_area, sizeof(MAGIC_TOKENS));
+}
+
+bool double_tap_check_match() {
+ return memcmp(magic_area, MAGIC_TOKENS, sizeof(MAGIC_TOKENS)) == 0;
+}
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h
new file mode 100644
index 000000000000..9aa738f2d9f8
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/double_tap.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H
+#define MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H
+
+#include
+
+void double_tap_init(void);
+void double_tap_mark(void);
+void double_tap_invalidate(void);
+bool double_tap_check_match(void);
+
+#endif /* MICROPY_INCLUDED_ESP32_DOUBLE_TAP_H */
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py b/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py
new file mode 100644
index 000000000000..e7fc7fe1619f
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/manifest.py
@@ -0,0 +1,9 @@
+include("$(PORT_DIR)/boards/manifest.py")
+
+# Utils
+require("time")
+require("senml")
+require("logging")
+
+# Bluetooth
+require("aioble")
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
new file mode 100644
index 000000000000..7ae4b3818535
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.cmake
@@ -0,0 +1,23 @@
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../.. ABSOLUTE)
+endif()
+
+set(IDF_TARGET esp32s3)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.usb
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/sdkconfig.spiram_sx
+ boards/sdkconfig.spiram_oct
+ ${MICROPY_BOARD_DIR}/sdkconfig.board
+)
+
+set(MICROPY_SOURCE_BOARD
+ ${MICROPY_BOARD_DIR}/board_init.c
+ ${MICROPY_BOARD_DIR}/double_tap.c
+ ${MICROPY_DIR}/shared/tinyusb/mp_cdc_common.c
+)
+
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
new file mode 100644
index 000000000000..3e98bb99d702
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h
@@ -0,0 +1,32 @@
+#define MICROPY_HW_BOARD_NAME "Arduino Nano ESP32"
+#define MICROPY_HW_MCU_NAME "ESP32S3"
+
+#define MICROPY_PY_MACHINE_DAC (0)
+
+#define MICROPY_HW_I2C0_SCL (12)
+#define MICROPY_HW_I2C0_SDA (11)
+
+#define MICROPY_HW_I2C1_SCL (8)
+#define MICROPY_HW_I2C1_SDA (9)
+
+#define MICROPY_HW_SPI1_MOSI (38)
+#define MICROPY_HW_SPI1_MISO (47)
+#define MICROPY_HW_SPI1_SCK (48)
+
+#define MICROPY_HW_SPI2_MOSI (10)
+#define MICROPY_HW_SPI2_MISO (17)
+#define MICROPY_HW_SPI2_SCK (18)
+
+#define MICROPY_HW_ENABLE_USBDEV (1)
+#define MICROPY_HW_USB_EXTERNAL_TINYUSB (1)
+#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
+#define MICROPY_SCHEDULER_STATIC_NODES (1)
+
+#define MICROPY_HW_USB_CUSTOM_LINE_STATE_CB NANO_ESP32_usb_callback_line_state_changed
+void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event);
+
+#define MICROPY_BOARD_STARTUP NANO_ESP32_board_startup
+void NANO_ESP32_board_startup(void);
+
+#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) NANO_ESP32_enter_bootloader()
+void NANO_ESP32_enter_bootloader(void);
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv b/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv
new file mode 100644
index 000000000000..13b4414b1d30
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv
@@ -0,0 +1,10 @@
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x5000,
+otadata, data, ota, 0xe000, 0x2000,
+app0, app, ota_0, 0x10000, 0x300000,
+app1, app, ota_1, 0x310000, 0x300000,
+ffat, data, fat, 0x610000, 0x960000,
+factory, app, factory, 0xF70000, 0x80000,
+coredump, data, coredump, 0xFF0000, 0x10000,
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv b/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv
new file mode 100644
index 000000000000..b891608d5d89
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/pins.csv
@@ -0,0 +1,38 @@
+D0,GPIO44
+D1,GPIO43
+D2,GPIO5
+D3,GPIO6
+D4,GPIO7
+D5,GPIO8
+D6,GPIO9
+D7,GPIO10
+D8,GPIO17
+D9,GPIO18
+D10,GPIO21
+D11,GPIO38
+D12,GPIO47
+D13,GPIO48
+LED_RED,GPIO46
+LED_GREEN,GPIO0
+LED_BLUE,GPIO45
+A0,GPIO1
+A1,GPIO2
+A2,GPIO3
+A3,GPIO4
+A4,GPIO11
+A5,GPIO12
+A6,GPIO13
+A7,GPIO14
+LED_BUILTIN,GPIO48
+TX,GPIO43
+RX,GPIO44
+RTS,GPIO45
+CTS,GPIO6
+DTR,GPIO1
+DSR,GPIO7
+SS,GPIO21
+MOSI,GPIO38
+MISO,GPIO47
+SCK,GPIO48
+SDA,GPIO11
+SCL,GPIO12
diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
new file mode 100644
index 000000000000..4d175f7ed77c
--- /dev/null
+++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/sdkconfig.board
@@ -0,0 +1,22 @@
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="boards/ARDUINO_NANO_ESP32/partitions-app3M_fat9M_fact512k_16MiB.csv"
+
+CONFIG_SPIRAM_TYPE_ESPPSRAM64=y
+CONFIG_SPIRAM_SPEED_80M=y
+CONFIG_SPIRAM_MEMTEST=
+CONFIG_SPIRAM_IGNORE_NOTFOUND=
+
+CONFIG_LWIP_LOCAL_HOSTNAME="nano-esp32"
+
+CONFIG_TINYUSB_DESC_CUSTOM_VID=0x2341
+CONFIG_TINYUSB_DESC_CUSTOM_PID=0x056B
+CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Arduino"
+CONFIG_TINYUSB_DESC_PRODUCT_STRING="Nano ESP32"
+
+# compatibility with Espressif Arduino core
+CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
+CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
+CONFIG_ESP_ENABLE_COREDUMP_TO_FLASH=y
diff --git a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board
index 9373a522324d..40a8e3047cce 100644
--- a/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board
+++ b/ports/esp32/boards/ESP32_S2_WROVER/sdkconfig.board
@@ -1,6 +1,5 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
diff --git a/ports/esp32/boards/GENERIC/board.md b/ports/esp32/boards/GENERIC/board.md
index 576ea80450f6..efb2b2cab7c2 100644
--- a/ports/esp32/boards/GENERIC/board.md
+++ b/ports/esp32/boards/GENERIC/board.md
@@ -1,3 +1 @@
-The following files are daily firmware for ESP32-based boards without external SPIRAM.
-
-This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
+The following files are firmware for ESP32-based boards without external SPIRAM.
diff --git a/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board b/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board
index f0cbad00e461..d9e7c7f61f62 100644
--- a/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_C3_USB/sdkconfig.board
@@ -1,9 +1,7 @@
CONFIG_ESP32C3_REV_MIN_3=y
-CONFIG_ESP32C3_REV_MIN=3
CONFIG_ESP32C3_BROWNOUT_DET=y
CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=
CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4=y
CONFIG_ESP32C3_BROWNOUT_DET_LVL=4
CONFIG_ESP_CONSOLE_UART_DEFAULT=
-CONFIG_ESP_CONSOLE_USB_CDC=
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
diff --git a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
index 07e208a09ae7..7b4313b7deef 100644
--- a/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_D2WD/sdkconfig.board
@@ -1,6 +1,7 @@
# Optimise using -Os to reduce size
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_PERF=n
+CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
diff --git a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board
index d314860cc937..7ff939aa991f 100644
--- a/ports/esp32/boards/GENERIC_OTA/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_OTA/sdkconfig.board
@@ -1,3 +1,6 @@
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-ota.csv"
+
+# Reduce firmware size to fit in the OTA partition.
+CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
diff --git a/ports/esp32/boards/GENERIC_S3/sdkconfig.board b/ports/esp32/boards/GENERIC_S3/sdkconfig.board
index c9726d4232ed..a36b97116285 100644
--- a/ports/esp32/boards/GENERIC_S3/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_S3/sdkconfig.board
@@ -1,10 +1,7 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
index b7351b90fe8e..e0b92dcd2640 100644
--- a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.cmake
@@ -3,6 +3,7 @@ set(IDF_TARGET esp32s3)
set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.usb
+ boards/sdkconfig.ble
boards/sdkconfig.spiram_sx
boards/GENERIC_S3_SPIRAM/sdkconfig.board
)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
index f9126c98d76e..1a8560a2d7ea 100644
--- a/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/mpconfigboard.h
@@ -1,7 +1,6 @@
#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram)"
#define MICROPY_HW_MCU_NAME "ESP32S3"
-#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_PY_MACHINE_DAC (0)
// Enable UART REPL for modules that have an external USB-UART and don't use native USB.
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board
index c9726d4232ed..a36b97116285 100644
--- a/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM/sdkconfig.board
@@ -1,10 +1,7 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json
new file mode 100644
index 000000000000..f3ca177ef974
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/board.json
@@ -0,0 +1,18 @@
+{
+ "deploy": [
+ "../deploy_s3.md"
+ ],
+ "docs": "",
+ "features": [
+ "BLE",
+ "WiFi"
+ ],
+ "images": [
+ "generic_s3.jpg"
+ ],
+ "mcu": "esp32s3",
+ "product": "Generic ESP32-S3 (SPIRAM Octal)",
+ "thumbnail": "",
+ "url": "https://www.espressif.com/en/products/modules",
+ "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake
new file mode 100644
index 000000000000..7a767c49d403
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.cmake
@@ -0,0 +1,11 @@
+set(IDF_TARGET esp32s3)
+
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.usb
+ boards/sdkconfig.ble
+ boards/sdkconfig.240mhz
+ boards/sdkconfig.spiram_sx
+ boards/sdkconfig.spiram_oct
+ boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board
+)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h
new file mode 100644
index 000000000000..88f6835c9420
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/mpconfigboard.h
@@ -0,0 +1,10 @@
+#define MICROPY_HW_BOARD_NAME "ESP32S3 module (spiram octal)"
+#define MICROPY_HW_MCU_NAME "ESP32S3"
+
+#define MICROPY_PY_MACHINE_DAC (0)
+
+// Enable UART REPL for modules that have an external USB-UART and don't use native USB.
+#define MICROPY_HW_ENABLE_UART_REPL (1)
+
+#define MICROPY_HW_I2C0_SCL (9)
+#define MICROPY_HW_I2C0_SDA (8)
diff --git a/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board
new file mode 100644
index 000000000000..a36b97116285
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_S3_SPIRAM_OCT/sdkconfig.board
@@ -0,0 +1,9 @@
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
+CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
+CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/board.md b/ports/esp32/boards/GENERIC_SPIRAM/board.md
index 3b02b902cd75..c638f63dd3e1 100644
--- a/ports/esp32/boards/GENERIC_SPIRAM/board.md
+++ b/ports/esp32/boards/GENERIC_SPIRAM/board.md
@@ -1,3 +1 @@
-The following files are daily firmware for ESP32-based boards with external SPIRAM (also known as PSRAM).
-
-This firmware is compiled using ESP-IDF v4.x. Some older releases are also provided that are compiled with ESP-IDF v3.x.
+The following files are firmware for ESP32-based boards with external SPIRAM (also known as PSRAM).
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake
index dcffe5f01e7a..2e1d799b93b1 100644
--- a/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake
+++ b/ports/esp32/boards/GENERIC_SPIRAM/mpconfigboard.cmake
@@ -2,5 +2,4 @@ set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.ble
boards/sdkconfig.spiram
- boards/GENERIC_SPIRAM/sdkconfig.board
)
diff --git a/ports/esp32/boards/GENERIC_SPIRAM/sdkconfig.board b/ports/esp32/boards/GENERIC_SPIRAM/sdkconfig.board
deleted file mode 100644
index a2859acb5f90..000000000000
--- a/ports/esp32/boards/GENERIC_SPIRAM/sdkconfig.board
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPIRAM increases the size of the firmware, use -Os to reduce it again to fit in iram
-CONFIG_COMPILER_OPTIMIZATION_SIZE=y
diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.json b/ports/esp32/boards/GENERIC_UNICORE/board.json
new file mode 100644
index 000000000000..8fed71a018aa
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_UNICORE/board.json
@@ -0,0 +1,19 @@
+{
+ "deploy": [
+ "../deploy.md"
+ ],
+ "docs": "",
+ "features": [
+ "BLE",
+ "WiFi"
+ ],
+ "id": "esp32-unicore",
+ "images": [
+ "generic_unicore.jpg"
+ ],
+ "mcu": "esp32",
+ "product": "ESP32 Unicore",
+ "thumbnail": "",
+ "url": "https://www.espressif.com/en/products/modules",
+ "vendor": "Espressif"
+}
diff --git a/ports/esp32/boards/GENERIC_UNICORE/board.md b/ports/esp32/boards/GENERIC_UNICORE/board.md
new file mode 100644
index 000000000000..b41c167498c7
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_UNICORE/board.md
@@ -0,0 +1 @@
+The following files are daily firmware for single-core ESP32-based boards without external SPIRAM.
diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake
new file mode 100644
index 000000000000..2f34688c8c47
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.cmake
@@ -0,0 +1,5 @@
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.ble
+ boards/GENERIC_UNICORE/sdkconfig.board
+)
diff --git a/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h
new file mode 100644
index 000000000000..5d0624b9c3f9
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_UNICORE/mpconfigboard.h
@@ -0,0 +1,2 @@
+#define MICROPY_HW_BOARD_NAME "ESP32 Unicore module"
+#define MICROPY_HW_MCU_NAME "ESP32-UNICORE"
diff --git a/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board b/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board
new file mode 100644
index 000000000000..f0b0b5e03dd4
--- /dev/null
+++ b/ports/esp32/boards/GENERIC_UNICORE/sdkconfig.board
@@ -0,0 +1 @@
+CONFIG_FREERTOS_UNICORE=y
diff --git a/ports/esp32/boards/LILYGO_TTGO_LORA32/mpconfigboard.h b/ports/esp32/boards/LILYGO_TTGO_LORA32/mpconfigboard.h
index 1c7b6fd55767..6be22dd0ffc4 100644
--- a/ports/esp32/boards/LILYGO_TTGO_LORA32/mpconfigboard.h
+++ b/ports/esp32/boards/LILYGO_TTGO_LORA32/mpconfigboard.h
@@ -1,2 +1,3 @@
#define MICROPY_HW_BOARD_NAME "LILYGO TTGO LoRa32"
#define MICROPY_HW_MCU_NAME "ESP32"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-ttgo-lora32"
diff --git a/ports/esp32/boards/LOLIN_C3_MINI/mpconfigboard.h b/ports/esp32/boards/LOLIN_C3_MINI/mpconfigboard.h
index 5872bdc8ae5e..12fd285da175 100644
--- a/ports/esp32/boards/LOLIN_C3_MINI/mpconfigboard.h
+++ b/ports/esp32/boards/LOLIN_C3_MINI/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "LOLIN_C3_MINI"
#define MICROPY_HW_MCU_NAME "ESP32-C3FH4"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-c3-mini"
#define MICROPY_HW_ENABLE_SDCARD (0)
#define MICROPY_PY_MACHINE_DAC (0)
diff --git a/ports/esp32/boards/LOLIN_C3_MINI/sdkconfig.board b/ports/esp32/boards/LOLIN_C3_MINI/sdkconfig.board
index f0cbad00e461..d9e7c7f61f62 100644
--- a/ports/esp32/boards/LOLIN_C3_MINI/sdkconfig.board
+++ b/ports/esp32/boards/LOLIN_C3_MINI/sdkconfig.board
@@ -1,9 +1,7 @@
CONFIG_ESP32C3_REV_MIN_3=y
-CONFIG_ESP32C3_REV_MIN=3
CONFIG_ESP32C3_BROWNOUT_DET=y
CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_7=
CONFIG_ESP32C3_BROWNOUT_DET_LVL_SEL_4=y
CONFIG_ESP32C3_BROWNOUT_DET_LVL=4
CONFIG_ESP_CONSOLE_UART_DEFAULT=
-CONFIG_ESP_CONSOLE_USB_CDC=
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
index e0ef10d1db92..9776b7b478aa 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
+++ b/ports/esp32/boards/LOLIN_S2_MINI/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "LOLIN_S2_MINI"
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-s2-mini"
#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_HW_ENABLE_SDCARD (0)
diff --git a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board
index 1a7ef3f8b92a..cbb3ad06d9a1 100644
--- a/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board
+++ b/ports/esp32/boards/LOLIN_S2_MINI/sdkconfig.board
@@ -1,4 +1,4 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_USB_AND_UART=y
# LWIP
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
index 549dd9847c7f..9241280dec6a 100644
--- a/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
+++ b/ports/esp32/boards/LOLIN_S2_PICO/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "LOLIN_S2_PICO"
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-s2-pico"
#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_HW_ENABLE_SDCARD (0)
diff --git a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board
index bf0f3e780e4d..eadff2f1b90b 100644
--- a/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board
+++ b/ports/esp32/boards/LOLIN_S2_PICO/sdkconfig.board
@@ -1,4 +1,4 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_USB_AND_UART=y
# LWIP
diff --git a/ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h b/ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h
index 4270b19caf96..18a59b15a50a 100644
--- a/ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h
+++ b/ports/esp32/boards/M5STACK_ATOM/mpconfigboard.h
@@ -1,2 +1,3 @@
#define MICROPY_HW_BOARD_NAME "M5Stack ATOM"
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "m5stack-atom"
diff --git a/ports/esp32/boards/M5STACK_ATOM/sdkconfig.board b/ports/esp32/boards/M5STACK_ATOM/sdkconfig.board
index b299822dcb6d..0026b4234423 100644
--- a/ports/esp32/boards/M5STACK_ATOM/sdkconfig.board
+++ b/ports/esp32/boards/M5STACK_ATOM/sdkconfig.board
@@ -1,4 +1,4 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_ESP32_REV_MIN_1=y
diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/board.json b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json
new file mode 100644
index 000000000000..84b6680d591b
--- /dev/null
+++ b/ports/esp32/boards/OLIMEX_ESP32_POE/board.json
@@ -0,0 +1,23 @@
+{
+ "deploy": [
+ "../deploy.md"
+ ],
+ "docs": "",
+ "features": [
+ "BLE",
+ "WiFi",
+ "MicroSD",
+ "Battery Charging",
+ "Ethernet",
+ "PoE",
+ "Breadboard friendly"
+ ],
+ "images": [
+ "ESP32-POE-ISO-1.jpg"
+ ],
+ "mcu": "esp32",
+ "product": "Olimex ESP32 POE",
+ "thumbnail": "",
+ "url": "https://www.olimex.com/",
+ "vendor": "OLIMEX"
+}
diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/board.md b/ports/esp32/boards/OLIMEX_ESP32_POE/board.md
new file mode 100644
index 000000000000..f077deda95cb
--- /dev/null
+++ b/ports/esp32/boards/OLIMEX_ESP32_POE/board.md
@@ -0,0 +1,2 @@
+The following files are firmware for Olimex ESP32 boards with Ethernet.
+They match the boards ESP32 ETH-PoE, ESP32 ETH-PoE-ISO and ESP32 Gateway.
diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake
new file mode 100644
index 000000000000..c460b07d5efa
--- /dev/null
+++ b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.cmake
@@ -0,0 +1,5 @@
+set(SDKCONFIG_DEFAULTS
+ boards/sdkconfig.base
+ boards/sdkconfig.ble
+ boards/OLIMEX_ESP32_POE/sdkconfig.board
+)
diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h
new file mode 100644
index 000000000000..c8458e35fa0d
--- /dev/null
+++ b/ports/esp32/boards/OLIMEX_ESP32_POE/mpconfigboard.h
@@ -0,0 +1,2 @@
+#define MICROPY_HW_BOARD_NAME "Olimex ESP32 ETH"
+#define MICROPY_HW_MCU_NAME "ESP32"
diff --git a/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board b/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board
new file mode 100644
index 000000000000..15ffbf3a67b9
--- /dev/null
+++ b/ports/esp32/boards/OLIMEX_ESP32_POE/sdkconfig.board
@@ -0,0 +1,4 @@
+CONFIG_ETH_PHY_INTERFACE_RMII=y
+CONFIG_ETH_RMII_CLK_OUTPUT=y
+CONFIG_ETH_RMII_CLK_OUT_GPIO=17
+CONFIG_LWIP_LOCAL_HOSTNAME="ESP32_POE"
diff --git a/ports/esp32/boards/SIL_WESP32/sdkconfig.board b/ports/esp32/boards/SIL_WESP32/sdkconfig.board
index 98eef1d10916..be9e40c4c3ae 100644
--- a/ports/esp32/boards/SIL_WESP32/sdkconfig.board
+++ b/ports/esp32/boards/SIL_WESP32/sdkconfig.board
@@ -7,7 +7,7 @@ CONFIG_ESPTOOLPY_FLASHSIZE="16MB"
# Fast flash
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESP32_REV_MIN_1=y
diff --git a/ports/esp32/boards/UM_FEATHERS2/board.md b/ports/esp32/boards/UM_FEATHERS2/board.md
index e04a8936c846..86ca33382d36 100644
--- a/ports/esp32/boards/UM_FEATHERS2/board.md
+++ b/ports/esp32/boards/UM_FEATHERS2/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the FeatherS2. This firmware is
-compiled using ESP-IDF v4.3 or later.
+The following files are firmware for the FeatherS2.
diff --git a/ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py b/ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py
index 95e1f5268160..df3ac4d299e6 100644
--- a/ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py
+++ b/ports/esp32/boards/UM_FEATHERS2/modules/feathers2.py
@@ -39,6 +39,7 @@
# Helper functions
+
# LED & Ambient Light Sensor control
def set_led(state):
l = Pin(LED, Pin.OUT)
diff --git a/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h
index 8d0c9f78c83a..d8529b6342fe 100644
--- a/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h
+++ b/ports/esp32/boards/UM_FEATHERS2/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "FeatherS2"
#define MICROPY_HW_MCU_NAME "ESP32-S2"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "FeatherS2"
#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_HW_ENABLE_SDCARD (0)
diff --git a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board
index ccda7bff6812..b23755dea789 100644
--- a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board
+++ b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board
@@ -1,15 +1,11 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"
-#CONFIG_USB_AND_UART=y
# LWIP
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2"
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/board.md b/ports/esp32/boards/UM_FEATHERS2NEO/board.md
index 60ee024a1261..26012d0bae5d 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/board.md
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the FeatherS2 Neo. This firmware is
-compiled using ESP-IDF v4.3 or later.
+The following files are firmware for the FeatherS2 Neo.
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
index 857c7559d1ac..d0b99e2f9fe1 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/modules/feathers2neo.py
@@ -38,6 +38,7 @@
DAC1 = const(17)
DAC2 = const(18)
+
# Helper functions
def set_pixel_power(state):
"""Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep."""
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
index b0b3e3aa992a..c98ef691769b 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.cmake
@@ -3,6 +3,7 @@ set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram_sx
boards/sdkconfig.usb
+ boards/UM_FEATHERS2NEO/sdkconfig.board
)
-set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
\ No newline at end of file
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
index 5ee6874b87ba..e7e4d37ece95 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "FeatherS2 Neo"
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "FeatherS2-Neo"
#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_HW_ENABLE_SDCARD (0)
diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board
index 87a92892d07e..b2c6979a70be 100644
--- a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board
+++ b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board
@@ -1,4 +1,4 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_USB_AND_UART=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
diff --git a/ports/esp32/boards/UM_FEATHERS3/board.md b/ports/esp32/boards/UM_FEATHERS3/board.md
index ca9c36ad331f..bed179041c28 100644
--- a/ports/esp32/boards/UM_FEATHERS3/board.md
+++ b/ports/esp32/boards/UM_FEATHERS3/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the FeatherS3. This firmware is
-compiled using ESP-IDF v4.4 or later.
+The following files are firmware for the FeatherS3.
diff --git a/ports/esp32/boards/UM_FEATHERS3/modules/feathers3.py b/ports/esp32/boards/UM_FEATHERS3/modules/feathers3.py
index 801f9cbf46fb..1ba919ceaeeb 100644
--- a/ports/esp32/boards/UM_FEATHERS3/modules/feathers3.py
+++ b/ports/esp32/boards/UM_FEATHERS3/modules/feathers3.py
@@ -32,6 +32,7 @@
# Helper functions
+
# LED & Ambient Light Sensor control
def led_set(state):
"""Set the state of the BLUE LED on IO13"""
diff --git a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
index 738b32ca1e84..91ea5056d17b 100644
--- a/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_FEATHERS3/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "FeatherS3"
#define MICROPY_HW_MCU_NAME "ESP32-S3"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "FeatherS3"
#define MICROPY_PY_MACHINE_DAC (0)
diff --git a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
index 5e2004512546..804944ab24be 100644
--- a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board
@@ -1,10 +1,7 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
@@ -13,11 +10,9 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"
CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS3"
-# CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID is not set
CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-# CONFIG_TINYUSB_DESC_USE_DEFAULT_PID is not set
CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D7
CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
CONFIG_TINYUSB_DESC_PRODUCT_STRING="FeatherS3"
-CONFIG_TINYUSB_DESC_SERIAL_STRING="_fs3_"
\ No newline at end of file
+CONFIG_TINYUSB_DESC_SERIAL_STRING="_fs3_"
diff --git a/ports/esp32/boards/UM_PROS3/board.md b/ports/esp32/boards/UM_PROS3/board.md
index 4d1c435a07d1..406abf74e3a1 100644
--- a/ports/esp32/boards/UM_PROS3/board.md
+++ b/ports/esp32/boards/UM_PROS3/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the ProS3. This firmware is
-compiled using ESP-IDF v4.4 or later.
+The following files are firmware for the ProS3.
diff --git a/ports/esp32/boards/UM_PROS3/modules/pros3.py b/ports/esp32/boards/UM_PROS3/modules/pros3.py
index 2edf3e42ea58..7f9590293618 100644
--- a/ports/esp32/boards/UM_PROS3/modules/pros3.py
+++ b/ports/esp32/boards/UM_PROS3/modules/pros3.py
@@ -28,6 +28,7 @@
I2C_SDA = const(8)
I2C_SCL = const(9)
+
# Helper functions
def set_ldo2_power(state):
"""Enable or Disable power to the second LDO"""
diff --git a/ports/esp32/boards/UM_PROS3/mpconfigboard.h b/ports/esp32/boards/UM_PROS3/mpconfigboard.h
index 1522e2aee3ad..ecff1e657066 100644
--- a/ports/esp32/boards/UM_PROS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_PROS3/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "ProS3"
#define MICROPY_HW_MCU_NAME "ESP32-S3"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "ProS3"
#define MICROPY_PY_MACHINE_DAC (0)
diff --git a/ports/esp32/boards/UM_PROS3/sdkconfig.board b/ports/esp32/boards/UM_PROS3/sdkconfig.board
index 06b3a00a1c5a..71511e3c5298 100644
--- a/ports/esp32/boards/UM_PROS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_PROS3/sdkconfig.board
@@ -1,10 +1,7 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
@@ -13,9 +10,7 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16MiB.csv"
CONFIG_LWIP_LOCAL_HOSTNAME="UMProS3"
-# CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID is not set
CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-# CONFIG_TINYUSB_DESC_USE_DEFAULT_PID is not set
CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D4
CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
diff --git a/ports/esp32/boards/UM_TINYPICO/board.md b/ports/esp32/boards/UM_TINYPICO/board.md
index d0b1266d2eec..0fb41c76e551 100644
--- a/ports/esp32/boards/UM_TINYPICO/board.md
+++ b/ports/esp32/boards/UM_TINYPICO/board.md
@@ -1,3 +1 @@
-The following files are daily firmware for the TinyPICO. This firmware is compiled
-using ESP-IDF v4.2 or later. Some older releases are also provided that are
-compiled with ESP-IDF v3.x.
+The following files are firmware for the TinyPICO.
diff --git a/ports/esp32/boards/UM_TINYPICO/modules/tinypico.py b/ports/esp32/boards/UM_TINYPICO/modules/tinypico.py
index 95450788426a..f6bedfb383cb 100644
--- a/ports/esp32/boards/UM_TINYPICO/modules/tinypico.py
+++ b/ports/esp32/boards/UM_TINYPICO/modules/tinypico.py
@@ -39,6 +39,7 @@
# Helper functions
+
# Get a *rough* estimate of the current battery voltage
# If the battery is not present, the charge IC will still report it's trying to charge at X voltage
# so it will still show a voltage.
diff --git a/ports/esp32/boards/UM_TINYPICO/mpconfigboard.h b/ports/esp32/boards/UM_TINYPICO/mpconfigboard.h
index 6bf70cc13b58..0bb3fa618415 100644
--- a/ports/esp32/boards/UM_TINYPICO/mpconfigboard.h
+++ b/ports/esp32/boards/UM_TINYPICO/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "TinyPICO"
#define MICROPY_HW_MCU_NAME "ESP32-PICO-D4"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "TinyPICO"
#define MICROPY_HW_I2C0_SCL (22)
#define MICROPY_HW_I2C0_SDA (21)
diff --git a/ports/esp32/boards/UM_TINYPICO/sdkconfig.board b/ports/esp32/boards/UM_TINYPICO/sdkconfig.board
index 8ed083e62d1a..8fa596a25ded 100644
--- a/ports/esp32/boards/UM_TINYPICO/sdkconfig.board
+++ b/ports/esp32/boards/UM_TINYPICO/sdkconfig.board
@@ -1,8 +1,5 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_ESP32_REV_MIN_1=y
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyPICO"
-
-# SPIRAM increases the size of the firmware, use -Os to reduce it again to fit in iram
-CONFIG_COMPILER_OPTIMIZATION_SIZE=y
diff --git a/ports/esp32/boards/UM_TINYS2/board.md b/ports/esp32/boards/UM_TINYS2/board.md
index 9a61374edf32..739453da8200 100644
--- a/ports/esp32/boards/UM_TINYS2/board.md
+++ b/ports/esp32/boards/UM_TINYS2/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the TinyS2. This firmware is compiled
-using ESP-IDF v4.3 or later.
+The following files are firmware for the TinyS2.
diff --git a/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake b/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
index e4b7b4a915c9..70cb4a814ff2 100644
--- a/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
+++ b/ports/esp32/boards/UM_TINYS2/mpconfigboard.cmake
@@ -3,4 +3,7 @@ set(SDKCONFIG_DEFAULTS
boards/sdkconfig.base
boards/sdkconfig.spiram_sx
boards/sdkconfig.usb
+ boards/UM_TINYS2/sdkconfig.board
)
+
+set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
diff --git a/ports/esp32/boards/UM_TINYS2/mpconfigboard.h b/ports/esp32/boards/UM_TINYS2/mpconfigboard.h
index 1052f6d79ca2..e0bde417c8a2 100644
--- a/ports/esp32/boards/UM_TINYS2/mpconfigboard.h
+++ b/ports/esp32/boards/UM_TINYS2/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "TinyS2"
#define MICROPY_HW_MCU_NAME "ESP32-S2FN4R2"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "TinyS2"
#define MICROPY_PY_BLUETOOTH (0)
#define MICROPY_HW_ENABLE_SDCARD (0)
diff --git a/ports/esp32/boards/UM_TINYS2/sdkconfig.board b/ports/esp32/boards/UM_TINYS2/sdkconfig.board
index 48b6749c720d..09e0deb078fa 100644
--- a/ports/esp32/boards/UM_TINYS2/sdkconfig.board
+++ b/ports/esp32/boards/UM_TINYS2/sdkconfig.board
@@ -1,6 +1,8 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_USB_AND_UART=y
+CONFIG_ESPTOOLPY_AFTER_NORESET=y
+
# LWIP
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS2"
# end of LWIP
diff --git a/ports/esp32/boards/UM_TINYS3/board.md b/ports/esp32/boards/UM_TINYS3/board.md
index da06e191f28c..5b4b5d8f1269 100644
--- a/ports/esp32/boards/UM_TINYS3/board.md
+++ b/ports/esp32/boards/UM_TINYS3/board.md
@@ -1,2 +1 @@
-The following files are daily firmware for the TinyS3. This firmware is
-compiled using ESP-IDF v4.4 or later.
+The following files are firmware for the TinyS3.
diff --git a/ports/esp32/boards/UM_TINYS3/modules/tinys3.py b/ports/esp32/boards/UM_TINYS3/modules/tinys3.py
index 4efcfe4b5299..06bbb5ff827c 100644
--- a/ports/esp32/boards/UM_TINYS3/modules/tinys3.py
+++ b/ports/esp32/boards/UM_TINYS3/modules/tinys3.py
@@ -28,6 +28,7 @@
I2C_SDA = const(8)
I2C_SCL = const(9)
+
# Helper functions
def set_pixel_power(state):
"""Enable or Disable power to the onboard NeoPixel to either show colour, or to reduce power for deep sleep."""
diff --git a/ports/esp32/boards/UM_TINYS3/mpconfigboard.h b/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
index b2638a984788..c0f81f0c447c 100644
--- a/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
+++ b/ports/esp32/boards/UM_TINYS3/mpconfigboard.h
@@ -1,5 +1,6 @@
#define MICROPY_HW_BOARD_NAME "TinyS3"
#define MICROPY_HW_MCU_NAME "ESP32-S3-FN8"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "TinyS3"
#define MICROPY_PY_MACHINE_DAC (0)
diff --git a/ports/esp32/boards/UM_TINYS3/sdkconfig.board b/ports/esp32/boards/UM_TINYS3/sdkconfig.board
index 2b9ddbebe7b5..c22e78eaeae7 100644
--- a/ports/esp32/boards/UM_TINYS3/sdkconfig.board
+++ b/ports/esp32/boards/UM_TINYS3/sdkconfig.board
@@ -1,10 +1,7 @@
-CONFIG_FLASHMODE_QIO=y
+CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
-CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_AFTER_NORESET=y
-CONFIG_SPIRAM_MEMTEST=
-
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
@@ -13,9 +10,7 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8MiB.csv"
CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS3"
-# CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID is not set
CONFIG_TINYUSB_DESC_CUSTOM_VID=0x303A
-# CONFIG_TINYUSB_DESC_USE_DEFAULT_PID is not set
CONFIG_TINYUSB_DESC_CUSTOM_PID=0x80D1
CONFIG_TINYUSB_DESC_BCD_DEVICE=0x0100
CONFIG_TINYUSB_DESC_MANUFACTURER_STRING="Unexpected Maker"
diff --git a/ports/esp32/boards/make-pins.py b/ports/esp32/boards/make-pins.py
new file mode 100755
index 000000000000..e0f988549b7f
--- /dev/null
+++ b/ports/esp32/boards/make-pins.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python
+
+import argparse
+import sys
+import csv
+import re
+
+MAX_CPU_PINS = 49
+
+
+def parse_pin(name_str):
+ """Parses a string and returns a pin number."""
+ if len(name_str) < 2:
+ raise ValueError("Expecting pin name to be at least 2 characters.")
+ if not name_str.startswith("GPIO"):
+ raise ValueError("Expecting pin name to start with GPIO")
+ return int(re.findall(r"\d+$", name_str)[0])
+
+
+class Pin:
+ def __init__(self, pin):
+ self.pin = pin
+ self.is_board = False
+
+ def cpu_pin_name(self):
+ return "GPIO{:d}".format(self.pin)
+
+ def is_board_pin(self):
+ return self.is_board
+
+ def set_is_board_pin(self):
+ self.is_board = True
+
+
+class NamedPin:
+ def __init__(self, name, pin):
+ self._name = name
+ self._pin = pin
+
+ def pin(self):
+ return self._pin
+
+ def name(self):
+ return self._name
+
+
+class Pins:
+ def __init__(self):
+ self.cpu_pins = [] # list of NamedPin objects
+ self.board_pins = [] # list of NamedPin objects
+
+ def find_pin(self, pin_name):
+ for pin in self.cpu_pins:
+ if pin.name() == pin_name:
+ return pin.pin()
+
+ def create_pins(self):
+ for pin_num in range(MAX_CPU_PINS):
+ pin = Pin(pin_num)
+ self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin))
+
+ def parse_board_file(self, filename):
+ with open(filename, "r") as csvfile:
+ rows = csv.reader(csvfile)
+ for row in rows:
+ if len(row) == 0 or row[0].startswith("#"):
+ # Skip empty lines, and lines starting with "#"
+ continue
+ if len(row) != 2:
+ raise ValueError("Expecting two entries in a row")
+
+ cpu_pin_name = row[1]
+ parse_pin(cpu_pin_name)
+ pin = self.find_pin(cpu_pin_name)
+ if not pin:
+ raise ValueError("Unknown pin {}".format(cpu_pin_name))
+ pin.set_is_board_pin()
+ if row[0]: # Only add board pins that have a name
+ self.board_pins.append(NamedPin(row[0], pin))
+
+ def print_table(self, label, named_pins, out_source):
+ print("", file=out_source)
+ print(
+ "const machine_{}_obj_t machine_{}_obj_table[GPIO_NUM_MAX] = {{".format(label, label),
+ file=out_source,
+ )
+ for pin in named_pins:
+ print(" #if MICROPY_HW_ENABLE_{}".format(pin.name()), file=out_source)
+ print(
+ " [GPIO_NUM_{}] = {{ .base = {{ .type = &machine_{}_type }} }},".format(
+ pin.pin().pin, label
+ ),
+ file=out_source,
+ )
+ print(" #endif", file=out_source)
+ print("};", file=out_source)
+
+ def print_named(self, label, named_pins, out_source):
+ print("", file=out_source)
+ print(
+ "STATIC const mp_rom_map_elem_t machine_pin_{:s}_pins_locals_dict_table[] = {{".format(
+ label
+ ),
+ file=out_source,
+ )
+ for named_pin in named_pins:
+ pin = named_pin.pin()
+ print(
+ " {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},".format(
+ named_pin.name(), pin.cpu_pin_name()
+ ),
+ file=out_source,
+ )
+
+ print("};", file=out_source)
+ print(
+ "MP_DEFINE_CONST_DICT(machine_pin_{:s}_pins_locals_dict, machine_pin_{:s}_pins_locals_dict_table);".format(
+ label, label
+ ),
+ file=out_source,
+ )
+
+ def print_tables(self, out_source):
+ self.print_table("pin", self.cpu_pins, out_source)
+ self.print_table("pin_irq", self.cpu_pins, out_source)
+ self.print_named("board", self.board_pins, out_source)
+
+ def print_header(self, out_header):
+ # Provide #defines for each cpu pin.
+ for named_pin in self.cpu_pins:
+ pin = named_pin.pin()
+ n = pin.cpu_pin_name()
+ print("#if MICROPY_HW_ENABLE_{}".format(n), file=out_header)
+ print(
+ "#define pin_{:s} (machine_pin_obj_table[{}])".format(n, pin.pin),
+ file=out_header,
+ )
+ print("#endif", file=out_header)
+
+ # Provide #define's mapping board to cpu name.
+ for named_pin in self.board_pins:
+ if named_pin.pin().is_board_pin():
+ print(
+ "#define pin_{:s} pin_{:s}".format(
+ named_pin.name(), named_pin.pin().cpu_pin_name()
+ ),
+ file=out_header,
+ )
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Generate board specific pin file")
+ parser.add_argument("--board-csv")
+ parser.add_argument("--prefix")
+ parser.add_argument("--output-source")
+ parser.add_argument("--output-header")
+ args = parser.parse_args(sys.argv[1:])
+
+ pins = Pins()
+ pins.create_pins()
+
+ if args.board_csv:
+ pins.parse_board_file(args.board_csv)
+
+ with open(args.output_source, "w") as out_source:
+ print("// This file was automatically generated by make-pins.py", file=out_source)
+ print("//", file=out_source)
+
+ if args.board_csv:
+ print("// --board-csv {:s}".format(args.board_csv), file=out_source)
+
+ if args.prefix:
+ print("// --prefix {:s}".format(args.prefix), file=out_source)
+ print("", file=out_source)
+ with open(args.prefix, "r") as prefix_file:
+ print(prefix_file.read(), end="", file=out_source)
+
+ pins.print_tables(out_source)
+
+ with open(args.output_header, "w") as out_header:
+ pins.print_header(out_header)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/ports/esp32/boards/manifest.py b/ports/esp32/boards/manifest.py
index 3f6c8cfde5a9..290d98c4e499 100644
--- a/ports/esp32/boards/manifest.py
+++ b/ports/esp32/boards/manifest.py
@@ -1,15 +1,15 @@
freeze("$(PORT_DIR)/modules")
-include("$(MPY_DIR)/extmod/uasyncio")
+include("$(MPY_DIR)/extmod/asyncio")
+
+# Useful networking-related packages.
+require("bundle-networking")
# Require some micropython-lib modules.
+# require("aioespnow")
require("dht")
require("ds18x20")
-require("mip")
require("neopixel")
-require("ntptime")
require("onewire")
require("umqtt.robust")
require("umqtt.simple")
require("upysh")
-require("urequests")
-require("webrepl")
diff --git a/ports/esp32/boards/pins_prefix.c b/ports/esp32/boards/pins_prefix.c
new file mode 100644
index 000000000000..2733ddaab865
--- /dev/null
+++ b/ports/esp32/boards/pins_prefix.c
@@ -0,0 +1,4 @@
+#include "py/obj.h"
+#include "machine_pin.h"
+#include "modmachine.h"
+#include "genhdr/pins.h"
diff --git a/ports/esp32/boards/sdkconfig.240mhz b/ports/esp32/boards/sdkconfig.240mhz
index e36884009d1e..c89a1ed25189 100644
--- a/ports/esp32/boards/sdkconfig.240mhz
+++ b/ports/esp32/boards/sdkconfig.240mhz
@@ -1,5 +1,6 @@
# MicroPython on ESP32, ESP IDF configuration with 240MHz CPU
-CONFIG_ESP32_DEFAULT_CPU_FREQ_80=
-CONFIG_ESP32_DEFAULT_CPU_FREQ_160=
-CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
-CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_40=
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80=
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240
diff --git a/ports/esp32/boards/sdkconfig.base b/ports/esp32/boards/sdkconfig.base
index 6b891aa006b1..bf6c3f45c526 100644
--- a/ports/esp32/boards/sdkconfig.base
+++ b/ports/esp32/boards/sdkconfig.base
@@ -4,8 +4,6 @@
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
# Compiler options: use -O2 and disable assertions to improve performance
-# (CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is for IDF 4.0.2)
-CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
CONFIG_COMPILER_OPTIMIZATION_PERF=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
@@ -21,10 +19,14 @@ CONFIG_LOG_DEFAULT_LEVEL_INFO=n
CONFIG_LOG_DEFAULT_LEVEL_ERROR=y
CONFIG_LOG_DEFAULT_LEVEL=1
-# ESP32-specific
+# Main XTAL Config
+# Only on: ESP32
+CONFIG_XTAL_FREQ_AUTO=y
+
+# ESP System Settings
+# Only on: ESP32, ESP32S3
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n
-CONFIG_ESP32_XTAL_FREQ_AUTO=y
# Power Management
CONFIG_PM_ENABLE=y
@@ -44,12 +46,14 @@ CONFIG_LWIP_PPP_PAP_SUPPORT=y
CONFIG_LWIP_PPP_CHAP_SUPPORT=y
# SSL
-# Use 4kiB output buffer instead of default 16kiB (because IDF heap is fragmented in 4.0)
+# Use 4kiB output buffer instead of default 16kiB
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
# ULP coprocessor support
-CONFIG_ESP32_ULP_COPROC_ENABLED=y
-CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=2040
+# Only on: ESP32, ESP32S2, ESP32S3
+CONFIG_ULP_COPROC_ENABLED=y
+CONFIG_ULP_COPROC_TYPE_FSM=y
+CONFIG_ULP_COPROC_RESERVE_MEM=2040
# For cmake build
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
@@ -60,7 +64,16 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_ESP32_WIFI_IRAM_OPT=n
CONFIG_ESP32_WIFI_RX_IRAM_OPT=n
-# ADC calibration
+# Legacy ADC Calibration Configuration
+# Only on: ESP32
CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
CONFIG_ADC_CAL_LUT_ENABLE=y
+
+# UART Configuration
+CONFIG_UART_ISR_IN_IRAM=y
+
+# IDF 5 deprecated
+CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
+CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
+CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
diff --git a/ports/esp32/boards/sdkconfig.ble b/ports/esp32/boards/sdkconfig.ble
index 08d5e481f499..91ac3240ebee 100644
--- a/ports/esp32/boards/sdkconfig.ble
+++ b/ports/esp32/boards/sdkconfig.ble
@@ -1,9 +1,14 @@
-# Note this requires building with IDF 4.x
+CONFIG_BT_NIMBLE_LOG_LEVEL_ERROR=y
CONFIG_BT_ENABLED=y
-CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
-CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=
-CONFIG_BTDM_CTRL_MODE_BTDM=
-
CONFIG_BT_NIMBLE_ENABLED=y
+CONFIG_BT_CONTROLLER_ENABLED=y
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4
+
+# Put NimBLE on core 1, and for synchronisation
+# with the ringbuffer and scheduler MP needs to be on the same core.
+# MP on core 1 prevents interference with WiFi for time sensitive operations.
+# Only on: ESP32, ESP32S2, ESP32S3
+CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n
+CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
+CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
diff --git a/ports/esp32/boards/sdkconfig.nimble_core0 b/ports/esp32/boards/sdkconfig.nimble_core0
deleted file mode 100644
index cacaff1197cb..000000000000
--- a/ports/esp32/boards/sdkconfig.nimble_core0
+++ /dev/null
@@ -1,6 +0,0 @@
-# For IDF <4.2, we need NimBLE on core 0, and for synchronisation
-# with the ringbuffer and scheduler MP needs to be on the same core.
-# See https://github.com/micropython/micropython/issues/5489
-CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y
-CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=n
-CONFIG_BT_NIMBLE_PINNED_TO_CORE=0
diff --git a/ports/esp32/boards/sdkconfig.nimble_core1 b/ports/esp32/boards/sdkconfig.nimble_core1
deleted file mode 100644
index 33653cc4b164..000000000000
--- a/ports/esp32/boards/sdkconfig.nimble_core1
+++ /dev/null
@@ -1,6 +0,0 @@
-# For IDF >=4.2, we are able to put NimBLE on core 1, and for synchronisation
-# with the ringbuffer and scheduler MP needs to be on the same core.
-# MP on core 1 prevents interference with WiFi for time sensitive operations.
-CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n
-CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
-CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
diff --git a/ports/esp32/boards/sdkconfig.spiram b/ports/esp32/boards/sdkconfig.spiram
index 5b4ce118b890..74d35f7b4ad4 100644
--- a/ports/esp32/boards/sdkconfig.spiram
+++ b/ports/esp32/boards/sdkconfig.spiram
@@ -1,6 +1,11 @@
# MicroPython on ESP32, ESP IDF configuration with SPIRAM support
-CONFIG_ESP32_SPIRAM_SUPPORT=y
+CONFIG_SPIRAM=y
CONFIG_SPIRAM_CACHE_WORKAROUND=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
-CONFIG_SPIRAM_USE_MEMMAP=y
+CONFIG_SPIRAM_USE_CAPS_ALLOC=y
+
+# SPIRAM increases the size of the firmware and overflows iram0_0_seg, due
+# to PSRAM bug workarounds. Apply some options to reduce the firmware size.
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
+CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y
diff --git a/ports/esp32/boards/sdkconfig.spiram_oct b/ports/esp32/boards/sdkconfig.spiram_oct
new file mode 100644
index 000000000000..aaea64fcd5c0
--- /dev/null
+++ b/ports/esp32/boards/sdkconfig.spiram_oct
@@ -0,0 +1,3 @@
+# MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support in Octal mode
+CONFIG_SPIRAM_MODE_QUAD=
+CONFIG_SPIRAM_MODE_OCT=y
diff --git a/ports/esp32/boards/sdkconfig.spiram_sx b/ports/esp32/boards/sdkconfig.spiram_sx
index ef24e90829e1..329a50733710 100644
--- a/ports/esp32/boards/sdkconfig.spiram_sx
+++ b/ports/esp32/boards/sdkconfig.spiram_sx
@@ -1,15 +1,10 @@
# MicroPython on ESP32-S2 and ESP32-PAD1_subscript_3, ESP IDF configuration with SPIRAM support
-CONFIG_ESP32S2_SPIRAM_SUPPORT=y
-CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_QUAD=y
CONFIG_SPIRAM_TYPE_AUTO=y
-CONFIG_DEFAULT_PSRAM_CLK_IO=30
-CONFIG_DEFAULT_PSRAM_CS_IO=26
+CONFIG_SPIRAM_CLK_IO=30
+CONFIG_SPIRAM_CS_IO=26
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
-CONFIG_SPIRAM_USE_MEMMAP=y
-CONFIG_SPIRAM_MEMTEST=y
-CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
-CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
+CONFIG_SPIRAM_USE_CAPS_ALLOC=y
diff --git a/ports/esp32/boards/sdkconfig.usb b/ports/esp32/boards/sdkconfig.usb
index 657edbc58059..4090c710e62e 100644
--- a/ports/esp32/boards/sdkconfig.usb
+++ b/ports/esp32/boards/sdkconfig.usb
@@ -1,4 +1,4 @@
-CONFIG_USB_ENABLED=y
-CONFIG_USB_CDC_ENABLED=y
-CONFIG_USB_CDC_RX_BUFSIZE=256
-CONFIG_USB_CDC_TX_BUFSIZE=256
+CONFIG_USB_OTG_SUPPORTED=y
+CONFIG_TINYUSB_CDC_ENABLED=y
+CONFIG_TINYUSB_CDC_RX_BUFSIZE=256
+CONFIG_TINYUSB_CDC_TX_BUFSIZE=256
diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake
new file mode 100644
index 000000000000..37a19316b603
--- /dev/null
+++ b/ports/esp32/esp32_common.cmake
@@ -0,0 +1,229 @@
+# Set location of base MicroPython directory.
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../.. ABSOLUTE)
+endif()
+
+# Set location of the ESP32 port directory.
+if(NOT MICROPY_PORT_DIR)
+ get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
+endif()
+
+# Include core source components.
+include(${MICROPY_DIR}/py/py.cmake)
+
+if(NOT CMAKE_BUILD_EARLY_EXPANSION)
+ # Enable extmod components that will be configured by extmod.cmake.
+ # A board may also have enabled additional components.
+ set(MICROPY_PY_BTREE ON)
+
+ include(${MICROPY_DIR}/py/usermod.cmake)
+ include(${MICROPY_DIR}/extmod/extmod.cmake)
+endif()
+
+list(APPEND MICROPY_QSTRDEFS_PORT
+ ${MICROPY_PORT_DIR}/qstrdefsport.h
+)
+
+list(APPEND MICROPY_SOURCE_SHARED
+ ${MICROPY_DIR}/shared/readline/readline.c
+ ${MICROPY_DIR}/shared/netutils/netutils.c
+ ${MICROPY_DIR}/shared/timeutils/timeutils.c
+ ${MICROPY_DIR}/shared/runtime/interrupt_char.c
+ ${MICROPY_DIR}/shared/runtime/stdout_helpers.c
+ ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
+ ${MICROPY_DIR}/shared/runtime/pyexec.c
+)
+
+list(APPEND MICROPY_SOURCE_LIB
+ ${MICROPY_DIR}/lib/littlefs/lfs1.c
+ ${MICROPY_DIR}/lib/littlefs/lfs1_util.c
+ ${MICROPY_DIR}/lib/littlefs/lfs2.c
+ ${MICROPY_DIR}/lib/littlefs/lfs2_util.c
+ #${MICROPY_DIR}/lib/mbedtls_errors/esp32_mbedtls_errors.c
+ ${MICROPY_DIR}/lib/oofatfs/ff.c
+ ${MICROPY_DIR}/lib/oofatfs/ffunicode.c
+)
+
+list(APPEND MICROPY_SOURCE_DRIVERS
+ ${MICROPY_DIR}/drivers/bus/softspi.c
+ ${MICROPY_DIR}/drivers/dht/dht.c
+)
+
+list(APPEND MICROPY_SOURCE_PORT
+ main.c
+ ppp_set_auth.c
+ uart.c
+ usb.c
+ usb_serial_jtag.c
+ gccollect.c
+ mphalport.c
+ fatfs_port.c
+ help.c
+ machine_bitstream.c
+ machine_timer.c
+ machine_pin.c
+ machine_touchpad.c
+ machine_adc.c
+ machine_adcblock.c
+ machine_dac.c
+ machine_i2c.c
+ machine_i2s.c
+ machine_uart.c
+ modmachine.c
+ network_common.c
+ network_lan.c
+ network_ppp.c
+ network_wlan.c
+ mpnimbleport.c
+ modsocket.c
+ modesp.c
+ esp32_nvs.c
+ esp32_partition.c
+ esp32_rmt.c
+ esp32_ulp.c
+ modesp32.c
+ machine_hw_spi.c
+ machine_wdt.c
+ mpthreadport.c
+ machine_rtc.c
+ machine_sdcard.c
+ modespnow.c
+)
+list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)
+list(APPEND MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins.c)
+
+list(APPEND MICROPY_SOURCE_QSTR
+ ${MICROPY_SOURCE_PY}
+ ${MICROPY_SOURCE_EXTMOD}
+ ${MICROPY_SOURCE_USERMOD}
+ ${MICROPY_SOURCE_SHARED}
+ ${MICROPY_SOURCE_LIB}
+ ${MICROPY_SOURCE_PORT}
+ ${MICROPY_SOURCE_BOARD}
+)
+
+list(APPEND IDF_COMPONENTS
+ app_update
+ bootloader_support
+ bt
+ driver
+ esp_adc
+ esp_app_format
+ esp_common
+ esp_eth
+ esp_event
+ esp_hw_support
+ esp_netif
+ esp_partition
+ esp_pm
+ esp_psram
+ esp_ringbuf
+ esp_rom
+ esp_system
+ esp_timer
+ esp_wifi
+ freertos
+ hal
+ heap
+ log
+ lwip
+ mbedtls
+ newlib
+ nvs_flash
+ sdmmc
+ soc
+ spi_flash
+ ulp
+ vfs
+ xtensa
+)
+
+# Register the main IDF component.
+idf_component_register(
+ SRCS
+ ${MICROPY_SOURCE_PY}
+ ${MICROPY_SOURCE_EXTMOD}
+ ${MICROPY_SOURCE_SHARED}
+ ${MICROPY_SOURCE_LIB}
+ ${MICROPY_SOURCE_DRIVERS}
+ ${MICROPY_SOURCE_PORT}
+ ${MICROPY_SOURCE_BOARD}
+ INCLUDE_DIRS
+ ${MICROPY_INC_CORE}
+ ${MICROPY_INC_USERMOD}
+ ${MICROPY_PORT_DIR}
+ ${MICROPY_BOARD_DIR}
+ ${CMAKE_BINARY_DIR}
+ REQUIRES
+ ${IDF_COMPONENTS}
+)
+
+# Set the MicroPython target as the current (main) IDF component target.
+set(MICROPY_TARGET ${COMPONENT_TARGET})
+
+# Define mpy-cross flags, for use with frozen code.
+set(MICROPY_CROSS_FLAGS -march=xtensawin)
+
+# Set compile options for this port.
+target_compile_definitions(${MICROPY_TARGET} PUBLIC
+ ${MICROPY_DEF_CORE}
+ MICROPY_ESP_IDF_4=1
+ MICROPY_VFS_FAT=1
+ MICROPY_VFS_LFS2=1
+ FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\"
+ LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT
+ LFS2_NO_MALLOC LFS2_NO_DEBUG LFS2_NO_WARN LFS2_NO_ERROR LFS2_NO_ASSERT
+)
+
+# Disable some warnings to keep the build output clean.
+target_compile_options(${MICROPY_TARGET} PUBLIC
+ -Wno-clobbered
+ -Wno-deprecated-declarations
+ -Wno-missing-field-initializers
+)
+
+# Additional include directories needed for private NimBLE headers.
+target_include_directories(${MICROPY_TARGET} PUBLIC
+ ${IDF_PATH}/components/bt/host/nimble/nimble
+)
+
+# Add additional extmod and usermod components.
+target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree)
+target_link_libraries(${MICROPY_TARGET} usermod)
+
+# Collect all of the include directories and compile definitions for the IDF components,
+# including those added by the IDF Component Manager via idf_components.yaml.
+foreach(comp ${__COMPONENT_NAMES_RESOLVED})
+ micropy_gather_target_properties(__idf_${comp})
+ micropy_gather_target_properties(${comp})
+endforeach()
+
+# Include the main MicroPython cmake rules.
+include(${MICROPY_DIR}/py/mkrules.cmake)
+
+# Generate source files for named pins (requires mkrules.cmake for MICROPY_GENHDR_DIR).
+
+set(GEN_PINS_PREFIX "${MICROPY_PORT_DIR}/boards/pins_prefix.c")
+set(GEN_PINS_MKPINS "${MICROPY_PORT_DIR}/boards/make-pins.py")
+set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins.c")
+set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h")
+
+if(EXISTS "${MICROPY_BOARD_DIR}/pins.csv")
+ set(GEN_PINS_BOARD_CSV "${MICROPY_BOARD_DIR}/pins.csv")
+ set(GEN_PINS_BOARD_CSV_ARG --board-csv "${GEN_PINS_BOARD_CSV}")
+endif()
+
+target_sources(${MICROPY_TARGET} PRIVATE ${GEN_PINS_HDR})
+
+add_custom_command(
+ OUTPUT ${GEN_PINS_SRC} ${GEN_PINS_HDR}
+ COMMAND ${Python3_EXECUTABLE} ${GEN_PINS_MKPINS} ${GEN_PINS_BOARD_CSV_ARG}
+ --prefix ${GEN_PINS_PREFIX} --output-source ${GEN_PINS_SRC} --output-header ${GEN_PINS_HDR}
+ DEPENDS
+ ${MICROPY_MPVERSION}
+ ${GEN_PINS_MKPINS}
+ ${GEN_PINS_BOARD_CSV}
+ ${GEN_PINS_PREFIX}
+ VERBATIM
+ COMMAND_EXPAND_LISTS
+)
diff --git a/ports/esp32/esp32_rmt.c b/ports/esp32/esp32_rmt.c
index 78c8c8aceeff..f92af636f55a 100644
--- a/ports/esp32/esp32_rmt.c
+++ b/ports/esp32/esp32_rmt.c
@@ -48,11 +48,7 @@
// and carrier output.
// Last available RMT channel that can transmit.
-#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0)
-#define RMT_LAST_TX_CHANNEL (RMT_CHANNEL_MAX - 1)
-#else
#define RMT_LAST_TX_CHANNEL (SOC_RMT_TX_CANDIDATES_PER_GROUP - 1)
-#endif
// Forward declaration
extern const mp_obj_type_t esp32_rmt_type;
@@ -326,13 +322,13 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
check_esp_err(rmt_wait_tx_done(self->channel_id, portMAX_DELAY));
}
- check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
-
if (self->loop_en) {
check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
check_esp_err(rmt_set_tx_loop_mode(self->channel_id, true));
}
+ check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
+
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_write_pulses_obj, 2, 3, esp32_rmt_write_pulses);
diff --git a/ports/esp32/esp32_ulp.c b/ports/esp32/esp32_ulp.c
index 843bdb2366df..97041c60bd6b 100644
--- a/ports/esp32/esp32_ulp.c
+++ b/ports/esp32/esp32_ulp.c
@@ -26,10 +26,15 @@
#include "py/runtime.h"
-#if CONFIG_IDF_TARGET_ESP32
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+#if CONFIG_IDF_TARGET_ESP32
#include "esp32/ulp.h"
-#include "esp_err.h"
+#elif CONFIG_IDF_TARGET_ESP32S2
+#include "esp32s2/ulp.h"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#include "esp32s3/ulp.h"
+#endif
typedef struct _esp32_ulp_obj_t {
mp_obj_base_t base;
@@ -87,7 +92,7 @@ STATIC const mp_rom_map_elem_t esp32_ulp_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_set_wakeup_period), MP_ROM_PTR(&esp32_ulp_set_wakeup_period_obj) },
{ MP_ROM_QSTR(MP_QSTR_load_binary), MP_ROM_PTR(&esp32_ulp_load_binary_obj) },
{ MP_ROM_QSTR(MP_QSTR_run), MP_ROM_PTR(&esp32_ulp_run_obj) },
- { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ESP32_ULP_COPROC_RESERVE_MEM) },
+ { MP_ROM_QSTR(MP_QSTR_RESERVE_MEM), MP_ROM_INT(CONFIG_ULP_COPROC_RESERVE_MEM) },
};
STATIC MP_DEFINE_CONST_DICT(esp32_ulp_locals_dict, esp32_ulp_locals_dict_table);
@@ -99,4 +104,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &esp32_ulp_locals_dict
);
-#endif // CONFIG_IDF_TARGET_ESP32
+#endif // CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
diff --git a/ports/esp32/gccollect.c b/ports/esp32/gccollect.c
index 403a3c7dfa0f..6fa287de28c0 100644
--- a/ports/esp32/gccollect.c
+++ b/ports/esp32/gccollect.c
@@ -34,7 +34,6 @@
#include "py/gc.h"
#include "py/mpthread.h"
#include "gccollect.h"
-#include "soc/cpu.h"
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
@@ -50,7 +49,7 @@ static void gc_collect_inner(int level) {
if (level == XCHAL_NUM_AREGS / 8) {
// get the sp
- volatile uint32_t sp = (uint32_t)get_sp();
+ volatile uint32_t sp = (uint32_t)esp_cpu_get_sp();
gc_collect_root((void **)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
return;
}
diff --git a/ports/esp32/help.c b/ports/esp32/help.c
index 2336d97f8441..2351d7dc7394 100644
--- a/ports/esp32/help.c
+++ b/ports/esp32/help.c
@@ -31,7 +31,7 @@
const char esp32_help_text[] =
"Welcome to MicroPython on the ESP32!\n"
"\n"
- "For generic online docs please visit http://docs.micropython.org/\n"
+ "For online docs please visit http://docs.micropython.org/\n"
"\n"
"For access to the hardware use the 'machine' module:\n"
"\n"
diff --git a/ports/esp32/machine_adcblock.h b/ports/esp32/machine_adcblock.h
index 0500726d7179..7c9249b072c1 100644
--- a/ports/esp32/machine_adcblock.h
+++ b/ports/esp32/machine_adcblock.h
@@ -3,6 +3,8 @@
#include "esp_adc_cal.h"
+#define ADC_ATTEN_MAX SOC_ADC_ATTEN_NUM
+
typedef struct _madcblock_obj_t {
mp_obj_base_t base;
adc_unit_t unit_id;
diff --git a/ports/esp32/machine_bitstream.c b/ports/esp32/machine_bitstream.c
index 4284b5f8baf7..87a5ae53cfe5 100644
--- a/ports/esp32/machine_bitstream.c
+++ b/ports/esp32/machine_bitstream.c
@@ -28,6 +28,10 @@
#include "py/mphal.h"
#include "modesp32.h"
+#include "rom/gpio.h"
+#include "soc/gpio_reg.h"
+#include "soc/gpio_sig_map.h"
+
#if MICROPY_PY_MACHINE_BITSTREAM
/******************************************************************************/
@@ -52,7 +56,7 @@ STATIC void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, u
}
// Convert ns to cpu ticks [high_time_0, period_0, high_time_1, period_1].
- uint32_t fcpu_mhz = ets_get_cpu_frequency();
+ uint32_t fcpu_mhz = esp_rom_get_cpu_ticks_per_us();
for (size_t i = 0; i < 4; ++i) {
timing_ns[i] = fcpu_mhz * timing_ns[i] / 1000;
if (timing_ns[i] > NS_TICKS_OVERHEAD) {
@@ -91,27 +95,6 @@ STATIC void IRAM_ATTR machine_bitstream_high_low_bitbang(mp_hal_pin_obj_t pin, u
#include "driver/rmt.h"
-#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
-// This convenience macro was not available in earlier IDF versions.
-#define RMT_DEFAULT_CONFIG_TX(gpio, channel_id) \
- { \
- .rmt_mode = RMT_MODE_TX, \
- .channel = channel_id, \
- .clk_div = 80, \
- .gpio_num = gpio, \
- .mem_block_num = 1, \
- .tx_config = { \
- .loop_en = false, \
- .carrier_freq_hz = 38000, \
- .carrier_duty_percent = 33, \
- .carrier_level = RMT_CARRIER_LEVEL_HIGH, \
- .carrier_en = false, \
- .idle_level = RMT_IDLE_LEVEL_LOW, \
- .idle_output_en = true, \
- } \
- }
-#endif
-
// Logical 0 and 1 values (encoded as a rmt_item32_t).
// The duration fields will be set later.
STATIC rmt_item32_t bitstream_high_low_0 = {{{ 0, 1, 0, 0 }}};
@@ -163,13 +146,7 @@ STATIC void machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timin
// Get the tick rate in kHz (this will likely be 40000).
uint32_t counter_clk_khz = 0;
- #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
- uint8_t div_cnt;
- check_esp_err(rmt_get_clk_div(config.channel, &div_cnt));
- counter_clk_khz = APB_CLK_FREQ / div_cnt;
- #else
check_esp_err(rmt_get_counter_clock(config.channel, &counter_clk_khz));
- #endif
counter_clk_khz /= 1000;
@@ -193,7 +170,7 @@ STATIC void machine_bitstream_high_low_rmt(mp_hal_pin_obj_t pin, uint32_t *timin
check_esp_err(rmt_driver_uninstall(config.channel));
// Cancel RMT output to GPIO pin.
- gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false);
+ esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
}
/******************************************************************************/
diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c
index 647874e17f64..e09c493f5b94 100644
--- a/ports/esp32/machine_hw_spi.c
+++ b/ports/esp32/machine_hw_spi.c
@@ -35,6 +35,8 @@
#include "modmachine.h"
#include "driver/spi_master.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/spi_pins.h"
// SPI mappings by device, naming used by IDF old/new
// upython | ESP32 | ESP32S2 | ESP32S3 | ESP32C3
@@ -42,34 +44,30 @@
// SPI(id=1) | HSPI/SPI2 | FSPI/SPI2 | SPI2 | SPI2
// SPI(id=2) | VSPI/SPI3 | HSPI/SPI3 | SPI3 | err
+// Number of available hardware SPI peripherals.
+#if SOC_SPI_PERIPH_NUM > 2
+#define MICROPY_HW_SPI_MAX (2)
+#else
+#define MICROPY_HW_SPI_MAX (1)
+#endif
+
// Default pins for SPI(id=1) aka IDF SPI2, can be overridden by a board
#ifndef MICROPY_HW_SPI1_SCK
-#ifdef SPI2_IOMUX_PIN_NUM_CLK
// Use IO_MUX pins by default.
// If SPI lines are routed to other pins through GPIO matrix
// routing adds some delay and lower limit applies to SPI clk freq
-#define MICROPY_HW_SPI1_SCK SPI2_IOMUX_PIN_NUM_CLK // pin 14 on ESP32
-#define MICROPY_HW_SPI1_MOSI SPI2_IOMUX_PIN_NUM_MOSI // pin 13 on ESP32
-#define MICROPY_HW_SPI1_MISO SPI2_IOMUX_PIN_NUM_MISO // pin 12 on ESP32
-// Only for compatibility with IDF 4.2 and older
-#elif CONFIG_IDF_TARGET_ESP32S2
-#define MICROPY_HW_SPI1_SCK FSPI_IOMUX_PIN_NUM_CLK
-#define MICROPY_HW_SPI1_MOSI FSPI_IOMUX_PIN_NUM_MOSI
-#define MICROPY_HW_SPI1_MISO FSPI_IOMUX_PIN_NUM_MISO
-#else
-#define MICROPY_HW_SPI1_SCK HSPI_IOMUX_PIN_NUM_CLK
-#define MICROPY_HW_SPI1_MOSI HSPI_IOMUX_PIN_NUM_MOSI
-#define MICROPY_HW_SPI1_MISO HSPI_IOMUX_PIN_NUM_MISO
-#endif
+#define MICROPY_HW_SPI1_SCK SPI2_IOMUX_PIN_NUM_CLK
+#define MICROPY_HW_SPI1_MOSI SPI2_IOMUX_PIN_NUM_MOSI
+#define MICROPY_HW_SPI1_MISO SPI2_IOMUX_PIN_NUM_MISO
#endif
// Default pins for SPI(id=2) aka IDF SPI3, can be overridden by a board
#ifndef MICROPY_HW_SPI2_SCK
#if CONFIG_IDF_TARGET_ESP32
// ESP32 has IO_MUX pins for VSPI/SPI3 lines, use them as defaults
-#define MICROPY_HW_SPI2_SCK VSPI_IOMUX_PIN_NUM_CLK // pin 18
-#define MICROPY_HW_SPI2_MOSI VSPI_IOMUX_PIN_NUM_MOSI // pin 23
-#define MICROPY_HW_SPI2_MISO VSPI_IOMUX_PIN_NUM_MISO // pin 19
+#define MICROPY_HW_SPI2_SCK SPI3_IOMUX_PIN_NUM_CLK // pin 18
+#define MICROPY_HW_SPI2_MOSI SPI3_IOMUX_PIN_NUM_MOSI // pin 23
+#define MICROPY_HW_SPI2_MISO SPI3_IOMUX_PIN_NUM_MISO // pin 19
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
// ESP32S2 and S3 uses GPIO matrix for SPI3 pins, no IO_MUX possible
// Set defaults to the pins used by SPI2 in Octal mode
@@ -82,13 +80,6 @@
#define MP_HW_SPI_MAX_XFER_BYTES (4092)
#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8
-#if CONFIG_IDF_TARGET_ESP32C3
-#define HSPI_HOST SPI2_HOST
-#elif CONFIG_IDF_TARGET_ESP32S3
-#define HSPI_HOST SPI3_HOST
-#define FSPI_HOST SPI2_HOST
-#endif
-
typedef struct _machine_hw_spi_default_pins_t {
int8_t sck;
int8_t mosi;
@@ -115,15 +106,15 @@ typedef struct _machine_hw_spi_obj_t {
} machine_hw_spi_obj_t;
// Default pin mappings for the hardware SPI instances
-STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[2] = {
+STATIC const machine_hw_spi_default_pins_t machine_hw_spi_default_pins[MICROPY_HW_SPI_MAX] = {
{ .sck = MICROPY_HW_SPI1_SCK, .mosi = MICROPY_HW_SPI1_MOSI, .miso = MICROPY_HW_SPI1_MISO },
#ifdef MICROPY_HW_SPI2_SCK
{ .sck = MICROPY_HW_SPI2_SCK, .mosi = MICROPY_HW_SPI2_MOSI, .miso = MICROPY_HW_SPI2_MISO },
#endif
};
-// Static objects mapping to HSPI and VSPI hardware peripherals
-STATIC machine_hw_spi_obj_t machine_hw_spi_obj[2];
+// Static objects mapping to SPI2 (and SPI3 if available) hardware peripherals.
+STATIC machine_hw_spi_obj_t machine_hw_spi_obj[MICROPY_HW_SPI_MAX];
STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
switch (spi_bus_remove_device(self->spi)) {
@@ -150,8 +141,8 @@ STATIC void machine_hw_spi_deinit_internal(machine_hw_spi_obj_t *self) {
for (int i = 0; i < 3; i++) {
if (pins[i] != -1) {
- gpio_pad_select_gpio(pins[i]);
- gpio_matrix_out(pins[i], SIG_GPIO_OUT_IDX, false, false);
+ esp_rom_gpio_pad_select_gpio(pins[i]);
+ esp_rom_gpio_connect_out_signal(pins[i], SIG_GPIO_OUT_IDX, false, false);
gpio_set_direction(pins[i], GPIO_MODE_INPUT);
}
}
@@ -226,17 +217,6 @@ STATIC void machine_hw_spi_init_internal(
changed = true;
}
- if (self->host != HSPI_HOST
- #ifdef FSPI_HOST
- && self->host != FSPI_HOST
- #endif
- #ifdef VSPI_HOST
- && self->host != VSPI_HOST
- #endif
- ) {
- mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), self->host);
- }
-
if (changed) {
if (self->state == MACHINE_HW_SPI_STATE_INIT) {
self->state = MACHINE_HW_SPI_STATE_DEINIT;
@@ -270,7 +250,7 @@ STATIC void machine_hw_spi_init_internal(
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3
dma_chan = SPI_DMA_CH_AUTO;
#else
- if (self->host == HSPI_HOST) {
+ if (self->host == SPI2_HOST) {
dma_chan = 1;
} else {
dma_chan = 2;
@@ -483,14 +463,15 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
machine_hw_spi_obj_t *self;
const machine_hw_spi_default_pins_t *default_pins;
- if (args[ARG_id].u_int == 1) { // SPI2_HOST which is FSPI_HOST on ESP32Sx, HSPI_HOST on others
- self = &machine_hw_spi_obj[0];
- default_pins = &machine_hw_spi_default_pins[0];
+ mp_int_t spi_id = args[ARG_id].u_int;
+ if (1 <= spi_id && spi_id <= MICROPY_HW_SPI_MAX) {
+ self = &machine_hw_spi_obj[spi_id - 1];
+ default_pins = &machine_hw_spi_default_pins[spi_id - 1];
} else {
- self = &machine_hw_spi_obj[1];
- default_pins = &machine_hw_spi_default_pins[1];
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
}
- self->base.type = &machine_hw_spi_type;
+
+ self->base.type = &machine_spi_type;
int8_t sck, mosi, miso;
@@ -533,6 +514,14 @@ mp_obj_t machine_hw_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_
return MP_OBJ_FROM_PTR(self);
}
+spi_host_device_t machine_hw_spi_get_host(mp_obj_t in) {
+ if (mp_obj_get_type(in) != &machine_spi_type) {
+ mp_raise_ValueError(MP_ERROR_TEXT("expecting a SPI object"));
+ }
+ machine_hw_spi_obj_t *self = (machine_hw_spi_obj_t *)in;
+ return self->host;
+}
+
STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
.init = machine_hw_spi_init,
.deinit = machine_hw_spi_deinit,
@@ -540,7 +529,7 @@ STATIC const mp_machine_spi_p_t machine_hw_spi_p = {
};
MP_DEFINE_CONST_OBJ_TYPE(
- machine_hw_spi_type,
+ machine_spi_type,
MP_QSTR_SPI,
MP_TYPE_FLAG_NONE,
make_new, machine_hw_spi_make_new,
diff --git a/ports/esp32/machine_i2c.c b/ports/esp32/machine_i2c.c
index 9244343dcf61..d498aa058d74 100644
--- a/ports/esp32/machine_i2c.c
+++ b/ports/esp32/machine_i2c.c
@@ -31,6 +31,7 @@
#include "modmachine.h"
#include "driver/i2c.h"
+#include "hal/i2c_ll.h"
#ifndef MICROPY_HW_I2C0_SCL
#define MICROPY_HW_I2C0_SCL (GPIO_NUM_18)
@@ -47,7 +48,15 @@
#endif
#endif
-#define I2C_DEFAULT_TIMEOUT_US (10000) // 10ms
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
+#define I2C_SCLK_FREQ XTAL_CLK_FREQ
+#elif CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
+#define I2C_SCLK_FREQ I2C_APB_CLK_FREQ
+#else
+#error "unsupported I2C for ESP32 SoC variant"
+#endif
+
+#define I2C_DEFAULT_TIMEOUT_US (50000) // 50ms
typedef struct _machine_hw_i2c_obj_t {
mp_obj_base_t base;
@@ -71,7 +80,8 @@ STATIC void machine_hw_i2c_init(machine_hw_i2c_obj_t *self, uint32_t freq, uint3
.master.clk_speed = freq,
};
i2c_param_config(self->port, &conf);
- i2c_set_timeout(self->port, I2C_APB_CLK_FREQ / 1000000 * timeout_us);
+ int timeout = I2C_SCLK_FREQ / 1000000 * timeout_us;
+ i2c_set_timeout(self->port, (timeout > I2C_LL_MAX_TIMEOUT) ? I2C_LL_MAX_TIMEOUT : timeout);
i2c_driver_install(self->port, I2C_MODE_MASTER, 0, 0, 0);
}
@@ -109,7 +119,7 @@ int machine_hw_i2c_transfer(mp_obj_base_t *self_in, uint16_t addr, size_t n, mp_
}
// TODO proper timeout
- esp_err_t err = i2c_master_cmd_begin(self->port, cmd, 100 * (1 + data_len) / portTICK_RATE_MS);
+ esp_err_t err = i2c_master_cmd_begin(self->port, cmd, 100 * (1 + data_len) / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (err == ESP_FAIL) {
@@ -131,7 +141,7 @@ STATIC void machine_hw_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp_p
int h, l;
i2c_get_period(self->port, &h, &l);
mp_printf(print, "I2C(%u, scl=%u, sda=%u, freq=%u)",
- self->port, self->scl, self->sda, I2C_APB_CLK_FREQ / (h + l));
+ self->port, self->scl, self->sda, I2C_SCLK_FREQ / (h + l));
}
mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@@ -161,7 +171,7 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
bool first_init = false;
if (self->base.type == NULL) {
// Created for the first time, set default pins
- self->base.type = &machine_hw_i2c_type;
+ self->base.type = &machine_i2c_type;
self->port = i2c_id;
if (self->port == I2C_NUM_0) {
self->scl = MICROPY_HW_I2C0_SCL;
@@ -175,10 +185,10 @@ mp_obj_t machine_hw_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_
// Set SCL/SDA pins if given
if (args[ARG_scl].u_obj != MP_OBJ_NULL) {
- self->scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj);
+ self->scl = machine_pin_get_id(args[ARG_scl].u_obj);
}
if (args[ARG_sda].u_obj != MP_OBJ_NULL) {
- self->sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj);
+ self->sda = machine_pin_get_id(args[ARG_sda].u_obj);
}
// Initialise the I2C peripheral
@@ -193,7 +203,7 @@ STATIC const mp_machine_i2c_p_t machine_hw_i2c_p = {
};
MP_DEFINE_CONST_OBJ_TYPE(
- machine_hw_i2c_type,
+ machine_i2c_type,
MP_QSTR_I2C,
MP_TYPE_FLAG_NONE,
make_new, machine_hw_i2c_make_new,
diff --git a/ports/esp32/machine_i2s.c b/ports/esp32/machine_i2s.c
index ce1cb59849dc..95751c87c3e6 100644
--- a/ports/esp32/machine_i2s.c
+++ b/ports/esp32/machine_i2s.c
@@ -61,9 +61,9 @@
// - a FreeRTOS task is created to implement the asynchronous background operations
// - a FreeRTOS queue is used to transfer the supplied buffer to the background task
//
-// Mode3: Uasyncio
+// Mode3: Asyncio
// - implements the stream protocol
-// - uasyncio mode is enabled when the ioctl() function is called
+// - asyncio mode is enabled when the ioctl() function is called
// - the I2S event queue is used to detect that I2S samples can be read or written from/to DMA memory
//
// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
@@ -102,7 +102,7 @@ typedef enum {
typedef enum {
BLOCKING,
NON_BLOCKING,
- UASYNCIO
+ ASYNCIO
} io_mode_t;
typedef enum {
@@ -148,7 +148,7 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT
};
void machine_i2s_init0() {
- for (i2s_port_t p = 0; p < I2S_NUM_MAX; p++) {
+ for (i2s_port_t p = 0; p < I2S_NUM_AUTO; p++) {
MP_STATE_PORT(machine_i2s_obj)[p] = NULL;
}
}
@@ -240,7 +240,7 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *
// copy audio samples from DMA memory to the app buffer
// audio samples are read from DMA memory in chunks
// loop, reading and copying chunks until the app buffer is filled
- // For uasyncio mode, the loop will make an early exit if DMA memory becomes empty
+ // For asyncio mode, the loop will make an early exit if DMA memory becomes empty
// Example:
// a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
// For every frame coming from DMA (8 bytes), 2 bytes are "cherry picked" and
@@ -257,7 +257,7 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *
size_t num_bytes_received_from_dma = 0;
TickType_t delay;
- if (self->io_mode == UASYNCIO) {
+ if (self->io_mode == ASYNCIO) {
delay = 0; // stop i2s_read() operation if DMA memory becomes empty
} else {
delay = portMAX_DELAY; // block until supplied buffer is filled
@@ -269,15 +269,6 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *
num_bytes_requested_from_dma,
&num_bytes_received_from_dma,
delay);
-
- // the following is a workaround for a bug in ESP-IDF v4.4
- // https://github.com/espressif/esp-idf/issues/8121
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
- if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) {
- ret = ESP_OK;
- }
- #endif
-
check_esp_err(ret);
// process the transform buffer one frame at a time.
@@ -307,7 +298,7 @@ STATIC uint32_t fill_appbuf_from_dma(machine_i2s_obj_t *self, mp_buffer_info_t *
num_bytes_needed_from_dma -= num_bytes_received_from_dma;
- if ((self->io_mode == UASYNCIO) && (num_bytes_received_from_dma < num_bytes_requested_from_dma)) {
+ if ((self->io_mode == ASYNCIO) && (num_bytes_received_from_dma < num_bytes_requested_from_dma)) {
// Unable to fill the entire app buffer from DMA memory. This indicates all DMA RX buffers are empty.
// Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently
// supply more audio samples
@@ -327,32 +318,23 @@ STATIC size_t copy_appbuf_to_dma(machine_i2s_obj_t *self, mp_buffer_info_t *appb
size_t num_bytes_written = 0;
TickType_t delay;
- if (self->io_mode == UASYNCIO) {
+ if (self->io_mode == ASYNCIO) {
delay = 0; // stop i2s_write() operation if DMA memory becomes full
} else {
delay = portMAX_DELAY; // block until supplied buffer is emptied
}
esp_err_t ret = i2s_write(self->port, appbuf->buf, appbuf->len, &num_bytes_written, delay);
-
- // the following is a workaround for a bug in ESP-IDF v4.4
- // https://github.com/espressif/esp-idf/issues/8121
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
- if ((delay != portMAX_DELAY) && (ret == ESP_ERR_TIMEOUT)) {
- ret = ESP_OK;
- }
- #endif
-
check_esp_err(ret);
- if ((self->io_mode == UASYNCIO) && (num_bytes_written < appbuf->len)) {
+ if ((self->io_mode == ASYNCIO) && (num_bytes_written < appbuf->len)) {
// Unable to empty the entire app buffer into DMA memory. This indicates all DMA TX buffers are full.
// Clear the I2S event queue so ioctl() indicates that the I2S object cannot currently
// accept more audio samples
xQueueReset(self->i2s_event_queue);
// Undo the swap transformation as the buffer has not been completely emptied.
- // The uasyncio stream writer will use the same buffer in a future write call.
+ // The asyncio stream writer will use the same buffer in a future write call.
if ((self->bits == I2S_BITS_PER_SAMPLE_32BIT) && (self->format == STEREO)) {
swap_32_bit_stereo_channels(appbuf);
}
@@ -410,9 +392,9 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
//
// are Pins valid?
- int8_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sck].u_obj);
- int8_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_ws].u_obj);
- int8_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : mp_hal_get_pin_obj(args[ARG_sd].u_obj);
+ int8_t sck = args[ARG_sck].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sck].u_obj);
+ int8_t ws = args[ARG_ws].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_ws].u_obj);
+ int8_t sd = args[ARG_sd].u_obj == MP_OBJ_NULL ? -1 : machine_pin_get_id(args[ARG_sd].u_obj);
// is Mode valid?
i2s_mode_t mode = args[ARG_mode].u_int;
@@ -467,10 +449,8 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
i2s_config.use_apll = false;
i2s_config.tx_desc_auto_clear = true;
i2s_config.fixed_mclk = 0;
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
- i2s_config.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT;
+ i2s_config.mclk_multiple = I2S_MCLK_MULTIPLE_256;
i2s_config.bits_per_chan = 0;
- #endif
// I2S queue size equals the number of DMA buffers
check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue));
@@ -487,9 +467,7 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
#endif
i2s_pin_config_t pin_config;
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4)
pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
- #endif
pin_config.bck_io_num = self->sck;
pin_config.ws_io_num = self->ws;
@@ -527,7 +505,7 @@ STATIC mp_obj_t machine_i2s_make_new(const mp_obj_type_t *type, size_t n_pos_arg
mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
i2s_port_t port = mp_obj_get_int(args[0]);
- if (port < 0 || port >= I2S_NUM_MAX) {
+ if (port < 0 || port >= I2S_NUM_AUTO) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid id"));
}
@@ -729,7 +707,7 @@ STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint
// send the descriptor to the task that handles non-blocking mode
xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
return size;
- } else { // blocking or uasyncio mode
+ } else { // blocking or asyncio mode
mp_buffer_info_t appbuf;
appbuf.buf = (void *)buf_in;
appbuf.len = size;
@@ -759,7 +737,7 @@ STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in,
// send the descriptor to the task that handles non-blocking mode
xQueueSend(self->non_blocking_mode_queue, &descriptor, 0);
return size;
- } else { // blocking or uasyncio mode
+ } else { // blocking or asyncio mode
mp_buffer_info_t appbuf;
appbuf.buf = (void *)buf_in;
appbuf.len = size;
@@ -772,7 +750,7 @@ STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
mp_uint_t flags = arg;
- self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used
+ self->io_mode = ASYNCIO; // a call to ioctl() is an indication that asyncio is being used
if (request == MP_STREAM_POLL) {
ret = 0;
@@ -841,6 +819,6 @@ MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &machine_i2s_locals_dict
);
-MP_REGISTER_ROOT_POINTER(struct _machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_MAX]);
+MP_REGISTER_ROOT_POINTER(struct _machine_i2s_obj_t *machine_i2s_obj[I2S_NUM_AUTO]);
#endif // MICROPY_PY_MACHINE_I2S
diff --git a/ports/esp32/machine_pin.c b/ports/esp32/machine_pin.c
index 4f6f948d52af..835f16b1b066 100644
--- a/ports/esp32/machine_pin.c
+++ b/ports/esp32/machine_pin.c
@@ -5,7 +5,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2016 Damien P. George
+ * Copyright (c) 2016-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
@@ -31,14 +31,17 @@
#include "driver/gpio.h"
#include "driver/rtc_io.h"
+#include "hal/gpio_ll.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "mphalport.h"
#include "modmachine.h"
#include "extmod/virtpin.h"
+#include "machine_pin.h"
#include "machine_rtc.h"
#include "modesp32.h"
+#include "genhdr/pins.h"
#if CONFIG_IDF_TARGET_ESP32C3
#include "soc/usb_serial_jtag_reg.h"
@@ -54,178 +57,18 @@
#define GPIO_FIRST_NON_OUTPUT (46)
#endif
-typedef struct _machine_pin_obj_t {
- mp_obj_base_t base;
- gpio_num_t id;
-} machine_pin_obj_t;
-
-typedef struct _machine_pin_irq_obj_t {
- mp_obj_base_t base;
- gpio_num_t id;
-} machine_pin_irq_obj_t;
-
-STATIC const machine_pin_obj_t machine_pin_obj[] = {
- #if CONFIG_IDF_TARGET_ESP32
-
- {{&machine_pin_type}, GPIO_NUM_0},
- {{&machine_pin_type}, GPIO_NUM_1},
- {{&machine_pin_type}, GPIO_NUM_2},
- {{&machine_pin_type}, GPIO_NUM_3},
- {{&machine_pin_type}, GPIO_NUM_4},
- {{&machine_pin_type}, GPIO_NUM_5},
- {{&machine_pin_type}, GPIO_NUM_6},
- {{&machine_pin_type}, GPIO_NUM_7},
- {{&machine_pin_type}, GPIO_NUM_8},
- {{&machine_pin_type}, GPIO_NUM_9},
- {{&machine_pin_type}, GPIO_NUM_10},
- {{&machine_pin_type}, GPIO_NUM_11},
- {{&machine_pin_type}, GPIO_NUM_12},
- {{&machine_pin_type}, GPIO_NUM_13},
- {{&machine_pin_type}, GPIO_NUM_14},
- {{&machine_pin_type}, GPIO_NUM_15},
- #if CONFIG_ESP32_SPIRAM_SUPPORT
- {{NULL}, -1},
- {{NULL}, -1},
- #else
- {{&machine_pin_type}, GPIO_NUM_16},
- {{&machine_pin_type}, GPIO_NUM_17},
- #endif
- {{&machine_pin_type}, GPIO_NUM_18},
- {{&machine_pin_type}, GPIO_NUM_19},
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 2)
- {{&machine_pin_type}, GPIO_NUM_20},
- #else
- {{NULL}, -1},
- #endif
- {{&machine_pin_type}, GPIO_NUM_21},
- {{&machine_pin_type}, GPIO_NUM_22},
- {{&machine_pin_type}, GPIO_NUM_23},
- {{NULL}, -1},
- {{&machine_pin_type}, GPIO_NUM_25},
- {{&machine_pin_type}, GPIO_NUM_26},
- {{&machine_pin_type}, GPIO_NUM_27},
- {{NULL}, -1},
- {{NULL}, -1},
- {{NULL}, -1},
- {{NULL}, -1},
- {{&machine_pin_type}, GPIO_NUM_32},
- {{&machine_pin_type}, GPIO_NUM_33},
- {{&machine_pin_type}, GPIO_NUM_34},
- {{&machine_pin_type}, GPIO_NUM_35},
- {{&machine_pin_type}, GPIO_NUM_36},
- {{&machine_pin_type}, GPIO_NUM_37},
- {{&machine_pin_type}, GPIO_NUM_38},
- {{&machine_pin_type}, GPIO_NUM_39},
-
- #elif CONFIG_IDF_TARGET_ESP32C3
-
- {{&machine_pin_type}, GPIO_NUM_0},
- {{&machine_pin_type}, GPIO_NUM_1},
- {{&machine_pin_type}, GPIO_NUM_2},
- {{&machine_pin_type}, GPIO_NUM_3},
- {{&machine_pin_type}, GPIO_NUM_4},
- {{&machine_pin_type}, GPIO_NUM_5},
- {{&machine_pin_type}, GPIO_NUM_6},
- {{&machine_pin_type}, GPIO_NUM_7},
- {{&machine_pin_type}, GPIO_NUM_8},
- {{&machine_pin_type}, GPIO_NUM_9},
- {{&machine_pin_type}, GPIO_NUM_10},
- {{&machine_pin_type}, GPIO_NUM_11},
- {{&machine_pin_type}, GPIO_NUM_12},
- {{&machine_pin_type}, GPIO_NUM_13},
- {{NULL}, -1}, // 14 FLASH
- {{NULL}, -1}, // 15 FLASH
- {{NULL}, -1}, // 16 FLASH
- {{NULL}, -1}, // 17 FLASH
- #if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
- {{NULL}, -1}, // 18 is for native USB D-
- {{NULL}, -1}, // 19 is for native USB D+
- #else
- {{&machine_pin_type}, GPIO_NUM_18},
- {{&machine_pin_type}, GPIO_NUM_19},
- #endif
- {{&machine_pin_type}, GPIO_NUM_20},
- {{&machine_pin_type}, GPIO_NUM_21},
-
- #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-
- {{&machine_pin_type}, GPIO_NUM_0},
- {{&machine_pin_type}, GPIO_NUM_1},
- {{&machine_pin_type}, GPIO_NUM_2},
- {{&machine_pin_type}, GPIO_NUM_3},
- {{&machine_pin_type}, GPIO_NUM_4},
- {{&machine_pin_type}, GPIO_NUM_5},
- {{&machine_pin_type}, GPIO_NUM_6},
- {{&machine_pin_type}, GPIO_NUM_7},
- {{&machine_pin_type}, GPIO_NUM_8},
- {{&machine_pin_type}, GPIO_NUM_9},
- {{&machine_pin_type}, GPIO_NUM_10},
- {{&machine_pin_type}, GPIO_NUM_11},
- {{&machine_pin_type}, GPIO_NUM_12},
- {{&machine_pin_type}, GPIO_NUM_13},
- {{&machine_pin_type}, GPIO_NUM_14},
- {{&machine_pin_type}, GPIO_NUM_15},
- {{&machine_pin_type}, GPIO_NUM_16},
- {{&machine_pin_type}, GPIO_NUM_17},
- {{&machine_pin_type}, GPIO_NUM_18},
- #if CONFIG_USB_CDC_ENABLED
- {{NULL}, -1}, // 19 is for native USB D-
- {{NULL}, -1}, // 20 is for native USB D-
- #else
- {{&machine_pin_type}, GPIO_NUM_19},
- {{&machine_pin_type}, GPIO_NUM_20},
- #endif
- {{&machine_pin_type}, GPIO_NUM_21},
- {{NULL}, -1}, // 22 not a pin
- {{NULL}, -1}, // 23 not a pin
- {{NULL}, -1}, // 24 not a pin
- {{NULL}, -1}, // 25 not a pin
- #if CONFIG_SPIRAM
- {{NULL}, -1}, // 26 PSRAM
- #else
- {{&machine_pin_type}, GPIO_NUM_26},
- #endif
- {{NULL}, -1}, // 27 FLASH/PSRAM
- {{NULL}, -1}, // 28 FLASH/PSRAM
- {{NULL}, -1}, // 29 FLASH/PSRAM
- {{NULL}, -1}, // 30 FLASH/PSRAM
- {{NULL}, -1}, // 31 FLASH/PSRAM
- {{NULL}, -1}, // 32 FLASH/PSRAM
- #if CONFIG_SPIRAM_MODE_OCT
- {{NULL}, -1}, // 33 FLASH/PSRAM
- {{NULL}, -1}, // 34 FLASH/PSRAM
- {{NULL}, -1}, // 35 FLASH/PSRAM
- {{NULL}, -1}, // 36 FLASH/PSRAM
- {{NULL}, -1}, // 37 FLASH/PSRAM
- #else
- {{&machine_pin_type}, GPIO_NUM_33},
- {{&machine_pin_type}, GPIO_NUM_34},
- {{&machine_pin_type}, GPIO_NUM_35},
- {{&machine_pin_type}, GPIO_NUM_36},
- {{&machine_pin_type}, GPIO_NUM_37},
- #endif
- {{&machine_pin_type}, GPIO_NUM_38},
- {{&machine_pin_type}, GPIO_NUM_39}, // MTCLK
- {{&machine_pin_type}, GPIO_NUM_40}, // MTDO
- {{&machine_pin_type}, GPIO_NUM_41}, // MTDI
- {{&machine_pin_type}, GPIO_NUM_42}, // MTMS
- {{&machine_pin_type}, GPIO_NUM_43}, // U0TXD
- {{&machine_pin_type}, GPIO_NUM_44}, // U0RXD
- {{&machine_pin_type}, GPIO_NUM_45},
- {{&machine_pin_type}, GPIO_NUM_46},
-
- #endif
-
- #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO
-
- {{&machine_pin_type}, GPIO_NUM_47},
- {{&machine_pin_type}, GPIO_NUM_48},
-
- #endif
-};
+// Return the gpio_num_t index for a given pin or pin-irq object.
+#define PIN_OBJ_INDEX(self) ((self) - &machine_pin_obj_table[0])
+#define PIN_IRQ_OBJ_INDEX(self) ((self) - &machine_pin_irq_obj_table[0])
-// forward declaration
-STATIC const machine_pin_irq_obj_t machine_pin_irq_object[];
+STATIC const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) {
+ const mp_map_t *named_map = &named_pins->map;
+ mp_map_elem_t *named_elem = mp_map_lookup((mp_map_t *)named_map, name, MP_MAP_LOOKUP);
+ if (named_elem != NULL && named_elem->value != NULL) {
+ return MP_OBJ_TO_PTR(named_elem->value);
+ }
+ return NULL;
+}
void machine_pins_init(void) {
static bool did_install = false;
@@ -237,31 +80,55 @@ void machine_pins_init(void) {
}
void machine_pins_deinit(void) {
- for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj); ++i) {
- if (machine_pin_obj[i].id != (gpio_num_t)-1) {
- gpio_isr_handler_remove(machine_pin_obj[i].id);
+ for (int i = 0; i < MP_ARRAY_SIZE(machine_pin_obj_table); ++i) {
+ if (machine_pin_obj_table[i].base.type != NULL) {
+ gpio_isr_handler_remove(i);
}
}
}
STATIC void machine_pin_isr_handler(void *arg) {
machine_pin_obj_t *self = arg;
- mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[self->id];
+ mp_obj_t handler = MP_STATE_PORT(machine_pin_irq_handler)[PIN_OBJ_INDEX(self)];
mp_sched_schedule(handler, MP_OBJ_FROM_PTR(self));
mp_hal_wake_main_task_from_isr();
}
-gpio_num_t machine_pin_get_id(mp_obj_t pin_in) {
- if (mp_obj_get_type(pin_in) != &machine_pin_type) {
- mp_raise_ValueError(MP_ERROR_TEXT("expecting a pin"));
+STATIC const machine_pin_obj_t *machine_pin_find(mp_obj_t pin_in) {
+ if (mp_obj_is_type(pin_in, &machine_pin_type)) {
+ return pin_in;
+ }
+
+ // Try to find the pin via integer index into the array of all pins.
+ if (mp_obj_is_int(pin_in)) {
+ int wanted_pin = mp_obj_get_int(pin_in);
+ if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj_table)) {
+ const machine_pin_obj_t *self = (machine_pin_obj_t *)&machine_pin_obj_table[wanted_pin];
+ if (self->base.type != NULL) {
+ return self;
+ }
+ }
+ }
+
+ // Try to find the pin in the board pins dict.
+ if (mp_obj_is_str(pin_in)) {
+ const machine_pin_obj_t *self = machine_pin_find_named(&machine_pin_board_pins_locals_dict, pin_in);
+ if (self->base.type != NULL) {
+ return self;
+ }
}
- machine_pin_obj_t *self = pin_in;
- return self->id;
+
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
+}
+
+gpio_num_t machine_pin_get_id(mp_obj_t pin_in) {
+ const machine_pin_obj_t *self = machine_pin_find(pin_in);
+ return PIN_OBJ_INDEX(self);
}
STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pin_obj_t *self = self_in;
- mp_printf(print, "Pin(%u)", self->id);
+ mp_printf(print, "Pin(%u)", PIN_OBJ_INDEX(self));
}
// pin.init(mode=None, pull=-1, *, value, drive, hold)
@@ -281,32 +148,32 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
// reset the pin to digital if this is a mode-setting init (grab it back from ADC)
if (args[ARG_mode].u_obj != mp_const_none) {
- if (rtc_gpio_is_valid_gpio(self->id)) {
+ if (rtc_gpio_is_valid_gpio(PIN_OBJ_INDEX(self))) {
#if !CONFIG_IDF_TARGET_ESP32C3
- rtc_gpio_deinit(self->id);
+ rtc_gpio_deinit(PIN_OBJ_INDEX(self));
#endif
}
}
#if CONFIG_IDF_TARGET_ESP32C3
- if (self->id == 18 || self->id == 19) {
+ if (PIN_OBJ_INDEX(self) == 18 || PIN_OBJ_INDEX(self) == 19) {
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
}
#endif
// configure the pin for gpio
- gpio_pad_select_gpio(self->id);
+ esp_rom_gpio_pad_select_gpio(PIN_OBJ_INDEX(self));
// set initial value (do this before configuring mode/pull)
if (args[ARG_value].u_obj != MP_OBJ_NULL) {
- gpio_set_level(self->id, mp_obj_is_true(args[ARG_value].u_obj));
+ gpio_set_level(PIN_OBJ_INDEX(self), mp_obj_is_true(args[ARG_value].u_obj));
}
// set drive capability (do this before configuring mode)
- if (args[ARG_drive].u_obj != MP_OBJ_NULL && GPIO_IS_VALID_OUTPUT_GPIO(self->id)) {
+ if (args[ARG_drive].u_obj != MP_OBJ_NULL && GPIO_IS_VALID_OUTPUT_GPIO(PIN_OBJ_INDEX(self))) {
mp_int_t strength = mp_obj_get_int(args[ARG_drive].u_obj);
if (0 <= strength && strength < GPIO_DRIVE_CAP_MAX) {
- gpio_set_drive_capability(self->id, strength);
+ gpio_set_drive_capability(PIN_OBJ_INDEX(self), strength);
}
}
@@ -314,11 +181,11 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
if (args[ARG_mode].u_obj != mp_const_none) {
mp_int_t pin_io_mode = mp_obj_get_int(args[ARG_mode].u_obj);
#ifdef GPIO_FIRST_NON_OUTPUT
- if (self->id >= GPIO_FIRST_NON_OUTPUT && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
+ if (PIN_OBJ_INDEX(self) >= GPIO_FIRST_NON_OUTPUT && (pin_io_mode & GPIO_MODE_DEF_OUTPUT)) {
mp_raise_ValueError(MP_ERROR_TEXT("pin can only be input"));
}
#endif
- gpio_set_direction(self->id, pin_io_mode);
+ gpio_set_direction(PIN_OBJ_INDEX(self), pin_io_mode);
}
// configure pull
@@ -328,24 +195,24 @@ STATIC mp_obj_t machine_pin_obj_init_helper(const machine_pin_obj_t *self, size_
mode = mp_obj_get_int(args[ARG_pull].u_obj);
}
if (mode & GPIO_PULL_DOWN) {
- gpio_pulldown_en(self->id);
+ gpio_pulldown_en(PIN_OBJ_INDEX(self));
} else {
- gpio_pulldown_dis(self->id);
+ gpio_pulldown_dis(PIN_OBJ_INDEX(self));
}
if (mode & GPIO_PULL_UP) {
- gpio_pullup_en(self->id);
+ gpio_pullup_en(PIN_OBJ_INDEX(self));
} else {
- gpio_pullup_dis(self->id);
+ gpio_pullup_dis(PIN_OBJ_INDEX(self));
}
}
// configure pad hold
- if (args[ARG_hold].u_obj != MP_OBJ_NULL && GPIO_IS_VALID_OUTPUT_GPIO(self->id)) {
+ if (args[ARG_hold].u_obj != MP_OBJ_NULL && GPIO_IS_VALID_OUTPUT_GPIO(PIN_OBJ_INDEX(self))) {
// always disable pad hold to apply outstanding config changes
- gpio_hold_dis(self->id);
+ gpio_hold_dis(PIN_OBJ_INDEX(self));
// (re-)enable pad hold if requested
if (mp_obj_is_true(args[ARG_hold].u_obj)) {
- gpio_hold_en(self->id);
+ gpio_hold_en(PIN_OBJ_INDEX(self));
}
}
@@ -357,14 +224,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// get the wanted pin object
- int wanted_pin = mp_obj_get_int(args[0]);
- const machine_pin_obj_t *self = NULL;
- if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(machine_pin_obj)) {
- self = (machine_pin_obj_t *)&machine_pin_obj[wanted_pin];
- }
- if (self == NULL || self->base.type == NULL) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
- }
+ const machine_pin_obj_t *self = machine_pin_find(args[0]);
if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO
@@ -382,10 +242,10 @@ STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c
machine_pin_obj_t *self = self_in;
if (n_args == 0) {
// get pin
- return MP_OBJ_NEW_SMALL_INT(gpio_get_level(self->id));
+ return MP_OBJ_NEW_SMALL_INT(gpio_get_level(PIN_OBJ_INDEX(self)));
} else {
// set pin
- gpio_set_level(self->id, mp_obj_is_true(args[0]));
+ gpio_set_level(PIN_OBJ_INDEX(self), mp_obj_is_true(args[0]));
return mp_const_none;
}
}
@@ -405,7 +265,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_
// pin.off()
STATIC mp_obj_t machine_pin_off(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
- gpio_set_level(self->id, 0);
+ gpio_set_level(PIN_OBJ_INDEX(self), 0);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);
@@ -413,7 +273,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_off_obj, machine_pin_off);
// pin.on()
STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
- gpio_set_level(self->id, 1);
+ gpio_set_level(PIN_OBJ_INDEX(self), 1);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);
@@ -423,7 +283,7 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
enum { ARG_handler, ARG_trigger, ARG_wake };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE} },
+ { MP_QSTR_trigger, MP_ARG_INT, {.u_int = GPIO_INTR_POSEDGE | GPIO_INTR_NEGEDGE} },
{ MP_QSTR_wake, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
@@ -436,7 +296,7 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
uint32_t trigger = args[ARG_trigger].u_int;
mp_obj_t wake_obj = args[ARG_wake].u_obj;
- if ((trigger == GPIO_PIN_INTR_LOLEVEL || trigger == GPIO_PIN_INTR_HILEVEL) && wake_obj != mp_const_none) {
+ if ((trigger == GPIO_INTR_LOW_LEVEL || trigger == GPIO_INTR_HIGH_LEVEL) && wake_obj != mp_const_none) {
mp_int_t wake;
if (mp_obj_get_int_maybe(wake_obj, &wake)) {
if (wake < 2 || wake > 7) {
@@ -450,20 +310,20 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
mp_raise_ValueError(MP_ERROR_TEXT("no resources"));
}
- if (!RTC_IS_VALID_EXT_PIN(self->id)) {
+ if (!RTC_IS_VALID_EXT_PIN(PIN_OBJ_INDEX(self))) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid pin for wake"));
}
if (machine_rtc_config.ext0_pin == -1) {
- machine_rtc_config.ext0_pin = self->id;
- } else if (machine_rtc_config.ext0_pin != self->id) {
+ machine_rtc_config.ext0_pin = PIN_OBJ_INDEX(self);
+ } else if (machine_rtc_config.ext0_pin != PIN_OBJ_INDEX(self)) {
mp_raise_ValueError(MP_ERROR_TEXT("no resources"));
}
- machine_rtc_config.ext0_level = trigger == GPIO_PIN_INTR_LOLEVEL ? 0 : 1;
+ machine_rtc_config.ext0_level = trigger == GPIO_INTR_LOW_LEVEL ? 0 : 1;
machine_rtc_config.ext0_wake_types = wake;
} else {
- if (machine_rtc_config.ext0_pin == self->id) {
+ if (machine_rtc_config.ext0_pin == PIN_OBJ_INDEX(self)) {
machine_rtc_config.ext0_pin = -1;
}
@@ -471,18 +331,25 @@ STATIC mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_
handler = MP_OBJ_NULL;
trigger = 0;
}
- gpio_isr_handler_remove(self->id);
- MP_STATE_PORT(machine_pin_irq_handler)[self->id] = handler;
- gpio_set_intr_type(self->id, trigger);
- gpio_isr_handler_add(self->id, machine_pin_isr_handler, (void *)self);
+ gpio_isr_handler_remove(PIN_OBJ_INDEX(self));
+ MP_STATE_PORT(machine_pin_irq_handler)[PIN_OBJ_INDEX(self)] = handler;
+ gpio_set_intr_type(PIN_OBJ_INDEX(self), trigger);
+ gpio_isr_handler_add(PIN_OBJ_INDEX(self), machine_pin_isr_handler, (void *)self);
}
}
// return the irq object
- return MP_OBJ_FROM_PTR(&machine_pin_irq_object[self->id]);
+ return MP_OBJ_FROM_PTR(&machine_pin_irq_obj_table[PIN_OBJ_INDEX(self)]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq);
+MP_DEFINE_CONST_OBJ_TYPE(
+ machine_pin_board_pins_obj_type,
+ MP_QSTR_board,
+ MP_TYPE_FLAG_NONE,
+ locals_dict, &machine_pin_board_pins_locals_dict
+ );
+
STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
// instance methods
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
@@ -491,16 +358,19 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
+ // class attributes
+ { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&machine_pin_board_pins_obj_type) },
+
// class constants
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(GPIO_MODE_INPUT) },
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT) },
{ MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(GPIO_MODE_INPUT_OUTPUT_OD) },
{ MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(GPIO_PULL_UP) },
{ MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(GPIO_PULL_DOWN) },
- { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_PIN_INTR_POSEDGE) },
- { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_PIN_INTR_NEGEDGE) },
- { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_PIN_INTR_LOLEVEL) },
- { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_PIN_INTR_HILEVEL) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(GPIO_INTR_POSEDGE) },
+ { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(GPIO_INTR_NEGEDGE) },
+ { MP_ROM_QSTR(MP_QSTR_WAKE_LOW), MP_ROM_INT(GPIO_INTR_LOW_LEVEL) },
+ { MP_ROM_QSTR(MP_QSTR_WAKE_HIGH), MP_ROM_INT(GPIO_INTR_HIGH_LEVEL) },
{ MP_ROM_QSTR(MP_QSTR_DRIVE_0), MP_ROM_INT(GPIO_DRIVE_CAP_0) },
{ MP_ROM_QSTR(MP_QSTR_DRIVE_1), MP_ROM_INT(GPIO_DRIVE_CAP_1) },
{ MP_ROM_QSTR(MP_QSTR_DRIVE_2), MP_ROM_INT(GPIO_DRIVE_CAP_2) },
@@ -513,10 +383,10 @@ STATIC mp_uint_t pin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, i
switch (request) {
case MP_PIN_READ: {
- return gpio_get_level(self->id);
+ return gpio_get_level(PIN_OBJ_INDEX(self));
}
case MP_PIN_WRITE: {
- gpio_set_level(self->id, arg);
+ gpio_set_level(PIN_OBJ_INDEX(self), arg);
return 0;
}
}
@@ -543,176 +413,19 @@ MP_DEFINE_CONST_OBJ_TYPE(
/******************************************************************************/
// Pin IRQ object
-STATIC const mp_obj_type_t machine_pin_irq_type;
-
-STATIC const machine_pin_irq_obj_t machine_pin_irq_object[] = {
- #if CONFIG_IDF_TARGET_ESP32
-
- {{&machine_pin_irq_type}, GPIO_NUM_0},
- {{&machine_pin_irq_type}, GPIO_NUM_1},
- {{&machine_pin_irq_type}, GPIO_NUM_2},
- {{&machine_pin_irq_type}, GPIO_NUM_3},
- {{&machine_pin_irq_type}, GPIO_NUM_4},
- {{&machine_pin_irq_type}, GPIO_NUM_5},
- {{&machine_pin_irq_type}, GPIO_NUM_6},
- {{&machine_pin_irq_type}, GPIO_NUM_7},
- {{&machine_pin_irq_type}, GPIO_NUM_8},
- {{&machine_pin_irq_type}, GPIO_NUM_9},
- {{&machine_pin_irq_type}, GPIO_NUM_10},
- {{&machine_pin_irq_type}, GPIO_NUM_11},
- {{&machine_pin_irq_type}, GPIO_NUM_12},
- {{&machine_pin_irq_type}, GPIO_NUM_13},
- {{&machine_pin_irq_type}, GPIO_NUM_14},
- {{&machine_pin_irq_type}, GPIO_NUM_15},
- #if CONFIG_ESP32_SPIRAM_SUPPORT
- {{NULL}, -1},
- {{NULL}, -1},
- #else
- {{&machine_pin_irq_type}, GPIO_NUM_16},
- {{&machine_pin_irq_type}, GPIO_NUM_17},
- #endif
- {{&machine_pin_irq_type}, GPIO_NUM_18},
- {{&machine_pin_irq_type}, GPIO_NUM_19},
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 2)
- {{&machine_pin_irq_type}, GPIO_NUM_20},
- #else
- {{NULL}, -1},
- #endif
- {{&machine_pin_irq_type}, GPIO_NUM_21},
- {{&machine_pin_irq_type}, GPIO_NUM_22},
- {{&machine_pin_irq_type}, GPIO_NUM_23},
- {{NULL}, -1},
- {{&machine_pin_irq_type}, GPIO_NUM_25},
- {{&machine_pin_irq_type}, GPIO_NUM_26},
- {{&machine_pin_irq_type}, GPIO_NUM_27},
- {{NULL}, -1},
- {{NULL}, -1},
- {{NULL}, -1},
- {{NULL}, -1},
- {{&machine_pin_irq_type}, GPIO_NUM_32},
- {{&machine_pin_irq_type}, GPIO_NUM_33},
- {{&machine_pin_irq_type}, GPIO_NUM_34},
- {{&machine_pin_irq_type}, GPIO_NUM_35},
- {{&machine_pin_irq_type}, GPIO_NUM_36},
- {{&machine_pin_irq_type}, GPIO_NUM_37},
- {{&machine_pin_irq_type}, GPIO_NUM_38},
- {{&machine_pin_irq_type}, GPIO_NUM_39},
-
- #elif CONFIG_IDF_TARGET_ESP32C3
-
- {{&machine_pin_irq_type}, GPIO_NUM_0},
- {{&machine_pin_irq_type}, GPIO_NUM_1},
- {{&machine_pin_irq_type}, GPIO_NUM_2},
- {{&machine_pin_irq_type}, GPIO_NUM_3},
- {{&machine_pin_irq_type}, GPIO_NUM_4},
- {{&machine_pin_irq_type}, GPIO_NUM_5},
- {{&machine_pin_irq_type}, GPIO_NUM_6},
- {{&machine_pin_irq_type}, GPIO_NUM_7},
- {{&machine_pin_irq_type}, GPIO_NUM_8},
- {{&machine_pin_irq_type}, GPIO_NUM_9},
- {{&machine_pin_irq_type}, GPIO_NUM_10},
- {{&machine_pin_irq_type}, GPIO_NUM_11},
- {{&machine_pin_irq_type}, GPIO_NUM_12},
- {{&machine_pin_irq_type}, GPIO_NUM_13},
- {{&machine_pin_irq_type}, GPIO_NUM_14},
- {{&machine_pin_irq_type}, GPIO_NUM_15},
- {{&machine_pin_irq_type}, GPIO_NUM_16},
- {{&machine_pin_irq_type}, GPIO_NUM_17},
- {{&machine_pin_irq_type}, GPIO_NUM_18},
- {{&machine_pin_irq_type}, GPIO_NUM_19},
- {{&machine_pin_irq_type}, GPIO_NUM_20},
- {{&machine_pin_irq_type}, GPIO_NUM_21},
-
- #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-
- {{&machine_pin_irq_type}, GPIO_NUM_0},
- {{&machine_pin_irq_type}, GPIO_NUM_1},
- {{&machine_pin_irq_type}, GPIO_NUM_2},
- {{&machine_pin_irq_type}, GPIO_NUM_3},
- {{&machine_pin_irq_type}, GPIO_NUM_4},
- {{&machine_pin_irq_type}, GPIO_NUM_5},
- {{&machine_pin_irq_type}, GPIO_NUM_6},
- {{&machine_pin_irq_type}, GPIO_NUM_7},
- {{&machine_pin_irq_type}, GPIO_NUM_8},
- {{&machine_pin_irq_type}, GPIO_NUM_9},
- {{&machine_pin_irq_type}, GPIO_NUM_10},
- {{&machine_pin_irq_type}, GPIO_NUM_11},
- {{&machine_pin_irq_type}, GPIO_NUM_12},
- {{&machine_pin_irq_type}, GPIO_NUM_13},
- {{&machine_pin_irq_type}, GPIO_NUM_14},
- {{&machine_pin_irq_type}, GPIO_NUM_15},
- {{&machine_pin_irq_type}, GPIO_NUM_16},
- {{&machine_pin_irq_type}, GPIO_NUM_17},
- {{&machine_pin_irq_type}, GPIO_NUM_18},
- #if CONFIG_USB_CDC_ENABLED
- {{NULL}, -1}, // 19 is for native USB D-
- {{NULL}, -1}, // 20 is for native USB D-
- #else
- {{&machine_pin_irq_type}, GPIO_NUM_19},
- {{&machine_pin_irq_type}, GPIO_NUM_20},
- #endif
- {{&machine_pin_irq_type}, GPIO_NUM_21},
- {{NULL}, -1}, // 22 not a pin
- {{NULL}, -1}, // 23 not a pin
- {{NULL}, -1}, // 24 not a pin
- {{NULL}, -1}, // 25 not a pin
- #if CONFIG_SPIRAM
- {{NULL}, -1}, // 26 PSRAM
- #else
- {{&machine_pin_irq_type}, GPIO_NUM_26},
- #endif
- {{NULL}, -1}, // 27 FLASH/PSRAM
- {{NULL}, -1}, // 28 FLASH/PSRAM
- {{NULL}, -1}, // 29 FLASH/PSRAM
- {{NULL}, -1}, // 30 FLASH/PSRAM
- {{NULL}, -1}, // 31 FLASH/PSRAM
- {{NULL}, -1}, // 32 FLASH/PSRAM
- #if CONFIG_SPIRAM_MODE_OCT
- {{NULL}, -1}, // 33 FLASH/PSRAM
- {{NULL}, -1}, // 34 FLASH/PSRAM
- {{NULL}, -1}, // 35 FLASH/PSRAM
- {{NULL}, -1}, // 36 FLASH/PSRAM
- {{NULL}, -1}, // 37 FLASH/PSRAM
- #else
- {{&machine_pin_irq_type}, GPIO_NUM_33},
- {{&machine_pin_irq_type}, GPIO_NUM_34},
- {{&machine_pin_irq_type}, GPIO_NUM_35},
- {{&machine_pin_irq_type}, GPIO_NUM_36},
- {{&machine_pin_irq_type}, GPIO_NUM_37},
- #endif
- {{&machine_pin_irq_type}, GPIO_NUM_38},
- {{&machine_pin_irq_type}, GPIO_NUM_39},
- {{&machine_pin_irq_type}, GPIO_NUM_40},
- {{&machine_pin_irq_type}, GPIO_NUM_41},
- {{&machine_pin_irq_type}, GPIO_NUM_42},
- {{&machine_pin_irq_type}, GPIO_NUM_43},
- {{&machine_pin_irq_type}, GPIO_NUM_44},
- {{&machine_pin_irq_type}, GPIO_NUM_45},
- {{&machine_pin_irq_type}, GPIO_NUM_46},
-
- #endif
-
- #if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO
-
- {{&machine_pin_irq_type}, GPIO_NUM_47},
- {{&machine_pin_irq_type}, GPIO_NUM_48},
-
- #endif
-};
-
STATIC mp_obj_t machine_pin_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
machine_pin_irq_obj_t *self = self_in;
mp_arg_check_num(n_args, n_kw, 0, 0, false);
- machine_pin_isr_handler((void *)&machine_pin_obj[self->id]);
+ machine_pin_isr_handler((void *)&machine_pin_obj_table[PIN_IRQ_OBJ_INDEX(self)]);
return mp_const_none;
}
STATIC mp_obj_t machine_pin_irq_trigger(size_t n_args, const mp_obj_t *args) {
machine_pin_irq_obj_t *self = args[0];
- uint32_t orig_trig = GPIO.pin[self->id].int_type;
+ uint32_t orig_trig = GPIO.pin[PIN_IRQ_OBJ_INDEX(self)].int_type;
if (n_args == 2) {
// set trigger
- gpio_set_intr_type(self->id, mp_obj_get_int(args[1]));
+ gpio_set_intr_type(PIN_IRQ_OBJ_INDEX(self), mp_obj_get_int(args[1]));
}
// return original trigger value
return MP_OBJ_NEW_SMALL_INT(orig_trig);
@@ -724,7 +437,7 @@ STATIC const mp_rom_map_elem_t machine_pin_irq_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(machine_pin_irq_locals_dict, machine_pin_irq_locals_dict_table);
-STATIC MP_DEFINE_CONST_OBJ_TYPE(
+MP_DEFINE_CONST_OBJ_TYPE(
machine_pin_irq_type,
MP_QSTR_IRQ,
MP_TYPE_FLAG_NONE,
@@ -732,4 +445,4 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &machine_pin_irq_locals_dict
);
-MP_REGISTER_ROOT_POINTER(mp_obj_t machine_pin_irq_handler[40]);
+MP_REGISTER_ROOT_POINTER(mp_obj_t machine_pin_irq_handler[GPIO_PIN_COUNT]);
diff --git a/ports/esp32/machine_pin.h b/ports/esp32/machine_pin.h
new file mode 100644
index 000000000000..dbbaac2219be
--- /dev/null
+++ b/ports/esp32/machine_pin.h
@@ -0,0 +1,164 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_ESP32_MACHINE_PIN_H
+#define MICROPY_INCLUDED_ESP32_MACHINE_PIN_H
+
+#include "py/obj.h"
+#include "hal/gpio_types.h"
+
+// Define which pins are enabled for a given SoC and configuration.
+
+#if CONFIG_IDF_TARGET_ESP32
+
+#define MICROPY_HW_ENABLE_GPIO0 (1)
+#define MICROPY_HW_ENABLE_GPIO1 (1)
+#define MICROPY_HW_ENABLE_GPIO2 (1)
+#define MICROPY_HW_ENABLE_GPIO3 (1)
+#define MICROPY_HW_ENABLE_GPIO4 (1)
+#define MICROPY_HW_ENABLE_GPIO5 (1)
+#define MICROPY_HW_ENABLE_GPIO6 (1)
+#define MICROPY_HW_ENABLE_GPIO7 (1)
+#define MICROPY_HW_ENABLE_GPIO8 (1)
+#define MICROPY_HW_ENABLE_GPIO9 (1)
+#define MICROPY_HW_ENABLE_GPIO10 (1)
+#define MICROPY_HW_ENABLE_GPIO11 (1)
+#define MICROPY_HW_ENABLE_GPIO12 (1)
+#define MICROPY_HW_ENABLE_GPIO13 (1)
+#define MICROPY_HW_ENABLE_GPIO14 (1)
+#define MICROPY_HW_ENABLE_GPIO15 (1)
+#if !CONFIG_ESP32_SPIRAM_SUPPORT
+#define MICROPY_HW_ENABLE_GPIO16 (1)
+#define MICROPY_HW_ENABLE_GPIO17 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO18 (1)
+#define MICROPY_HW_ENABLE_GPIO19 (1)
+#define MICROPY_HW_ENABLE_GPIO20 (1)
+#define MICROPY_HW_ENABLE_GPIO21 (1)
+#define MICROPY_HW_ENABLE_GPIO22 (1)
+#define MICROPY_HW_ENABLE_GPIO23 (1)
+#define MICROPY_HW_ENABLE_GPIO25 (1)
+#define MICROPY_HW_ENABLE_GPIO26 (1)
+#define MICROPY_HW_ENABLE_GPIO27 (1)
+#define MICROPY_HW_ENABLE_GPIO32 (1)
+#define MICROPY_HW_ENABLE_GPIO33 (1)
+#define MICROPY_HW_ENABLE_GPIO34 (1)
+#define MICROPY_HW_ENABLE_GPIO35 (1)
+#define MICROPY_HW_ENABLE_GPIO36 (1)
+#define MICROPY_HW_ENABLE_GPIO37 (1)
+#define MICROPY_HW_ENABLE_GPIO38 (1)
+#define MICROPY_HW_ENABLE_GPIO39 (1)
+
+#elif CONFIG_IDF_TARGET_ESP32C3
+
+#define MICROPY_HW_ENABLE_GPIO0 (1)
+#define MICROPY_HW_ENABLE_GPIO1 (1)
+#define MICROPY_HW_ENABLE_GPIO2 (1)
+#define MICROPY_HW_ENABLE_GPIO3 (1)
+#define MICROPY_HW_ENABLE_GPIO4 (1)
+#define MICROPY_HW_ENABLE_GPIO5 (1)
+#define MICROPY_HW_ENABLE_GPIO6 (1)
+#define MICROPY_HW_ENABLE_GPIO7 (1)
+#define MICROPY_HW_ENABLE_GPIO8 (1)
+#define MICROPY_HW_ENABLE_GPIO9 (1)
+#define MICROPY_HW_ENABLE_GPIO10 (1)
+#define MICROPY_HW_ENABLE_GPIO11 (1)
+#define MICROPY_HW_ENABLE_GPIO12 (1)
+#define MICROPY_HW_ENABLE_GPIO13 (1)
+#if !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
+#define MICROPY_HW_ENABLE_GPIO18 (1)
+#define MICROPY_HW_ENABLE_GPIO19 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO20 (1)
+#define MICROPY_HW_ENABLE_GPIO21 (1)
+
+#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+
+#define MICROPY_HW_ENABLE_GPIO0 (1)
+#define MICROPY_HW_ENABLE_GPIO1 (1)
+#define MICROPY_HW_ENABLE_GPIO2 (1)
+#define MICROPY_HW_ENABLE_GPIO3 (1)
+#define MICROPY_HW_ENABLE_GPIO4 (1)
+#define MICROPY_HW_ENABLE_GPIO5 (1)
+#define MICROPY_HW_ENABLE_GPIO6 (1)
+#define MICROPY_HW_ENABLE_GPIO7 (1)
+#define MICROPY_HW_ENABLE_GPIO8 (1)
+#define MICROPY_HW_ENABLE_GPIO9 (1)
+#define MICROPY_HW_ENABLE_GPIO10 (1)
+#define MICROPY_HW_ENABLE_GPIO11 (1)
+#define MICROPY_HW_ENABLE_GPIO12 (1)
+#define MICROPY_HW_ENABLE_GPIO13 (1)
+#define MICROPY_HW_ENABLE_GPIO14 (1)
+#define MICROPY_HW_ENABLE_GPIO15 (1)
+#define MICROPY_HW_ENABLE_GPIO16 (1)
+#define MICROPY_HW_ENABLE_GPIO17 (1)
+#define MICROPY_HW_ENABLE_GPIO18 (1)
+#if !CONFIG_USB_CDC_ENABLED
+#define MICROPY_HW_ENABLE_GPIO19 (1)
+#define MICROPY_HW_ENABLE_GPIO20 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO21 (1)
+#if !CONFIG_SPIRAM
+#define MICROPY_HW_ENABLE_GPIO26 (1)
+#endif
+#if !CONFIG_SPIRAM_MODE_OCT
+#define MICROPY_HW_ENABLE_GPIO33 (1)
+#define MICROPY_HW_ENABLE_GPIO34 (1)
+#define MICROPY_HW_ENABLE_GPIO35 (1)
+#define MICROPY_HW_ENABLE_GPIO36 (1)
+#define MICROPY_HW_ENABLE_GPIO37 (1)
+#endif
+#define MICROPY_HW_ENABLE_GPIO38 (1)
+#define MICROPY_HW_ENABLE_GPIO39 (1)
+#define MICROPY_HW_ENABLE_GPIO40 (1)
+#define MICROPY_HW_ENABLE_GPIO41 (1)
+#define MICROPY_HW_ENABLE_GPIO42 (1)
+#define MICROPY_HW_ENABLE_GPIO43 (1)
+#define MICROPY_HW_ENABLE_GPIO44 (1)
+#define MICROPY_HW_ENABLE_GPIO45 (1)
+#define MICROPY_HW_ENABLE_GPIO46 (1)
+#if CONFIG_IDF_TARGET_ESP32S3 && MICROPY_HW_ESP32S3_EXTENDED_IO
+#define MICROPY_HW_ENABLE_GPIO47 (1)
+#define MICROPY_HW_ENABLE_GPIO48 (1)
+#endif
+
+#endif
+
+typedef struct _machine_pin_obj_t {
+ mp_obj_base_t base;
+} machine_pin_obj_t;
+
+typedef struct _machine_pin_irq_obj_t {
+ mp_obj_base_t base;
+} machine_pin_irq_obj_t;
+
+extern const mp_obj_type_t machine_pin_irq_type;
+
+extern const machine_pin_obj_t machine_pin_obj_table[GPIO_NUM_MAX];
+extern const machine_pin_irq_obj_t machine_pin_irq_obj_table[GPIO_NUM_MAX];
+
+extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;
+
+#endif // MICROPY_INCLUDED_ESP32_MACHINE_PIN_H
diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c
index 2a456c71c783..462d0fa79c74 100644
--- a/ports/esp32/machine_pwm.c
+++ b/ports/esp32/machine_pwm.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -34,6 +34,7 @@
#include "driver/ledc.h"
#include "esp_err.h"
+#include "soc/gpio_sig_map.h"
#define PWM_DBG(...)
// #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n");
@@ -164,13 +165,13 @@ STATIC void pwm_deinit(int channel_idx) {
// Mark it unused, and tell the hardware to stop routing
check_esp_err(ledc_stop(mode, channel, 0));
// Disable ledc signal for the pin
- // gpio_matrix_out(pin, SIG_GPIO_OUT_IDX, false, false);
+ // esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
if (mode == LEDC_LOW_SPEED_MODE) {
- gpio_matrix_out(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, true);
+ esp_rom_gpio_connect_out_signal(pin, LEDC_LS_SIG_OUT0_IDX + channel, false, true);
} else {
#if LEDC_SPEED_MODE_MAX > 1
#if CONFIG_IDF_TARGET_ESP32
- gpio_matrix_out(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, true);
+ esp_rom_gpio_connect_out_signal(pin, LEDC_HS_SIG_OUT0_IDX + channel, false, true);
#else
#error Add supported CONFIG_IDF_TARGET_ESP32_xxx
#endif
@@ -209,18 +210,13 @@ STATIC void configure_channel(machine_pwm_obj_t *self) {
STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) {
if (freq != timer->freq_hz) {
// Find the highest bit resolution for the requested frequency
- unsigned int i = LEDC_APB_CLK_HZ; // 80 MHz
+ unsigned int i = APB_CLK_FREQ; // 80 MHz
#if SOC_LEDC_SUPPORT_REF_TICK
if (freq < EMPIRIC_FREQ) {
- i = LEDC_REF_CLK_HZ; // 1 MHz
+ i = REF_CLK_FREQ; // 1 MHz
}
#endif
- #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
- // original code
- i /= freq;
- #else
- // See https://github.com/espressif/esp-idf/issues/7722
int divider = (i + freq / 2) / freq; // rounded
if (divider == 0) {
divider = 1;
@@ -230,7 +226,6 @@ STATIC void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf
f = 1.0;
}
i = (unsigned int)roundf((float)i / f);
- #endif
unsigned int res = 0;
for (; i > 1; i >>= 1) {
@@ -298,7 +293,14 @@ STATIC int duty_to_ns(machine_pwm_obj_t *self, int duty) {
#define get_duty_raw(self) ledc_get_duty(self->mode, self->channel)
+STATIC void pwm_is_active(machine_pwm_obj_t *self) {
+ if (self->active == false) {
+ mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("PWM inactive"));
+ }
+}
+
STATIC uint32_t get_duty_u16(machine_pwm_obj_t *self) {
+ pwm_is_active(self);
int resolution = timers[TIMER_IDX(self->mode, self->timer)].duty_resolution;
int duty = ledc_get_duty(self->mode, self->channel);
if (resolution <= UI_RES_16_BIT) {
@@ -310,14 +312,17 @@ STATIC uint32_t get_duty_u16(machine_pwm_obj_t *self) {
}
STATIC uint32_t get_duty_u10(machine_pwm_obj_t *self) {
+ pwm_is_active(self);
return get_duty_u16(self) >> 6; // Scale down from 16 bit to 10 bit resolution
}
STATIC uint32_t get_duty_ns(machine_pwm_obj_t *self) {
+ pwm_is_active(self);
return duty_to_ns(self, get_duty_u16(self));
}
STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
+ pwm_is_active(self);
if ((duty < 0) || (duty > UI_MAX_DUTY)) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_u16 must be from 0 to %d"), UI_MAX_DUTY);
}
@@ -340,11 +345,11 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
/*
// Bug: Sometimes duty is not set right now.
// Not a bug. It's a feature. The duty is applied at the beginning of the next signal period.
- // Bug: It has been experimentally established that the duty is setted during 2 signal periods, but 1 period is expected.
+ // Bug: It has been experimentally established that the duty is set during 2 signal periods, but 1 period is expected.
// See https://github.com/espressif/esp-idf/issues/7288
if (duty != get_duty_u16(self)) {
PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz);
- ets_delay_us(2 * 1000000 / timer.freq_hz);
+ esp_rom_delay_us(2 * 1000000 / timer.freq_hz);
if (duty != get_duty_u16(self)) {
PWM_DBG("set_duty_u16(%u), get_duty_u16():%u, channel_duty:%d, duty_resolution:%d, freq_hz:%d", duty, get_duty_u16(self), channel_duty, timer.duty_resolution, timer.freq_hz);
}
@@ -356,6 +361,7 @@ STATIC void set_duty_u16(machine_pwm_obj_t *self, int duty) {
}
STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
+ pwm_is_active(self);
if ((duty < 0) || (duty > MAX_DUTY_U10)) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty must be from 0 to %u"), MAX_DUTY_U10);
}
@@ -365,6 +371,7 @@ STATIC void set_duty_u10(machine_pwm_obj_t *self, int duty) {
}
STATIC void set_duty_ns(machine_pwm_obj_t *self, int ns) {
+ pwm_is_active(self);
if ((ns < 0) || (ns > duty_to_ns(self, UI_MAX_DUTY))) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("duty_ns must be from 0 to %d ns"), duty_to_ns(self, UI_MAX_DUTY));
}
@@ -498,7 +505,7 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
}
}
if ((freq <= 0) || (freq > 40000000)) {
- mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz"));
+ mp_raise_ValueError(MP_ERROR_TEXT("frequency must be from 1Hz to 40MHz"));
}
int timer_idx;
@@ -595,15 +602,17 @@ STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
self->duty_x = 0;
}
-// Set's and get's methods of PWM class
+// Set and get methods of PWM class
STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
+ pwm_is_active(self);
return MP_OBJ_NEW_SMALL_INT(ledc_get_freq(self->mode, self->timer));
}
STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+ pwm_is_active(self);
if ((freq <= 0) || (freq > 40000000)) {
- mp_raise_ValueError(MP_ERROR_TEXT("freqency must be from 1Hz to 40MHz"));
+ mp_raise_ValueError(MP_ERROR_TEXT("frequency must be from 1Hz to 40MHz"));
}
if (freq == timers[TIMER_IDX(self->mode, self->timer)].freq_hz) {
return;
diff --git a/ports/esp32/machine_sdcard.c b/ports/esp32/machine_sdcard.c
index 801a26f378db..bc4aaf30c6f2 100644
--- a/ports/esp32/machine_sdcard.c
+++ b/ports/esp32/machine_sdcard.c
@@ -69,18 +69,71 @@ typedef struct _sdcard_obj_t {
#define _SECTOR_SIZE(self) (self->card.csd.sector_size)
-STATIC gpio_num_t pin_or_int(const mp_obj_t arg) {
- if (mp_obj_is_small_int(arg)) {
- return MP_OBJ_SMALL_INT_VALUE(arg);
- } else {
- // This raises a value error if the argument is not a Pin.
- return machine_pin_get_id(arg);
- }
-}
+// SPI bus default bus and device configuration.
+
+static const spi_bus_config_t spi_bus_defaults[2] = {
+ {
+ #if CONFIG_IDF_TARGET_ESP32
+ .miso_io_num = GPIO_NUM_19,
+ .mosi_io_num = GPIO_NUM_23,
+ .sclk_io_num = GPIO_NUM_18,
+ #else
+ .miso_io_num = GPIO_NUM_36,
+ .mosi_io_num = GPIO_NUM_35,
+ .sclk_io_num = GPIO_NUM_37,
+ #endif
+ .data2_io_num = GPIO_NUM_NC,
+ .data3_io_num = GPIO_NUM_NC,
+ .data4_io_num = GPIO_NUM_NC,
+ .data5_io_num = GPIO_NUM_NC,
+ .data6_io_num = GPIO_NUM_NC,
+ .data7_io_num = GPIO_NUM_NC,
+ .max_transfer_sz = 4000,
+ .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_MOSI,
+ .intr_flags = 0,
+ },
+ {
+ .miso_io_num = GPIO_NUM_2,
+ .mosi_io_num = GPIO_NUM_15,
+ .sclk_io_num = GPIO_NUM_14,
+ .data2_io_num = GPIO_NUM_NC,
+ .data3_io_num = GPIO_NUM_NC,
+ .data4_io_num = GPIO_NUM_NC,
+ .data5_io_num = GPIO_NUM_NC,
+ .data6_io_num = GPIO_NUM_NC,
+ .data7_io_num = GPIO_NUM_NC,
+ .max_transfer_sz = 4000,
+ .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MISO | SPICOMMON_BUSFLAG_MOSI,
+ .intr_flags = 0,
+ },
+};
+
+#if CONFIG_IDF_TARGET_ESP32
+static const uint8_t spi_dma_channel_defaults[2] = {
+ 2,
+ 1,
+};
+#endif
+
+static const sdspi_device_config_t spi_dev_defaults[2] = {
+ {
+ #if CONFIG_IDF_TARGET_ESP32
+ .host_id = VSPI_HOST,
+ .gpio_cs = GPIO_NUM_5,
+ #else
+ .host_id = SPI3_HOST,
+ .gpio_cs = GPIO_NUM_34,
+ #endif
+ .gpio_cd = SDSPI_SLOT_NO_CD,
+ .gpio_wp = SDSPI_SLOT_NO_WP,
+ .gpio_int = SDSPI_SLOT_NO_INT,
+ },
+ SDSPI_DEVICE_CONFIG_DEFAULT(), // HSPI (ESP32) / SPI2 (ESP32S3)
+};
#define SET_CONFIG_PIN(config, pin_var, arg_id) \
if (arg_vals[arg_id].u_obj != mp_const_none) \
- config.pin_var = pin_or_int(arg_vals[arg_id].u_obj)
+ config.pin_var = machine_pin_get_id(arg_vals[arg_id].u_obj)
STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) {
if (force || !(self->flags & SDCARD_CARD_FLAGS_CARD_INIT_DONE)) {
@@ -188,10 +241,11 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
}
if (is_spi) {
- #if CONFIG_IDF_TARGET_ESP32S3
- self->host.slot = slot_num ? SPI3_HOST : SPI2_HOST;
- #else
+ // Needs to match spi_dev_defaults above.
+ #if CONFIG_IDF_TARGET_ESP32
self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST;
+ #else
+ self->host.slot = slot_num ? SPI2_HOST : SPI3_HOST;
#endif
}
@@ -202,46 +256,39 @@ STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args
if (is_spi) {
// SPI interface
- #if CONFIG_IDF_TARGET_ESP32S3
- STATIC const sdspi_slot_config_t slot_defaults[2] = {
- {
- .gpio_miso = GPIO_NUM_36,
- .gpio_mosi = GPIO_NUM_35,
- .gpio_sck = GPIO_NUM_37,
- .gpio_cs = GPIO_NUM_34,
- .gpio_cd = SDSPI_SLOT_NO_CD,
- .gpio_wp = SDSPI_SLOT_NO_WP,
- .dma_channel = 2
- },
- SDSPI_SLOT_CONFIG_DEFAULT()
- };
+ DEBUG_printf(" Setting up SPI slot configuration");
+ spi_host_device_t spi_host_id = self->host.slot;
+ spi_bus_config_t bus_config = spi_bus_defaults[slot_num];
+ #if CONFIG_IDF_TARGET_ESP32
+ spi_dma_chan_t dma_channel = spi_dma_channel_defaults[slot_num];
#else
- STATIC const sdspi_slot_config_t slot_defaults[2] = {
- {
- .gpio_miso = GPIO_NUM_19,
- .gpio_mosi = GPIO_NUM_23,
- .gpio_sck = GPIO_NUM_18,
- .gpio_cs = GPIO_NUM_5,
- .gpio_cd = SDSPI_SLOT_NO_CD,
- .gpio_wp = SDSPI_SLOT_NO_WP,
- .dma_channel = 2
- },
- SDSPI_SLOT_CONFIG_DEFAULT()
- };
+ spi_dma_chan_t dma_channel = SPI_DMA_CH_AUTO;
#endif
+ sdspi_device_config_t dev_config = spi_dev_defaults[slot_num];
- DEBUG_printf(" Setting up SPI slot configuration");
- sdspi_slot_config_t slot_config = slot_defaults[slot_num];
+ SET_CONFIG_PIN(bus_config, miso_io_num, ARG_miso);
+ SET_CONFIG_PIN(bus_config, mosi_io_num, ARG_mosi);
+ SET_CONFIG_PIN(bus_config, sclk_io_num, ARG_sck);
- SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd);
- SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp);
- SET_CONFIG_PIN(slot_config, gpio_miso, ARG_miso);
- SET_CONFIG_PIN(slot_config, gpio_mosi, ARG_mosi);
- SET_CONFIG_PIN(slot_config, gpio_sck, ARG_sck);
- SET_CONFIG_PIN(slot_config, gpio_cs, ARG_cs);
+ SET_CONFIG_PIN(dev_config, gpio_cs, ARG_cs);
+ SET_CONFIG_PIN(dev_config, gpio_cd, ARG_cd);
+ SET_CONFIG_PIN(dev_config, gpio_wp, ARG_wp);
- DEBUG_printf(" Calling init_slot()");
- check_esp_err(sdspi_host_init_slot(self->host.slot, &slot_config));
+ DEBUG_printf(" Calling spi_bus_initialize()");
+ check_esp_err(spi_bus_initialize(spi_host_id, &bus_config, dma_channel));
+
+ DEBUG_printf(" Calling sdspi_host_init_device()");
+ sdspi_dev_handle_t sdspi_handle;
+ esp_err_t ret = sdspi_host_init_device(&dev_config, &sdspi_handle);
+ if (ret != ESP_OK) {
+ spi_bus_free(spi_host_id);
+ check_esp_err(ret);
+ }
+ if (self->host.slot != sdspi_handle) {
+ // MicroPython restriction: the SPI bus must be exclusively for the SD card.
+ spi_bus_free(spi_host_id);
+ mp_raise_ValueError(MP_ERROR_TEXT("SPI bus already in use"));
+ }
} else {
// SD/MMC interface
DEBUG_printf(" Setting up SDMMC slot configuration");
@@ -275,12 +322,9 @@ STATIC mp_obj_t sd_deinit(mp_obj_t self_in) {
DEBUG_printf("De-init host\n");
if (self->flags & SDCARD_CARD_FLAGS_HOST_INIT_DONE) {
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
if (self->host.flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
self->host.deinit_p(self->host.slot);
- } else
- #endif
- {
+ } else {
self->host.deinit();
}
if (self->host.flags & SDMMC_HOST_FLAG_SPI) {
diff --git a/ports/esp32/machine_timer.c b/ports/esp32/machine_timer.c
index 83fe81f6eee3..aba3db1983fc 100644
--- a/ports/esp32/machine_timer.c
+++ b/ports/esp32/machine_timer.c
@@ -35,22 +35,21 @@
#include "modmachine.h"
#include "mphalport.h"
-#include "driver/timer.h"
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 1)
+#include "hal/timer_hal.h"
#include "hal/timer_ll.h"
-#define HAVE_TIMER_LL (1)
-#endif
+#include "soc/timer_periph.h"
-#define TIMER_INTR_SEL TIMER_INTR_LEVEL
#define TIMER_DIVIDER 8
// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly
-#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER)
+#define TIMER_SCALE (APB_CLK_FREQ / TIMER_DIVIDER)
#define TIMER_FLAGS 0
typedef struct _machine_timer_obj_t {
mp_obj_base_t base;
+
+ timer_hal_context_t hal_context;
mp_uint_t group;
mp_uint_t index;
@@ -83,15 +82,9 @@ void machine_timer_deinit_all(void) {
STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_timer_obj_t *self = self_in;
-
- timer_config_t config;
- mp_printf(print, "Timer(%p; ", self);
-
- timer_get_config(self->group, self->index, &config);
-
- mp_printf(print, "alarm_en=%d, ", config.alarm_en);
- mp_printf(print, "auto_reload=%d, ", config.auto_reload);
- mp_printf(print, "counter_en=%d)", config.counter_en);
+ qstr mode = self->repeat ? MP_QSTR_PERIODIC : MP_QSTR_ONE_SHOT;
+ uint64_t period = self->period / (TIMER_SCALE / 1000); // convert to ms
+ mp_printf(print, "Timer(%u, mode=%q, period=%lu)", (self->group << 1) | self->index, mode, period);
}
STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
@@ -129,8 +122,14 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
}
STATIC void machine_timer_disable(machine_timer_obj_t *self) {
+ if (self->hal_context.dev != NULL) {
+ // Disable the counter and alarm.
+ timer_ll_enable_counter(self->hal_context.dev, self->index, false);
+ timer_ll_enable_alarm(self->hal_context.dev, self->index, false);
+ }
+
if (self->handle) {
- timer_pause(self->group, self->index);
+ // Free the interrupt handler.
esp_intr_free(self->handle);
self->handle = NULL;
}
@@ -141,61 +140,47 @@ STATIC void machine_timer_disable(machine_timer_obj_t *self) {
STATIC void machine_timer_isr(void *self_in) {
machine_timer_obj_t *self = self_in;
- timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0);
- #if HAVE_TIMER_LL
+ uint32_t intr_status = timer_ll_get_intr_status(self->hal_context.dev);
- #if CONFIG_IDF_TARGET_ESP32 && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
- device->hw_timer[self->index].update = 1;
- #else
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
- #if CONFIG_IDF_TARGET_ESP32S3
- device->hw_timer[self->index].update.tn_update = 1;
- #else
- device->hw_timer[self->index].update.tx_update = 1;
- #endif
- #else
- device->hw_timer[self->index].update.update = 1;
- #endif
- #endif
- timer_ll_clear_intr_status(device, self->index);
- #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
- timer_ll_set_alarm_enable(device, self->index, self->repeat);
- #else
- timer_ll_set_alarm_value(device, self->index, self->repeat);
- #endif
-
- #else
-
- device->hw_timer[self->index].update = 1;
- if (self->index) {
- device->int_clr_timers.t1 = 1;
- } else {
- device->int_clr_timers.t0 = 1;
+ if (intr_status & TIMER_LL_EVENT_ALARM(self->index)) {
+ timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
+ if (self->repeat) {
+ timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
+ }
+ mp_sched_schedule(self->callback, self);
+ mp_hal_wake_main_task_from_isr();
}
- device->hw_timer[self->index].config.alarm_en = self->repeat;
-
- #endif
-
- mp_sched_schedule(self->callback, self);
- mp_hal_wake_main_task_from_isr();
}
STATIC void machine_timer_enable(machine_timer_obj_t *self) {
- timer_config_t config;
- config.alarm_en = TIMER_ALARM_EN;
- config.auto_reload = self->repeat;
- config.counter_dir = TIMER_COUNT_UP;
- config.divider = TIMER_DIVIDER;
- config.intr_type = TIMER_INTR_LEVEL;
- config.counter_en = TIMER_PAUSE;
-
- check_esp_err(timer_init(self->group, self->index, &config));
- check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000));
- check_esp_err(timer_set_alarm_value(self->group, self->index, self->period));
- check_esp_err(timer_enable_intr(self->group, self->index));
- check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void *)self, TIMER_FLAGS, &self->handle));
- check_esp_err(timer_start(self->group, self->index));
+ // Initialise the timer.
+ timer_hal_init(&self->hal_context, self->group, self->index);
+ timer_ll_enable_counter(self->hal_context.dev, self->index, false);
+ timer_ll_set_clock_source(self->hal_context.dev, self->index, GPTIMER_CLK_SRC_APB);
+ timer_ll_set_clock_prescale(self->hal_context.dev, self->index, TIMER_DIVIDER);
+ timer_hal_set_counter_value(&self->hal_context, 0);
+ timer_ll_set_count_direction(self->hal_context.dev, self->index, GPTIMER_COUNT_UP);
+
+ // Allocate and enable the alarm interrupt.
+ timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), false);
+ timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
+ ESP_ERROR_CHECK(
+ esp_intr_alloc(timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
+ TIMER_FLAGS, machine_timer_isr, self, &self->handle)
+ );
+ timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), true);
+
+ // Enable the alarm to trigger at the given period.
+ timer_ll_set_alarm_value(self->hal_context.dev, self->index, self->period);
+ timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
+
+ // Set the counter to reload at 0 if it's in repeat mode.
+ timer_ll_set_reload_value(self->hal_context.dev, self->index, 0);
+ timer_ll_enable_auto_reload(self->hal_context.dev, self->index, self->repeat);
+
+ // Enable the counter.
+ timer_ll_enable_counter(self->hal_context.dev, self->index, true);
}
STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@@ -259,11 +244,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init)
STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
machine_timer_obj_t *self = self_in;
- double result;
-
- timer_get_counter_time_sec(self->group, self->index, &result);
-
- return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms
+ uint64_t result = timer_ll_get_counter_value(self->hal_context.dev, self->index);
+ return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result / (TIMER_SCALE / 1000))); // value in ms
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c
index ad1f6c9474cd..d9f4ef3ebc7f 100644
--- a/ports/esp32/machine_touchpad.c
+++ b/ports/esp32/machine_touchpad.c
@@ -27,10 +27,10 @@
#include "py/runtime.h"
#include "py/mphal.h"
#include "modmachine.h"
+#include "driver/gpio.h"
-#if CONFIG_IDF_TARGET_ESP32
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-#include "driver/gpio.h"
#if CONFIG_IDF_TARGET_ESP32
#include "driver/touch_pad.h"
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
@@ -43,8 +43,8 @@ typedef struct _mtp_obj_t {
touch_pad_t touchpad_id;
} mtp_obj_t;
-#if CONFIG_IDF_TARGET_ESP32
STATIC const mtp_obj_t touchpad_obj[] = {
+ #if CONFIG_IDF_TARGET_ESP32
{{&machine_touchpad_type}, GPIO_NUM_4, TOUCH_PAD_NUM0},
{{&machine_touchpad_type}, GPIO_NUM_0, TOUCH_PAD_NUM1},
{{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2},
@@ -55,9 +55,7 @@ STATIC const mtp_obj_t touchpad_obj[] = {
{{&machine_touchpad_type}, GPIO_NUM_27, TOUCH_PAD_NUM7},
{{&machine_touchpad_type}, GPIO_NUM_33, TOUCH_PAD_NUM8},
{{&machine_touchpad_type}, GPIO_NUM_32, TOUCH_PAD_NUM9},
-};
-#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
-STATIC const mtp_obj_t touchpad_obj[] = {
+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{{&machine_touchpad_type}, GPIO_NUM_1, TOUCH_PAD_NUM1},
{{&machine_touchpad_type}, GPIO_NUM_2, TOUCH_PAD_NUM2},
{{&machine_touchpad_type}, GPIO_NUM_3, TOUCH_PAD_NUM3},
@@ -72,12 +70,11 @@ STATIC const mtp_obj_t touchpad_obj[] = {
{{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM12},
{{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM13},
{{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM14},
+ #endif
};
-#endif
STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
const mp_obj_t *args) {
-
mp_arg_check_num(n_args, n_kw, 1, 1, true);
gpio_num_t pin_id = machine_pin_get_id(args[0]);
const mtp_obj_t *self = NULL;
@@ -95,9 +92,16 @@ STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
if (!initialized) {
touch_pad_init();
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
+ #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+ touch_pad_fsm_start();
+ #endif
initialized = 1;
}
+ #if CONFIG_IDF_TARGET_ESP32
esp_err_t err = touch_pad_config(self->touchpad_id, 0);
+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+ esp_err_t err = touch_pad_config(self->touchpad_id);
+ #endif
if (err == ESP_OK) {
return MP_OBJ_FROM_PTR(self);
}
@@ -106,8 +110,12 @@ STATIC mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_
STATIC mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) {
mtp_obj_t *self = self_in;
+ #if CONFIG_IDF_TARGET_ESP32
uint16_t value = mp_obj_get_int(value_in);
esp_err_t err = touch_pad_config(self->touchpad_id, value);
+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+ esp_err_t err = touch_pad_config(self->touchpad_id);
+ #endif
if (err == ESP_OK) {
return mp_const_none;
}
@@ -117,8 +125,13 @@ MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config);
STATIC mp_obj_t mtp_read(mp_obj_t self_in) {
mtp_obj_t *self = self_in;
+ #if CONFIG_IDF_TARGET_ESP32
uint16_t value;
esp_err_t err = touch_pad_read(self->touchpad_id, &value);
+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
+ uint32_t value;
+ esp_err_t err = touch_pad_read_raw_data(self->touchpad_id, &value);
+ #endif
if (err == ESP_OK) {
return MP_OBJ_NEW_SMALL_INT(value);
}
@@ -142,4 +155,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &mtp_locals_dict
);
-#endif // CONFIG_IDF_TARGET_ESP32
+#endif
diff --git a/ports/esp32/machine_uart.c b/ports/esp32/machine_uart.c
index 4cfa31b71de3..e7b2b8376b7a 100644
--- a/ports/esp32/machine_uart.c
+++ b/ports/esp32/machine_uart.c
@@ -34,20 +34,21 @@
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
+#include "py/mphal.h"
#include "modmachine.h"
#include "uart.h"
-#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
-#define UART_INV_TX UART_INVERSE_TXD
-#define UART_INV_RX UART_INVERSE_RXD
-#define UART_INV_RTS UART_INVERSE_RTS
-#define UART_INV_CTS UART_INVERSE_CTS
+#if SOC_UART_SUPPORT_XTAL_CLK
+// Works independently of APB frequency, on ESP32C3, ESP32S3.
+#define UART_SOURCE_CLK UART_SCLK_XTAL
#else
+#define UART_SOURCE_CLK UART_SCLK_DEFAULT
+#endif
+
#define UART_INV_TX UART_SIGNAL_TXD_INV
#define UART_INV_RX UART_SIGNAL_RXD_INV
#define UART_INV_RTS UART_SIGNAL_RTS_INV
#define UART_INV_CTS UART_SIGNAL_CTS_INV
-#endif
#define UART_INV_MASK (UART_INV_TX | UART_INV_RX | UART_INV_RTS | UART_INV_CTS)
@@ -58,10 +59,10 @@ typedef struct _machine_uart_obj_t {
uint8_t bits;
uint8_t parity;
uint8_t stop;
- int8_t tx;
- int8_t rx;
- int8_t rts;
- int8_t cts;
+ gpio_num_t tx;
+ gpio_num_t rx;
+ gpio_num_t rts;
+ gpio_num_t cts;
uint16_t txbuf;
uint16_t rxbuf;
uint16_t timeout; // timeout waiting for first char (in ms)
@@ -133,10 +134,10 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_stop, MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
- { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
- { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
- { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = UART_PIN_NO_CHANGE} },
+ { MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_txbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
@@ -164,7 +165,8 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
}
uart_config_t uartcfg = {
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .rx_flow_ctrl_thresh = 0
+ .rx_flow_ctrl_thresh = 0,
+ .source_clk = UART_SOURCE_CLK,
};
uint32_t baudrate;
uart_get_baudrate(self->uart_num, &baudrate);
@@ -184,22 +186,22 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
}
uart_get_baudrate(self->uart_num, &baudrate);
- uart_set_pin(self->uart_num, args[ARG_tx].u_int, args[ARG_rx].u_int, args[ARG_rts].u_int, args[ARG_cts].u_int);
- if (args[ARG_tx].u_int != UART_PIN_NO_CHANGE) {
- self->tx = args[ARG_tx].u_int;
+ if (args[ARG_tx].u_obj != MP_OBJ_NULL) {
+ self->tx = machine_pin_get_id(args[ARG_tx].u_obj);
}
- if (args[ARG_rx].u_int != UART_PIN_NO_CHANGE) {
- self->rx = args[ARG_rx].u_int;
+ if (args[ARG_rx].u_obj != MP_OBJ_NULL) {
+ self->rx = machine_pin_get_id(args[ARG_rx].u_obj);
}
- if (args[ARG_rts].u_int != UART_PIN_NO_CHANGE) {
- self->rts = args[ARG_rts].u_int;
+ if (args[ARG_rts].u_obj != MP_OBJ_NULL) {
+ self->rts = machine_pin_get_id(args[ARG_rts].u_obj);
}
- if (args[ARG_cts].u_int != UART_PIN_NO_CHANGE) {
- self->cts = args[ARG_cts].u_int;
+ if (args[ARG_cts].u_obj != MP_OBJ_NULL) {
+ self->cts = machine_pin_get_id(args[ARG_cts].u_obj);
}
+ uart_set_pin(self->uart_num, self->tx, self->rx, self->rts, self->cts);
// set data bits
switch (args[ARG_bits].u_int) {
@@ -273,9 +275,7 @@ STATIC void machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args, co
uint32_t char_time_ms = 12000 / baudrate + 1;
uint32_t rx_timeout = self->timeout_char / char_time_ms;
if (rx_timeout < 1) {
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0)
uart_set_rx_full_threshold(self->uart_num, 1);
- #endif
uart_set_rx_timeout(self->uart_num, 1);
} else {
uart_set_rx_timeout(self->uart_num, rx_timeout);
@@ -317,7 +317,8 @@ STATIC mp_obj_t machine_uart_make_new(const mp_obj_type_t *type, size_t n_args,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .rx_flow_ctrl_thresh = 0
+ .rx_flow_ctrl_thresh = 0,
+ .source_clk = UART_SOURCE_CLK,
};
// create instance
diff --git a/ports/esp32/machine_wdt.c b/ports/esp32/machine_wdt.c
index 4ccf417b6099..bf924c35e09b 100644
--- a/ports/esp32/machine_wdt.c
+++ b/ports/esp32/machine_wdt.c
@@ -37,9 +37,12 @@ const mp_obj_type_t machine_wdt_type;
typedef struct _machine_wdt_obj_t {
mp_obj_base_t base;
+ esp_task_wdt_user_handle_t twdt_user_handle;
} machine_wdt_obj_t;
-STATIC machine_wdt_obj_t wdt_default = {{&machine_wdt_type}};
+STATIC machine_wdt_obj_t wdt_default = {
+ {&machine_wdt_type}, 0
+};
STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_id, ARG_timeout };
@@ -54,26 +57,36 @@ STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, size_t n_args
mp_raise_ValueError(NULL);
}
- // Convert milliseconds to seconds (esp_task_wdt_init needs seconds)
- args[ARG_timeout].u_int /= 1000;
-
if (args[ARG_timeout].u_int <= 0) {
mp_raise_ValueError(MP_ERROR_TEXT("WDT timeout too short"));
}
- mp_int_t rs_code = esp_task_wdt_init(args[ARG_timeout].u_int, true);
+ esp_task_wdt_config_t config = {
+ .timeout_ms = args[ARG_timeout].u_int,
+ .idle_core_mask = 0,
+ .trigger_panic = true,
+ };
+ mp_int_t rs_code = esp_task_wdt_reconfigure(&config);
if (rs_code != ESP_OK) {
mp_raise_OSError(rs_code);
}
- esp_task_wdt_add(NULL);
+ if (wdt_default.twdt_user_handle == NULL) {
+ rs_code = esp_task_wdt_add_user("mpy_machine_wdt", &wdt_default.twdt_user_handle);
+ if (rs_code != ESP_OK) {
+ mp_raise_OSError(rs_code);
+ }
+ }
return &wdt_default;
}
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
(void)self_in;
- esp_task_wdt_reset();
+ mp_int_t rs_code = esp_task_wdt_reset_user(wdt_default.twdt_user_handle);
+ if (rs_code != ESP_OK) {
+ mp_raise_OSError(rs_code);
+ }
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index c543c5b645d5..3a172e6f8d4a 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -35,16 +35,9 @@
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_task.h"
-#include "soc/cpu.h"
+#include "esp_event.h"
#include "esp_log.h"
-
-#if CONFIG_IDF_TARGET_ESP32
-#include "esp32/spiram.h"
-#elif CONFIG_IDF_TARGET_ESP32S2
-#include "esp32s2/spiram.h"
-#elif CONFIG_IDF_TARGET_ESP32S3
-#include "esp32s3/spiram.h"
-#endif
+#include "esp_psram.h"
#include "py/stackctrl.h"
#include "py/nlr.h"
@@ -67,6 +60,10 @@
#include "extmod/modbluetooth.h"
#endif
+#if MICROPY_ESPNOW
+#include "modespnow.h"
+#endif
+
// MicroPython runs as a task under FreeRTOS
#define MP_TASK_PRIORITY (ESP_TASK_PRIO_MIN + 1)
#define MP_TASK_STACK_SIZE (16 * 1024)
@@ -84,11 +81,11 @@ int vprintf_null(const char *format, va_list ap) {
}
void mp_task(void *pvParameter) {
- volatile uint32_t sp = (uint32_t)get_sp();
+ volatile uint32_t sp = (uint32_t)esp_cpu_get_sp();
#if MICROPY_PY_THREAD
mp_thread_init(pxTaskGetStackStart(NULL), MP_TASK_STACK_SIZE / sizeof(uintptr_t));
#endif
- #if CONFIG_USB_ENABLED
+ #if CONFIG_USB_OTG_SUPPORTED
usb_init();
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
usb_serial_jtag_init();
@@ -98,50 +95,18 @@ void mp_task(void *pvParameter) {
#endif
machine_init();
- size_t mp_task_heap_size;
- void *mp_task_heap = NULL;
-
- #if CONFIG_SPIRAM_USE_MALLOC
- // SPIRAM is issued using MALLOC, fallback to normal allocation rules
- mp_task_heap = NULL;
- #elif CONFIG_ESP32_SPIRAM_SUPPORT
- // Try to use the entire external SPIRAM directly for the heap
- mp_task_heap = (void *)SOC_EXTRAM_DATA_LOW;
- switch (esp_spiram_get_chip_size()) {
- case ESP_SPIRAM_SIZE_16MBITS:
- mp_task_heap_size = 2 * 1024 * 1024;
- break;
- case ESP_SPIRAM_SIZE_32MBITS:
- case ESP_SPIRAM_SIZE_64MBITS:
- mp_task_heap_size = 4 * 1024 * 1024;
- break;
- default:
- // No SPIRAM, fallback to normal allocation
- mp_task_heap = NULL;
- break;
- }
- #elif CONFIG_ESP32S2_SPIRAM_SUPPORT || CONFIG_ESP32S3_SPIRAM_SUPPORT
- // Try to use the entire external SPIRAM directly for the heap
- size_t esp_spiram_size = esp_spiram_get_size();
- if (esp_spiram_size > 0) {
- mp_task_heap = (void *)SOC_EXTRAM_DATA_HIGH - esp_spiram_size;
- mp_task_heap_size = esp_spiram_size;
+ esp_err_t err = esp_event_loop_create_default();
+ if (err != ESP_OK) {
+ ESP_LOGE("esp_init", "can't create event loop: 0x%x\n", err);
}
- #endif
- if (mp_task_heap == NULL) {
- // Allocate the uPy heap using malloc and get the largest available region,
- // limiting to 1/2 total available memory to leave memory for the OS.
- #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0)
- size_t heap_total = heap_caps_get_total_size(MALLOC_CAP_8BIT);
- #else
- multi_heap_info_t info;
- heap_caps_get_info(&info, MALLOC_CAP_8BIT);
- size_t heap_total = info.total_free_bytes + info.total_allocated_bytes;
- #endif
- mp_task_heap_size = MIN(heap_caps_get_largest_free_block(MALLOC_CAP_8BIT), heap_total / 2);
- mp_task_heap = malloc(mp_task_heap_size);
- }
+ // Allocate the uPy heap using malloc and get the largest available region,
+ // limiting to 1/2 total available memory to leave memory for the OS.
+ // When SPIRAM is enabled, this will allocate from SPIRAM.
+ uint32_t caps = MALLOC_CAP_8BIT;
+ size_t heap_total = heap_caps_get_total_size(caps);
+ size_t mp_task_heap_size = MIN(heap_caps_get_largest_free_block(caps), heap_total / 2);
+ void *mp_task_heap = heap_caps_malloc(mp_task_heap_size, caps);
soft_reset:
// initialise the stack pointer for the main thread
@@ -161,7 +126,7 @@ void mp_task(void *pvParameter) {
#endif
// run boot-up scripts
- pyexec_frozen_module("_boot.py");
+ pyexec_frozen_module("_boot.py", false);
pyexec_file_if_exists("boot.py");
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
int ret = pyexec_file_if_exists("main.py");
@@ -190,6 +155,11 @@ void mp_task(void *pvParameter) {
mp_bluetooth_deinit();
#endif
+ #if MICROPY_ESPNOW
+ espnow_deinit(mp_const_none);
+ MP_STATE_PORT(espnow_singleton) = NULL;
+ #endif
+
machine_timer_deinit_all();
#if MICROPY_PY_THREAD
@@ -215,7 +185,9 @@ void mp_task(void *pvParameter) {
// TODO: machine_rmt_deinit_all();
machine_pins_deinit();
machine_deinit();
- usocket_events_deinit();
+ #if MICROPY_PY_SOCKET_EVENTS
+ socket_events_deinit();
+ #endif
mp_deinit();
fflush(stdout);
@@ -244,11 +216,6 @@ void nlr_jump_fail(void *val) {
esp_restart();
}
-// modussl_mbedtls uses this function but it's not enabled in ESP IDF
-void mbedtls_debug_set_threshold(int threshold) {
- (void)threshold;
-}
-
void *esp_native_code_commit(void *buf, size_t len, void *reloc) {
len = (len + 3) & ~3;
uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC);
diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt
deleted file mode 100644
index fccfd6b7c7a9..000000000000
--- a/ports/esp32/main/CMakeLists.txt
+++ /dev/null
@@ -1,227 +0,0 @@
-# Set location of base MicroPython directory.
-if(NOT MICROPY_DIR)
- get_filename_component(MICROPY_DIR ${PROJECT_DIR}/../.. ABSOLUTE)
-endif()
-
-# Include core source components.
-include(${MICROPY_DIR}/py/py.cmake)
-
-if(NOT CMAKE_BUILD_EARLY_EXPANSION)
- # Enable extmod components that will be configured by extmod.cmake.
- # A board may also have enabled additional components.
- set(MICROPY_PY_BTREE ON)
-
- include(${MICROPY_DIR}/py/usermod.cmake)
- include(${MICROPY_DIR}/extmod/extmod.cmake)
-endif()
-
-set(MICROPY_QSTRDEFS_PORT
- ${PROJECT_DIR}/qstrdefsport.h
-)
-
-set(MICROPY_SOURCE_SHARED
- ${MICROPY_DIR}/shared/readline/readline.c
- ${MICROPY_DIR}/shared/netutils/netutils.c
- ${MICROPY_DIR}/shared/timeutils/timeutils.c
- ${MICROPY_DIR}/shared/runtime/interrupt_char.c
- ${MICROPY_DIR}/shared/runtime/stdout_helpers.c
- ${MICROPY_DIR}/shared/runtime/sys_stdio_mphal.c
- ${MICROPY_DIR}/shared/runtime/pyexec.c
-)
-
-set(MICROPY_SOURCE_LIB
- ${MICROPY_DIR}/lib/littlefs/lfs1.c
- ${MICROPY_DIR}/lib/littlefs/lfs1_util.c
- ${MICROPY_DIR}/lib/littlefs/lfs2.c
- ${MICROPY_DIR}/lib/littlefs/lfs2_util.c
- ${MICROPY_DIR}/lib/mbedtls_errors/mp_mbedtls_errors.c
- ${MICROPY_DIR}/lib/oofatfs/ff.c
- ${MICROPY_DIR}/lib/oofatfs/ffunicode.c
-)
-if(IDF_TARGET STREQUAL "esp32c3")
- list(APPEND MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/runtime/gchelper_generic.c)
-endif()
-
-set(MICROPY_SOURCE_DRIVERS
- ${MICROPY_DIR}/drivers/bus/softspi.c
- ${MICROPY_DIR}/drivers/dht/dht.c
-)
-
-set(MICROPY_SOURCE_PORT
- ${PROJECT_DIR}/main.c
- ${PROJECT_DIR}/uart.c
- ${PROJECT_DIR}/usb.c
- ${PROJECT_DIR}/usb_serial_jtag.c
- ${PROJECT_DIR}/gccollect.c
- ${PROJECT_DIR}/mphalport.c
- ${PROJECT_DIR}/fatfs_port.c
- ${PROJECT_DIR}/help.c
- ${PROJECT_DIR}/modutime.c
- ${PROJECT_DIR}/machine_bitstream.c
- ${PROJECT_DIR}/machine_timer.c
- ${PROJECT_DIR}/machine_pin.c
- ${PROJECT_DIR}/machine_touchpad.c
- ${PROJECT_DIR}/machine_adc.c
- ${PROJECT_DIR}/machine_adcblock.c
- ${PROJECT_DIR}/machine_dac.c
- ${PROJECT_DIR}/machine_i2c.c
- ${PROJECT_DIR}/machine_i2s.c
- ${PROJECT_DIR}/machine_uart.c
- ${PROJECT_DIR}/modmachine.c
- ${PROJECT_DIR}/modnetwork.c
- ${PROJECT_DIR}/network_lan.c
- ${PROJECT_DIR}/network_ppp.c
- ${PROJECT_DIR}/network_wlan.c
- ${PROJECT_DIR}/mpnimbleport.c
- ${PROJECT_DIR}/modsocket.c
- ${PROJECT_DIR}/modesp.c
- ${PROJECT_DIR}/esp32_nvs.c
- ${PROJECT_DIR}/esp32_partition.c
- ${PROJECT_DIR}/esp32_rmt.c
- ${PROJECT_DIR}/esp32_ulp.c
- ${PROJECT_DIR}/modesp32.c
- ${PROJECT_DIR}/machine_hw_spi.c
- ${PROJECT_DIR}/machine_wdt.c
- ${PROJECT_DIR}/mpthreadport.c
- ${PROJECT_DIR}/machine_rtc.c
- ${PROJECT_DIR}/machine_sdcard.c
-)
-
-set(MICROPY_SOURCE_QSTR
- ${MICROPY_SOURCE_PY}
- ${MICROPY_SOURCE_EXTMOD}
- ${MICROPY_SOURCE_USERMOD}
- ${MICROPY_SOURCE_SHARED}
- ${MICROPY_SOURCE_LIB}
- ${MICROPY_SOURCE_PORT}
- ${MICROPY_SOURCE_BOARD}
-)
-
-set(IDF_COMPONENTS
- app_update
- bootloader_support
- bt
- driver
- esp_adc_cal
- esp_common
- esp_eth
- esp_event
- esp_ringbuf
- esp_rom
- esp_wifi
- freertos
- heap
- log
- lwip
- mbedtls
- mdns
- newlib
- nvs_flash
- sdmmc
- soc
- spi_flash
- tcpip_adapter
- ulp
- vfs
- xtensa
-)
-
-if(IDF_VERSION_MINOR GREATER_EQUAL 1 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
- list(APPEND IDF_COMPONENTS esp_netif)
-endif()
-
-if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
- list(APPEND IDF_COMPONENTS esp_system)
- list(APPEND IDF_COMPONENTS esp_timer)
-endif()
-
-if(IDF_VERSION_MINOR GREATER_EQUAL 3 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
- list(APPEND IDF_COMPONENTS esp_hw_support)
- list(APPEND IDF_COMPONENTS esp_pm)
- list(APPEND IDF_COMPONENTS hal)
-endif()
-
-if(IDF_TARGET STREQUAL "esp32")
- list(APPEND IDF_COMPONENTS esp32)
-elseif(IDF_TARGET STREQUAL "esp32c3")
- list(APPEND IDF_COMPONENTS esp32c3)
- list(APPEND IDF_COMPONENTS riscv)
-elseif(IDF_TARGET STREQUAL "esp32s2")
- list(APPEND IDF_COMPONENTS esp32s2)
- list(APPEND IDF_COMPONENTS tinyusb)
-elseif(IDF_TARGET STREQUAL "esp32s3")
- list(APPEND IDF_COMPONENTS esp32s3)
- list(APPEND IDF_COMPONENTS tinyusb)
-endif()
-
-# Register the main IDF component.
-idf_component_register(
- SRCS
- ${MICROPY_SOURCE_PY}
- ${MICROPY_SOURCE_EXTMOD}
- ${MICROPY_SOURCE_SHARED}
- ${MICROPY_SOURCE_LIB}
- ${MICROPY_SOURCE_DRIVERS}
- ${MICROPY_SOURCE_PORT}
- ${MICROPY_SOURCE_BOARD}
- INCLUDE_DIRS
- ${MICROPY_INC_CORE}
- ${MICROPY_INC_USERMOD}
- ${MICROPY_PORT_DIR}
- ${MICROPY_BOARD_DIR}
- ${CMAKE_BINARY_DIR}
- REQUIRES
- ${IDF_COMPONENTS}
-)
-
-# Set the MicroPython target as the current (main) IDF component target.
-set(MICROPY_TARGET ${COMPONENT_TARGET})
-
-# Define mpy-cross flags, for use with frozen code.
-set(MICROPY_CROSS_FLAGS -march=xtensawin)
-
-# Set compile options for this port.
-target_compile_definitions(${MICROPY_TARGET} PUBLIC
- ${MICROPY_DEF_CORE}
- MICROPY_ESP_IDF_4=1
- MICROPY_VFS_FAT=1
- MICROPY_VFS_LFS2=1
- FFCONF_H=\"${MICROPY_OOFATFS_DIR}/ffconf.h\"
- LFS1_NO_MALLOC LFS1_NO_DEBUG LFS1_NO_WARN LFS1_NO_ERROR LFS1_NO_ASSERT
- LFS2_NO_MALLOC LFS2_NO_DEBUG LFS2_NO_WARN LFS2_NO_ERROR LFS2_NO_ASSERT
-)
-
-# Disable some warnings to keep the build output clean.
-target_compile_options(${MICROPY_TARGET} PUBLIC
- -Wno-clobbered
- -Wno-deprecated-declarations
- -Wno-missing-field-initializers
-)
-
-# Additional include directories needed for private NimBLE headers.
-target_include_directories(${MICROPY_TARGET} PUBLIC
- ${IDF_PATH}/components/bt/host/nimble/nimble
-)
-
-# Add additional extmod and usermod components.
-target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree)
-target_link_libraries(${MICROPY_TARGET} usermod)
-
-# Collect all of the include directories and compile definitions for the IDF components.
-foreach(comp ${IDF_COMPONENTS})
- micropy_gather_target_properties(__idf_${comp})
-endforeach()
-
-if(IDF_VERSION_MINOR GREATER_EQUAL 2 OR IDF_VERSION_MAJOR GREATER_EQUAL 5)
- # These paths cannot currently be found by the IDF_COMPONENTS search loop above,
- # so add them explicitly.
- list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/${IDF_TARGET}/include)
- list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/soc/soc/include)
- if(IDF_VERSION_MINOR GREATER_EQUAL 3)
- list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/additions/include)
- list(APPEND MICROPY_CPP_INC_EXTRA ${IDF_PATH}/components/tinyusb/tinyusb/src)
- endif()
-endif()
-
-# Include the main MicroPython cmake rules.
-include(${MICROPY_DIR}/py/mkrules.cmake)
diff --git a/ports/esp32/main_esp32/CMakeLists.txt b/ports/esp32/main_esp32/CMakeLists.txt
new file mode 100644
index 000000000000..40188abff8e5
--- /dev/null
+++ b/ports/esp32/main_esp32/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Set location of base MicroPython directory.
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE)
+endif()
+
+# Set location of the ESP32 port directory.
+if(NOT MICROPY_PORT_DIR)
+ get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
+endif()
+
+include(${MICROPY_PORT_DIR}/esp32_common.cmake)
diff --git a/ports/esp32/main_esp32/idf_component.yml b/ports/esp32/main_esp32/idf_component.yml
new file mode 100644
index 000000000000..8be21ed2fbe8
--- /dev/null
+++ b/ports/esp32/main_esp32/idf_component.yml
@@ -0,0 +1,5 @@
+## IDF Component Manager Manifest File
+dependencies:
+ espressif/mdns: "~1.1.0"
+ idf:
+ version: ">=5.0.2"
diff --git a/ports/esp32/main_esp32c3/CMakeLists.txt b/ports/esp32/main_esp32c3/CMakeLists.txt
new file mode 100644
index 000000000000..307c0f32183a
--- /dev/null
+++ b/ports/esp32/main_esp32c3/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Set location of base MicroPython directory.
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE)
+endif()
+
+# Set location of the ESP32 port directory.
+if(NOT MICROPY_PORT_DIR)
+ get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
+endif()
+
+list(APPEND MICROPY_SOURCE_LIB ${MICROPY_DIR}/shared/runtime/gchelper_generic.c)
+list(APPEND IDF_COMPONENTS riscv)
+
+include(${MICROPY_PORT_DIR}/esp32_common.cmake)
diff --git a/ports/esp32/main_esp32c3/idf_component.yml b/ports/esp32/main_esp32c3/idf_component.yml
new file mode 100644
index 000000000000..8be21ed2fbe8
--- /dev/null
+++ b/ports/esp32/main_esp32c3/idf_component.yml
@@ -0,0 +1,5 @@
+## IDF Component Manager Manifest File
+dependencies:
+ espressif/mdns: "~1.1.0"
+ idf:
+ version: ">=5.0.2"
diff --git a/ports/esp32/main_esp32s2/CMakeLists.txt b/ports/esp32/main_esp32s2/CMakeLists.txt
new file mode 100644
index 000000000000..40188abff8e5
--- /dev/null
+++ b/ports/esp32/main_esp32s2/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Set location of base MicroPython directory.
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE)
+endif()
+
+# Set location of the ESP32 port directory.
+if(NOT MICROPY_PORT_DIR)
+ get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
+endif()
+
+include(${MICROPY_PORT_DIR}/esp32_common.cmake)
diff --git a/ports/esp32/main_esp32s2/idf_component.yml b/ports/esp32/main_esp32s2/idf_component.yml
new file mode 100644
index 000000000000..69e27bf8b54b
--- /dev/null
+++ b/ports/esp32/main_esp32s2/idf_component.yml
@@ -0,0 +1,6 @@
+## IDF Component Manager Manifest File
+dependencies:
+ espressif/mdns: "~1.1.0"
+ espressif/esp_tinyusb: "~1.0.0"
+ idf:
+ version: ">=5.0.2"
diff --git a/ports/esp32/main_esp32s3/CMakeLists.txt b/ports/esp32/main_esp32s3/CMakeLists.txt
new file mode 100644
index 000000000000..40188abff8e5
--- /dev/null
+++ b/ports/esp32/main_esp32s3/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Set location of base MicroPython directory.
+if(NOT MICROPY_DIR)
+ get_filename_component(MICROPY_DIR ${CMAKE_CURRENT_LIST_DIR}/../../.. ABSOLUTE)
+endif()
+
+# Set location of the ESP32 port directory.
+if(NOT MICROPY_PORT_DIR)
+ get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
+endif()
+
+include(${MICROPY_PORT_DIR}/esp32_common.cmake)
diff --git a/ports/esp32/main_esp32s3/idf_component.yml b/ports/esp32/main_esp32s3/idf_component.yml
new file mode 100644
index 000000000000..69e27bf8b54b
--- /dev/null
+++ b/ports/esp32/main_esp32s3/idf_component.yml
@@ -0,0 +1,6 @@
+## IDF Component Manager Manifest File
+dependencies:
+ espressif/mdns: "~1.1.0"
+ espressif/esp_tinyusb: "~1.0.0"
+ idf:
+ version: ">=5.0.2"
diff --git a/ports/esp32/modesp.c b/ports/esp32/modesp.c
index 0c6429be7f1e..4726ce587420 100644
--- a/ports/esp32/modesp.c
+++ b/ports/esp32/modesp.c
@@ -29,13 +29,12 @@
#include
+#include "esp_flash.h"
#include "esp_log.h"
-#include "esp_spi_flash.h"
#include "py/runtime.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "drivers/dht/dht.h"
STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) {
esp_log_level_t level = LOG_LOCAL_LEVEL;
@@ -54,33 +53,33 @@ STATIC mp_obj_t esp_osdebug(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_osdebug_obj, 1, 2, esp_osdebug);
-STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t buf_in) {
+STATIC mp_obj_t esp_flash_read_(mp_obj_t offset_in, mp_obj_t buf_in) {
mp_int_t offset = mp_obj_get_int(offset_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
- esp_err_t res = spi_flash_read(offset, bufinfo.buf, bufinfo.len);
+ esp_err_t res = esp_flash_read(NULL, bufinfo.buf, offset, bufinfo.len);
if (res != ESP_OK) {
mp_raise_OSError(MP_EIO);
}
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read_);
-STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, mp_obj_t buf_in) {
+STATIC mp_obj_t esp_flash_write_(mp_obj_t offset_in, mp_obj_t buf_in) {
mp_int_t offset = mp_obj_get_int(offset_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
- esp_err_t res = spi_flash_write(offset, bufinfo.buf, bufinfo.len);
+ esp_err_t res = esp_flash_write(NULL, bufinfo.buf, offset, bufinfo.len);
if (res != ESP_OK) {
mp_raise_OSError(MP_EIO);
}
return mp_const_none;
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write_);
STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
mp_int_t sector = mp_obj_get_int(sector_in);
- esp_err_t res = spi_flash_erase_sector(sector);
+ esp_err_t res = esp_flash_erase_region(NULL, sector * 4096, 4096);
if (res != ESP_OK) {
mp_raise_OSError(MP_EIO);
}
@@ -89,7 +88,9 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
STATIC mp_obj_t esp_flash_size(void) {
- return mp_obj_new_int_from_uint(spi_flash_get_chip_size());
+ uint32_t size;
+ esp_flash_get_size(NULL, &size);
+ return mp_obj_new_int_from_uint(size);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
@@ -99,14 +100,14 @@ STATIC mp_obj_t esp_flash_user_start(void) {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start);
STATIC mp_obj_t esp_gpio_matrix_in(mp_obj_t pin, mp_obj_t sig, mp_obj_t inv) {
- gpio_matrix_in(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv));
+ esp_rom_gpio_connect_in_signal(mp_obj_get_int(pin), mp_obj_get_int(sig), mp_obj_get_int(inv));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_gpio_matrix_in_obj, esp_gpio_matrix_in);
STATIC mp_obj_t esp_gpio_matrix_out(size_t n_args, const mp_obj_t *args) {
(void)n_args;
- gpio_matrix_out(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3]));
+ esp_rom_gpio_connect_out_signal(mp_obj_get_int(args[0]), mp_obj_get_int(args[1]), mp_obj_get_int(args[2]), mp_obj_get_int(args[3]));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_gpio_matrix_out_obj, 4, 4, esp_gpio_matrix_out);
@@ -125,8 +126,6 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_gpio_matrix_in), MP_ROM_PTR(&esp_gpio_matrix_in_obj) },
{ MP_ROM_QSTR(MP_QSTR_gpio_matrix_out), MP_ROM_PTR(&esp_gpio_matrix_out_obj) },
- { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
-
// Constants for second arg of osdebug()
{ MP_ROM_QSTR(MP_QSTR_LOG_NONE), MP_ROM_INT((mp_uint_t)ESP_LOG_NONE)},
{ MP_ROM_QSTR(MP_QSTR_LOG_ERROR), MP_ROM_INT((mp_uint_t)ESP_LOG_ERROR)},
diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c
index 017db36e22ad..ef3ad0b76d45 100644
--- a/ports/esp32/modesp32.c
+++ b/ports/esp32/modesp32.c
@@ -45,10 +45,8 @@
#include "modesp32.h"
// These private includes are needed for idf_heap_info.
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
#define MULTI_HEAP_FREERTOS
#include "../multi_heap_platform.h"
-#endif
#include "../heap_private.h"
STATIC mp_obj_t esp32_wake_on_touch(const mp_obj_t wake) {
@@ -161,21 +159,15 @@ STATIC mp_obj_t esp32_raw_temperature(void) {
CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT);
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE);
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP);
- ets_delay_us(100);
+ esp_rom_delay_us(100);
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT);
- ets_delay_us(5);
+ esp_rom_delay_us(5);
int res = GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT, SENS_TSENS_OUT_S);
return mp_obj_new_int(res);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_raw_temperature_obj, esp32_raw_temperature);
-STATIC mp_obj_t esp32_hall_sensor(void) {
- adc1_config_width(ADC_WIDTH_12Bit);
- return MP_OBJ_NEW_SMALL_INT(hall_sensor_read());
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_hall_sensor_obj, esp32_hall_sensor);
-
#endif
STATIC mp_obj_t esp32_idf_heap_info(const mp_obj_t cap_in) {
@@ -210,14 +202,13 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_gpio_deep_sleep_hold), MP_ROM_PTR(&esp32_gpio_deep_sleep_hold_obj) },
#if CONFIG_IDF_TARGET_ESP32
{ MP_ROM_QSTR(MP_QSTR_raw_temperature), MP_ROM_PTR(&esp32_raw_temperature_obj) },
- { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_idf_heap_info), MP_ROM_PTR(&esp32_idf_heap_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_NVS), MP_ROM_PTR(&esp32_nvs_type) },
{ MP_ROM_QSTR(MP_QSTR_Partition), MP_ROM_PTR(&esp32_partition_type) },
{ MP_ROM_QSTR(MP_QSTR_RMT), MP_ROM_PTR(&esp32_rmt_type) },
- #if CONFIG_IDF_TARGET_ESP32
+ #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{ MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) },
#endif
diff --git a/ports/esp32/modespnow.c b/ports/esp32/modespnow.c
new file mode 100644
index 000000000000..08836c0ad790
--- /dev/null
+++ b/ports/esp32/modespnow.c
@@ -0,0 +1,861 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2020 Nick Moore
+ * Copyright (c) 2018 shawwwn
+ * Copyright (c) 2020-2021 Glenn Moloney @glenn20
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include
+#include
+#include
+
+#include "esp_log.h"
+#include "esp_now.h"
+#include "esp_wifi.h"
+#include "esp_wifi_types.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "py/obj.h"
+#include "py/objstr.h"
+#include "py/objarray.h"
+#include "py/stream.h"
+#include "py/binary.h"
+#include "py/ringbuf.h"
+
+#include "mpconfigport.h"
+#include "mphalport.h"
+#include "modnetwork.h"
+#include "modespnow.h"
+
+#ifndef MICROPY_ESPNOW_RSSI
+// Include code to track rssi of peers
+#define MICROPY_ESPNOW_RSSI 1
+#endif
+#ifndef MICROPY_ESPNOW_EXTRA_PEER_METHODS
+// Include mod_peer(),get_peer(),peer_count()
+#define MICROPY_ESPNOW_EXTRA_PEER_METHODS 1
+#endif
+
+// Relies on gcc Variadic Macros and Statement Expressions
+#define NEW_TUPLE(...) \
+ ({mp_obj_t _z[] = {__VA_ARGS__}; mp_obj_new_tuple(MP_ARRAY_SIZE(_z), _z); })
+
+static const uint8_t ESPNOW_MAGIC = 0x99;
+
+// ESPNow packet format for the receive buffer.
+// Use this for peeking at the header of the next packet in the buffer.
+typedef struct {
+ uint8_t magic; // = ESPNOW_MAGIC
+ uint8_t msg_len; // Length of the message
+ #if MICROPY_ESPNOW_RSSI
+ uint32_t time_ms; // Timestamp (ms) when packet is received
+ int8_t rssi; // RSSI value (dBm) (-127 to 0)
+ #endif // MICROPY_ESPNOW_RSSI
+} __attribute__((packed)) espnow_hdr_t;
+
+typedef struct {
+ espnow_hdr_t hdr; // The header
+ uint8_t peer[6]; // Peer address
+ uint8_t msg[0]; // Message is up to 250 bytes
+} __attribute__((packed)) espnow_pkt_t;
+
+// The maximum length of an espnow packet (bytes)
+static const size_t MAX_PACKET_LEN = (
+ (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN));
+
+// Enough for 2 full-size packets: 2 * (6 + 7 + 250) = 526 bytes
+// Will allocate an additional 7 bytes for buffer overhead
+static const size_t DEFAULT_RECV_BUFFER_SIZE = (2 * MAX_PACKET_LEN);
+
+// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes).
+static const size_t DEFAULT_RECV_TIMEOUT_MS = (5 * 60 * 1000);
+
+// Time to wait (millisec) for responses from sent packets: (2 seconds).
+static const size_t DEFAULT_SEND_TIMEOUT_MS = (2 * 1000);
+
+// Number of milliseconds to wait for pending responses to sent packets.
+// This is a fallback which should never be reached.
+static const mp_uint_t PENDING_RESPONSES_TIMEOUT_MS = 100;
+static const mp_uint_t PENDING_RESPONSES_BUSY_POLL_MS = 10;
+
+// The data structure for the espnow_singleton.
+typedef struct _esp_espnow_obj_t {
+ mp_obj_base_t base;
+
+ ringbuf_t *recv_buffer; // A buffer for received packets
+ size_t recv_buffer_size; // The size of the recv_buffer
+ mp_int_t recv_timeout_ms; // Timeout for recv()
+ volatile size_t rx_packets; // # of received packets
+ size_t dropped_rx_pkts; // # of dropped packets (buffer full)
+ size_t tx_packets; // # of sent packets
+ volatile size_t tx_responses; // # of sent packet responses received
+ volatile size_t tx_failures; // # of sent packet responses failed
+ size_t peer_count; // Cache the # of peers for send(sync=True)
+ mp_obj_t recv_cb; // Callback when a packet is received
+ mp_obj_t recv_cb_arg; // Argument passed to callback
+ #if MICROPY_ESPNOW_RSSI
+ mp_obj_t peers_table; // A dictionary of discovered peers
+ #endif // MICROPY_ESPNOW_RSSI
+} esp_espnow_obj_t;
+
+const mp_obj_type_t esp_espnow_type;
+
+// ### Initialisation and Config functions
+//
+
+// Return a pointer to the ESPNow module singleton
+// If state == INITIALISED check the device has been initialised.
+// Raises OSError if not initialised and state == INITIALISED.
+static esp_espnow_obj_t *_get_singleton() {
+ return MP_STATE_PORT(espnow_singleton);
+}
+
+static esp_espnow_obj_t *_get_singleton_initialised() {
+ esp_espnow_obj_t *self = _get_singleton();
+ // assert(self);
+ if (self->recv_buffer == NULL) {
+ // Throw an espnow not initialised error
+ check_esp_err(ESP_ERR_ESPNOW_NOT_INIT);
+ }
+ return self;
+}
+
+// Allocate and initialise the ESPNow module as a singleton.
+// Returns the initialised espnow_singleton.
+STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_args) {
+
+ // The espnow_singleton must be defined in MICROPY_PORT_ROOT_POINTERS
+ // (see mpconfigport.h) to prevent memory allocated here from being
+ // garbage collected.
+ // NOTE: on soft reset the espnow_singleton MUST be set to NULL and the
+ // ESP-NOW functions de-initialised (see main.c).
+ esp_espnow_obj_t *self = MP_STATE_PORT(espnow_singleton);
+ if (self != NULL) {
+ return self;
+ }
+ self = m_new_obj(esp_espnow_obj_t);
+ self->base.type = &esp_espnow_type;
+ self->recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE;
+ self->recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS;
+ self->recv_buffer = NULL; // Buffer is allocated in espnow_init()
+ self->recv_cb = mp_const_none;
+ #if MICROPY_ESPNOW_RSSI
+ self->peers_table = mp_obj_new_dict(0);
+ // Prevent user code modifying the dict
+ mp_obj_dict_get_map(self->peers_table)->is_fixed = 1;
+ #endif // MICROPY_ESPNOW_RSSI
+
+ // Set the global singleton pointer for the espnow protocol.
+ MP_STATE_PORT(espnow_singleton) = self;
+
+ return self;
+}
+
+// Forward declare the send and recv ESPNow callbacks
+STATIC void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status);
+
+STATIC void recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *msg, int msg_len);
+
+// ESPNow.init(): Initialise the data buffers and ESP-NOW functions.
+// Initialise the Espressif ESPNOW software stack, register callbacks and
+// allocate the recv data buffers.
+// Returns None.
+static mp_obj_t espnow_init(mp_obj_t _) {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (self->recv_buffer == NULL) { // Already initialised
+ self->recv_buffer = m_new_obj(ringbuf_t);
+ ringbuf_alloc(self->recv_buffer, self->recv_buffer_size);
+
+ esp_initialise_wifi(); // Call the wifi init code in network_wlan.c
+ check_esp_err(esp_now_init());
+ check_esp_err(esp_now_register_recv_cb(recv_cb));
+ check_esp_err(esp_now_register_send_cb(send_cb));
+ }
+ return mp_const_none;
+}
+
+// ESPNow.deinit(): De-initialise the ESPNOW software stack, disable callbacks
+// and deallocate the recv data buffers.
+// Note: this function is called from main.c:mp_task() to cleanup before soft
+// reset, so cannot be declared STATIC and must guard against self == NULL;.
+mp_obj_t espnow_deinit(mp_obj_t _) {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (self != NULL && self->recv_buffer != NULL) {
+ check_esp_err(esp_now_unregister_recv_cb());
+ check_esp_err(esp_now_unregister_send_cb());
+ check_esp_err(esp_now_deinit());
+ self->recv_buffer->buf = NULL;
+ self->recv_buffer = NULL;
+ self->peer_count = 0; // esp_now_deinit() removes all peers.
+ self->tx_packets = self->tx_responses;
+ }
+ return mp_const_none;
+}
+
+STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (n_args > 1) {
+ if (mp_obj_is_true(args[1])) {
+ espnow_init(self);
+ } else {
+ espnow_deinit(self);
+ }
+ }
+ return self->recv_buffer != NULL ? mp_const_true : mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_active_obj, 1, 2, espnow_active);
+
+// ESPNow.config(['param'|param=value, ..])
+// Get or set configuration values. Supported config params:
+// buffer: size of buffer for rx packets (default=514 bytes)
+// timeout: Default read timeout (default=300,000 milliseconds)
+STATIC mp_obj_t espnow_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ esp_espnow_obj_t *self = _get_singleton();
+ enum { ARG_get, ARG_rxbuf, ARG_timeout_ms, ARG_rate };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_timeout_ms, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MIN} },
+ { MP_QSTR_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
+ MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ if (args[ARG_rxbuf].u_int >= 0) {
+ self->recv_buffer_size = args[ARG_rxbuf].u_int;
+ }
+ if (args[ARG_timeout_ms].u_int != INT_MIN) {
+ self->recv_timeout_ms = args[ARG_timeout_ms].u_int;
+ }
+ if (args[ARG_rate].u_int >= 0) {
+ esp_initialise_wifi(); // Call the wifi init code in network_wlan.c
+ check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, args[ARG_rate].u_int));
+ check_esp_err(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, args[ARG_rate].u_int));
+ }
+ if (args[ARG_get].u_obj == MP_OBJ_NULL) {
+ return mp_const_none;
+ }
+#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
+ // Return the value of the requested parameter
+ uintptr_t name = (uintptr_t)args[ARG_get].u_obj;
+ if (name == QS(MP_QSTR_rxbuf)) {
+ return mp_obj_new_int(self->recv_buffer_size);
+ } else if (name == QS(MP_QSTR_timeout_ms)) {
+ return mp_obj_new_int(self->recv_timeout_ms);
+ } else {
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+ }
+#undef QS
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config);
+
+// ESPNow.irq(recv_cb)
+// Set callback function to be invoked when a message is received.
+STATIC mp_obj_t espnow_irq(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton();
+ mp_obj_t recv_cb = args[1];
+ if (recv_cb != mp_const_none && !mp_obj_is_callable(recv_cb)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid handler"));
+ }
+ self->recv_cb = recv_cb;
+ self->recv_cb_arg = (n_args > 2) ? args[2] : mp_const_none;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_irq_obj, 2, 3, espnow_irq);
+
+// ESPnow.stats(): Provide some useful stats.
+// Returns a tuple of:
+// (tx_pkts, tx_responses, tx_failures, rx_pkts, dropped_rx_pkts)
+STATIC mp_obj_t espnow_stats(mp_obj_t _) {
+ const esp_espnow_obj_t *self = _get_singleton();
+ return NEW_TUPLE(
+ mp_obj_new_int(self->tx_packets),
+ mp_obj_new_int(self->tx_responses),
+ mp_obj_new_int(self->tx_failures),
+ mp_obj_new_int(self->rx_packets),
+ mp_obj_new_int(self->dropped_rx_pkts));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_stats_obj, espnow_stats);
+
+#if MICROPY_ESPNOW_RSSI
+// ### Maintaining the peer table and reading RSSI values
+//
+// We maintain a peers table for several reasons, to:
+// - support monitoring the RSSI values for all peers; and
+// - to return unique bytestrings for each peer which supports more efficient
+// application memory usage and peer handling.
+
+// Lookup a peer in the peers table and return a reference to the item in the
+// peers_table. Add peer to the table if it is not found (may alloc memory).
+// Will not return NULL.
+static mp_map_elem_t *_lookup_add_peer(esp_espnow_obj_t *self, const uint8_t *peer) {
+ // We do not want to allocate any new memory in the case that the peer
+ // already exists in the peers_table (which is almost all the time).
+ // So, we use a byte string on the stack and look that up in the dict.
+ mp_map_t *map = mp_obj_dict_get_map(self->peers_table);
+ mp_obj_str_t peer_obj = {{&mp_type_bytes}, 0, ESP_NOW_ETH_ALEN, peer};
+ mp_map_elem_t *item = mp_map_lookup(map, &peer_obj, MP_MAP_LOOKUP);
+ if (item == NULL) {
+ // If not found, add the peer using a new bytestring
+ map->is_fixed = 0; // Allow to modify the dict
+ mp_obj_t new_peer = mp_obj_new_bytes(peer, ESP_NOW_ETH_ALEN);
+ item = mp_map_lookup(map, new_peer, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ item->value = mp_obj_new_list(2, NULL);
+ map->is_fixed = 1; // Relock the dict
+ }
+ return item;
+}
+
+// Update the peers table with the new rssi value from a received pkt and
+// return a reference to the item in the peers_table.
+static mp_map_elem_t *_update_rssi(const uint8_t *peer, int8_t rssi, uint32_t time_ms) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+ // Lookup the peer in the device table
+ mp_map_elem_t *item = _lookup_add_peer(self, peer);
+ mp_obj_list_t *list = MP_OBJ_TO_PTR(item->value);
+ list->items[0] = MP_OBJ_NEW_SMALL_INT(rssi);
+ list->items[1] = mp_obj_new_int(time_ms);
+ return item;
+}
+#endif // MICROPY_ESPNOW_RSSI
+
+// Return C pointer to byte memory string/bytes/bytearray in obj.
+// Raise ValueError if the length does not match expected len.
+static uint8_t *_get_bytes_len_rw(mp_obj_t obj, size_t len, mp_uint_t rw) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(obj, &bufinfo, rw);
+ if (bufinfo.len != len) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
+ }
+ return (uint8_t *)bufinfo.buf;
+}
+
+static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len) {
+ return _get_bytes_len_rw(obj, len, MP_BUFFER_READ);
+}
+
+static uint8_t *_get_bytes_len_w(mp_obj_t obj, size_t len) {
+ return _get_bytes_len_rw(obj, len, MP_BUFFER_WRITE);
+}
+
+// Return C pointer to the MAC address.
+// Raise ValueError if mac_addr is wrong type or is not 6 bytes long.
+static const uint8_t *_get_peer(mp_obj_t mac_addr) {
+ return mp_obj_is_true(mac_addr)
+ ? _get_bytes_len(mac_addr, ESP_NOW_ETH_ALEN) : NULL;
+}
+
+// Copy data from the ring buffer - wait if buffer is empty up to timeout_ms
+// 0: Success
+// -1: Not enough data available to complete read (try again later)
+// -2: Requested read is larger than buffer - will never succeed
+static int ringbuf_get_bytes_wait(ringbuf_t *r, uint8_t *data, size_t len, mp_int_t timeout_ms) {
+ mp_uint_t start = mp_hal_ticks_ms();
+ int status = 0;
+ while (((status = ringbuf_get_bytes(r, data, len)) == -1)
+ && (timeout_ms < 0 || (mp_uint_t)(mp_hal_ticks_ms() - start) < (mp_uint_t)timeout_ms)) {
+ MICROPY_EVENT_POLL_HOOK;
+ }
+ return status;
+}
+
+// ESPNow.recvinto(buffers[, timeout_ms]):
+// Waits for an espnow message and copies the peer_addr and message into
+// the buffers list.
+// Arguments:
+// buffers: (Optional) list of bytearrays to store return values.
+// timeout_ms: (Optional) timeout in milliseconds (or None).
+// Buffers should be a list: [bytearray(6), bytearray(250)]
+// If buffers is 4 elements long, the rssi and timestamp values will be
+// loaded into the 3rd and 4th elements.
+// Default timeout is set with ESPNow.config(timeout=milliseconds).
+// Return (None, None) on timeout.
+STATIC mp_obj_t espnow_recvinto(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ mp_int_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none)
+ ? mp_obj_get_int(args[2]) : self->recv_timeout_ms);
+
+ mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]);
+ if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) {
+ mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recvinto(): Invalid argument"));
+ }
+ mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]);
+ if (mp_obj_is_type(msg, &mp_type_bytearray)) {
+ msg->len += msg->free; // Make all the space in msg array available
+ msg->free = 0;
+ }
+ #if MICROPY_ESPNOW_RSSI
+ uint8_t peer_buf[ESP_NOW_ETH_ALEN];
+ #else
+ uint8_t *peer_buf = _get_bytes_len_w(list->items[0], ESP_NOW_ETH_ALEN);
+ #endif // MICROPY_ESPNOW_RSSI
+ uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN);
+
+ // Read the packet header from the incoming buffer
+ espnow_hdr_t hdr;
+ if (ringbuf_get_bytes_wait(self->recv_buffer, (uint8_t *)&hdr, sizeof(hdr), timeout_ms) < 0) {
+ return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet
+ }
+ int msg_len = hdr.msg_len;
+
+ // Check the message packet header format and read the message data
+ if (hdr.magic != ESPNOW_MAGIC
+ || msg_len > ESP_NOW_MAX_DATA_LEN
+ || ringbuf_get_bytes(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 0
+ || ringbuf_get_bytes(self->recv_buffer, msg_buf, msg_len) < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recv(): buffer error"));
+ }
+ if (mp_obj_is_type(msg, &mp_type_bytearray)) {
+ // Set the length of the message bytearray.
+ size_t size = msg->len + msg->free;
+ msg->len = msg_len;
+ msg->free = size - msg_len;
+ }
+
+ #if MICROPY_ESPNOW_RSSI
+ // Update rssi value in the peer device table
+ mp_map_elem_t *entry = _update_rssi(peer_buf, hdr.rssi, hdr.time_ms);
+ list->items[0] = entry->key; // Set first element of list to peer
+ if (list->len >= 4) {
+ list->items[2] = MP_OBJ_NEW_SMALL_INT(hdr.rssi);
+ list->items[3] = mp_obj_new_int(hdr.time_ms);
+ }
+ #endif // MICROPY_ESPNOW_RSSI
+
+ return MP_OBJ_NEW_SMALL_INT(msg_len);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recvinto_obj, 2, 3, espnow_recvinto);
+
+// Test if data is available to read from the buffers
+STATIC mp_obj_t espnow_any(const mp_obj_t _) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ return ringbuf_avail(self->recv_buffer) ? mp_const_true : mp_const_false;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_any_obj, espnow_any);
+
+// Used by espnow_send() for sends() with sync==True.
+// Wait till all pending sent packet responses have been received.
+// ie. self->tx_responses == self->tx_packets.
+static void _wait_for_pending_responses(esp_espnow_obj_t *self) {
+ mp_uint_t start = mp_hal_ticks_ms();
+ mp_uint_t t;
+ while (self->tx_responses < self->tx_packets) {
+ if ((t = mp_hal_ticks_ms() - start) > PENDING_RESPONSES_TIMEOUT_MS) {
+ mp_raise_OSError(MP_ETIMEDOUT);
+ }
+ if (t > PENDING_RESPONSES_BUSY_POLL_MS) {
+ // After 10ms of busy waiting give other tasks a look in.
+ MICROPY_EVENT_POLL_HOOK;
+ }
+ }
+}
+
+// ESPNow.send(peer_addr, message, [sync (=true), size])
+// ESPNow.send(message)
+// Send a message to the peer's mac address. Optionally wait for a response.
+// If peer_addr == None or any non-true value, send to all registered peers.
+// If sync == True, wait for response after sending.
+// If size is provided it should be the number of bytes in message to send().
+// Returns:
+// True if sync==False and message sent successfully.
+// True if sync==True and message is received successfully by all recipients
+// False if sync==True and message is not received by at least one recipient
+// Raises: EAGAIN if the internal espnow buffers are full.
+STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+ // Check the various combinations of input arguments
+ const uint8_t *peer = (n_args > 2) ? _get_peer(args[1]) : NULL;
+ mp_obj_t msg = (n_args > 2) ? args[2] : (n_args == 2) ? args[1] : MP_OBJ_NULL;
+ bool sync = n_args <= 3 || args[3] == mp_const_none || mp_obj_is_true(args[3]);
+
+ // Get a pointer to the data buffer of the message
+ mp_buffer_info_t message;
+ mp_get_buffer_raise(msg, &message, MP_BUFFER_READ);
+
+ if (sync) {
+ // Flush out any pending responses.
+ // If the last call was sync==False there may be outstanding responses
+ // still to be received (possible many if we just had a burst of
+ // unsync send()s). We need to wait for all pending responses if this
+ // call has sync=True.
+ _wait_for_pending_responses(self);
+ }
+ int saved_failures = self->tx_failures;
+ // Send the packet - try, try again if internal esp-now buffers are full.
+ esp_err_t err;
+ mp_uint_t start = mp_hal_ticks_ms();
+ while ((ESP_ERR_ESPNOW_NO_MEM == (err = esp_now_send(peer, message.buf, message.len)))
+ && (mp_uint_t)(mp_hal_ticks_ms() - start) < (mp_uint_t)DEFAULT_SEND_TIMEOUT_MS) {
+ MICROPY_EVENT_POLL_HOOK;
+ }
+ check_esp_err(err); // Will raise OSError if e != ESP_OK
+ // Increment the sent packet count. If peer_addr==NULL msg will be
+ // sent to all peers EXCEPT any broadcast or multicast addresses.
+ self->tx_packets += ((peer == NULL) ? self->peer_count : 1);
+ if (sync) {
+ // Wait for and tally all the expected responses from peers
+ _wait_for_pending_responses(self);
+ }
+ // Return False if sync and any peers did not respond.
+ return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_send_obj, 2, 4, espnow_send);
+
+// ### The ESP_Now send and recv callback routines
+//
+
+// Callback triggered when a sent packet is acknowledged by the peer (or not).
+// Just count the number of responses and number of failures.
+// These are used in the send() logic.
+STATIC void send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) {
+ esp_espnow_obj_t *self = _get_singleton();
+ self->tx_responses++;
+ if (status != ESP_NOW_SEND_SUCCESS) {
+ self->tx_failures++;
+ }
+}
+
+// Callback triggered when an ESP-Now packet is received.
+// Write the peer MAC address and the message into the recv_buffer as an
+// ESPNow packet.
+// If the buffer is full, drop the message and increment the dropped count.
+// Schedules the user callback if one has been registered (ESPNow.config()).
+STATIC void recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *msg, int msg_len) {
+ esp_espnow_obj_t *self = _get_singleton();
+ ringbuf_t *buf = self->recv_buffer;
+ // TODO: Test this works with ">".
+ if (sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) {
+ self->dropped_rx_pkts++;
+ return;
+ }
+ espnow_hdr_t header;
+ header.magic = ESPNOW_MAGIC;
+ header.msg_len = msg_len;
+ #if MICROPY_ESPNOW_RSSI
+ header.rssi = recv_info->rx_ctrl->rssi;
+ header.time_ms = mp_hal_ticks_ms();
+ #endif // MICROPY_ESPNOW_RSSI
+
+ ringbuf_put_bytes(buf, (uint8_t *)&header, sizeof(header));
+ ringbuf_put_bytes(buf, recv_info->src_addr, ESP_NOW_ETH_ALEN);
+ ringbuf_put_bytes(buf, msg, msg_len);
+ self->rx_packets++;
+ if (self->recv_cb != mp_const_none) {
+ mp_sched_schedule(self->recv_cb, self->recv_cb_arg);
+ }
+}
+
+// ### Peer Management Functions
+//
+
+// Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications).
+// Raise OSError if ESP-NOW functions are not initialised.
+// Raise ValueError if key is not a bytes-like object exactly 16 bytes long.
+STATIC mp_obj_t espnow_set_pmk(mp_obj_t _, mp_obj_t key) {
+ check_esp_err(esp_now_set_pmk(_get_bytes_len(key, ESP_NOW_KEY_LEN)));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk);
+
+// Common code for add_peer() and mod_peer() to process the args and kw_args:
+// Raise ValueError if the LMK is not a bytes-like object of exactly 16 bytes.
+// Raise TypeError if invalid keyword args or too many positional args.
+// Return true if all args parsed correctly.
+STATIC bool _update_peer_info(
+ esp_now_peer_info_t *peer, size_t n_args,
+ const mp_obj_t *pos_args, mp_map_t *kw_args) {
+
+ enum { ARG_lmk, ARG_channel, ARG_ifidx, ARG_encrypt };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_lmk, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_channel, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_ifidx, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_encrypt, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ if (args[ARG_lmk].u_obj != mp_const_none) {
+ mp_obj_t obj = args[ARG_lmk].u_obj;
+ peer->encrypt = mp_obj_is_true(obj);
+ if (peer->encrypt) {
+ // Key must be 16 bytes in length.
+ memcpy(peer->lmk, _get_bytes_len(obj, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN);
+ }
+ }
+ if (args[ARG_channel].u_obj != mp_const_none) {
+ peer->channel = mp_obj_get_int(args[ARG_channel].u_obj);
+ }
+ if (args[ARG_ifidx].u_obj != mp_const_none) {
+ peer->ifidx = mp_obj_get_int(args[ARG_ifidx].u_obj);
+ }
+ if (args[ARG_encrypt].u_obj != mp_const_none) {
+ peer->encrypt = mp_obj_is_true(args[ARG_encrypt].u_obj);
+ }
+ return true;
+}
+
+// Update the cached peer count in self->peer_count;
+// The peer_count ignores broadcast and multicast addresses and is used for the
+// send() logic and is updated from add_peer(), mod_peer() and del_peer().
+STATIC void _update_peer_count() {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ esp_now_peer_info_t peer = {0};
+ bool from_head = true;
+ int count = 0;
+ // esp_now_fetch_peer() skips over any broadcast or multicast addresses
+ while (esp_now_fetch_peer(from_head, &peer) == ESP_OK) {
+ from_head = false;
+ if (++count >= ESP_NOW_MAX_TOTAL_PEER_NUM) {
+ break; // Should not happen
+ }
+ }
+ self->peer_count = count;
+}
+
+// ESPNow.add_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or
+// ESPNow.add_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False],
+// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False])
+// Positional args set to None will be left at defaults.
+// Raise OSError if ESPNow.init() has not been called.
+// Raise ValueError if mac or LMK are not bytes-like objects or wrong length.
+// Raise TypeError if invalid keyword args or too many positional args.
+// Return None.
+STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ esp_now_peer_info_t peer = {0};
+ memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN);
+ _update_peer_info(&peer, n_args - 2, args + 2, kw_args);
+
+ check_esp_err(esp_now_add_peer(&peer));
+ _update_peer_count();
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_add_peer_obj, 2, espnow_add_peer);
+
+// ESPNow.del_peer(peer_mac): Unregister peer_mac.
+// Raise OSError if ESPNow.init() has not been called.
+// Raise ValueError if peer is not a bytes-like objects or wrong length.
+// Return None.
+STATIC mp_obj_t espnow_del_peer(mp_obj_t _, mp_obj_t peer) {
+ uint8_t peer_addr[ESP_NOW_ETH_ALEN];
+ memcpy(peer_addr, _get_peer(peer), ESP_NOW_ETH_ALEN);
+
+ check_esp_err(esp_now_del_peer(peer_addr));
+ _update_peer_count();
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_del_peer_obj, espnow_del_peer);
+
+// Convert a peer_info struct to python tuple
+// Used by espnow_get_peer() and espnow_get_peers()
+static mp_obj_t _peer_info_to_tuple(const esp_now_peer_info_t *peer) {
+ return NEW_TUPLE(
+ mp_obj_new_bytes(peer->peer_addr, MP_ARRAY_SIZE(peer->peer_addr)),
+ mp_obj_new_bytes(peer->lmk, MP_ARRAY_SIZE(peer->lmk)),
+ mp_obj_new_int(peer->channel),
+ mp_obj_new_int(peer->ifidx),
+ (peer->encrypt) ? mp_const_true : mp_const_false);
+}
+
+// ESPNow.get_peers(): Fetch peer_info records for all registered ESPNow peers.
+// Raise OSError if ESPNow.init() has not been called.
+// Return a tuple of tuples:
+// ((peer_addr, lmk, channel, ifidx, encrypt),
+// (peer_addr, lmk, channel, ifidx, encrypt), ...)
+STATIC mp_obj_t espnow_get_peers(mp_obj_t _) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ // Build and initialise the peer info tuple.
+ mp_obj_tuple_t *peerinfo_tuple = mp_obj_new_tuple(self->peer_count, NULL);
+ esp_now_peer_info_t peer = {0};
+ for (int i = 0; i < peerinfo_tuple->len; i++) {
+ int status = esp_now_fetch_peer((i == 0), &peer);
+ peerinfo_tuple->items[i] =
+ (status == ESP_OK ? _peer_info_to_tuple(&peer) : mp_const_none);
+ }
+
+ return peerinfo_tuple;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_get_peers_obj, espnow_get_peers);
+
+#if MICROPY_ESPNOW_EXTRA_PEER_METHODS
+// ESPNow.get_peer(peer_mac): Get the peer info for peer_mac as a tuple.
+// Raise OSError if ESPNow.init() has not been called.
+// Raise ValueError if mac or LMK are not bytes-like objects or wrong length.
+// Return a tuple of (peer_addr, lmk, channel, ifidx, encrypt).
+STATIC mp_obj_t espnow_get_peer(mp_obj_t _, mp_obj_t arg1) {
+ esp_now_peer_info_t peer = {0};
+ memcpy(peer.peer_addr, _get_peer(arg1), ESP_NOW_ETH_ALEN);
+
+ check_esp_err(esp_now_get_peer(peer.peer_addr, &peer));
+
+ return _peer_info_to_tuple(&peer);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_get_peer_obj, espnow_get_peer);
+
+// ESPNow.mod_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]]) or
+// ESPNow.mod_peer(peer_mac, [lmk=b'0123456789abcdef'|b''|None|False],
+// [channel=1..11|0], [ifidx=0|1], [encrypt=True|False])
+// Positional args set to None will be left at current values.
+// Raise OSError if ESPNow.init() has not been called.
+// Raise ValueError if mac or LMK are not bytes-like objects or wrong length.
+// Raise TypeError if invalid keyword args or too many positional args.
+// Return None.
+STATIC mp_obj_t espnow_mod_peer(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
+ esp_now_peer_info_t peer = {0};
+ memcpy(peer.peer_addr, _get_peer(args[1]), ESP_NOW_ETH_ALEN);
+ check_esp_err(esp_now_get_peer(peer.peer_addr, &peer));
+
+ _update_peer_info(&peer, n_args - 2, args + 2, kw_args);
+
+ check_esp_err(esp_now_mod_peer(&peer));
+ _update_peer_count();
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_mod_peer_obj, 2, espnow_mod_peer);
+
+// ESPNow.espnow_peer_count(): Get the number of registered peers.
+// Raise OSError if ESPNow.init() has not been called.
+// Return a tuple of (num_total_peers, num_encrypted_peers).
+STATIC mp_obj_t espnow_peer_count(mp_obj_t _) {
+ esp_now_peer_num_t peer_num = {0};
+ check_esp_err(esp_now_get_peer_num(&peer_num));
+
+ return NEW_TUPLE(
+ mp_obj_new_int(peer_num.total_num),
+ mp_obj_new_int(peer_num.encrypt_num));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(espnow_peer_count_obj, espnow_peer_count);
+#endif
+
+STATIC const mp_rom_map_elem_t esp_espnow_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&espnow_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stats), MP_ROM_PTR(&espnow_stats_obj) },
+
+ // Send and receive messages
+ { MP_ROM_QSTR(MP_QSTR_recvinto), MP_ROM_PTR(&espnow_recvinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) },
+ { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&espnow_any_obj) },
+
+ // Peer management functions
+ { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) },
+ { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) },
+ { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_peers), MP_ROM_PTR(&espnow_get_peers_obj) },
+ #if MICROPY_ESPNOW_EXTRA_PEER_METHODS
+ { MP_ROM_QSTR(MP_QSTR_mod_peer), MP_ROM_PTR(&espnow_mod_peer_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_peer), MP_ROM_PTR(&espnow_get_peer_obj) },
+ { MP_ROM_QSTR(MP_QSTR_peer_count), MP_ROM_PTR(&espnow_peer_count_obj) },
+ #endif // MICROPY_ESPNOW_EXTRA_PEER_METHODS
+};
+STATIC MP_DEFINE_CONST_DICT(esp_espnow_locals_dict, esp_espnow_locals_dict_table);
+
+STATIC const mp_rom_map_elem_t espnow_globals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__espnow) },
+ { MP_ROM_QSTR(MP_QSTR_ESPNowBase), MP_ROM_PTR(&esp_espnow_type) },
+ { MP_ROM_QSTR(MP_QSTR_MAX_DATA_LEN), MP_ROM_INT(ESP_NOW_MAX_DATA_LEN)},
+ { MP_ROM_QSTR(MP_QSTR_ADDR_LEN), MP_ROM_INT(ESP_NOW_ETH_ALEN)},
+ { MP_ROM_QSTR(MP_QSTR_KEY_LEN), MP_ROM_INT(ESP_NOW_KEY_LEN)},
+ { MP_ROM_QSTR(MP_QSTR_MAX_TOTAL_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_TOTAL_PEER_NUM)},
+ { MP_ROM_QSTR(MP_QSTR_MAX_ENCRYPT_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_ENCRYPT_PEER_NUM)},
+};
+STATIC MP_DEFINE_CONST_DICT(espnow_globals_dict, espnow_globals_dict_table);
+
+// ### Dummy Buffer Protocol support
+// ...so asyncio can poll.ipoll() on this device
+
+// Support ioctl(MP_STREAM_POLL, ) for asyncio
+STATIC mp_uint_t espnow_stream_ioctl(
+ mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ if (request != MP_STREAM_POLL) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ esp_espnow_obj_t *self = _get_singleton();
+ return (self->recv_buffer == NULL) ? 0 : // If not initialised
+ arg ^ (
+ // If no data in the buffer, unset the Read ready flag
+ ((ringbuf_avail(self->recv_buffer) == 0) ? MP_STREAM_POLL_RD : 0) |
+ // If still waiting for responses, unset the Write ready flag
+ ((self->tx_responses < self->tx_packets) ? MP_STREAM_POLL_WR : 0));
+}
+
+STATIC const mp_stream_p_t espnow_stream_p = {
+ .ioctl = espnow_stream_ioctl,
+};
+
+#if MICROPY_ESPNOW_RSSI
+// Return reference to the dictionary of peers we have seen:
+// {peer1: (rssi, time_sec), peer2: (rssi, time_msec), ...}
+// where:
+// peerX is a byte string containing the 6-byte mac address of the peer,
+// rssi is the wifi signal strength from the last msg received
+// (in dBm from -127 to 0)
+// time_sec is the time in milliseconds since device last booted.
+STATIC void espnow_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (dest[0] != MP_OBJ_NULL) { // Only allow "Load" operation
+ return;
+ }
+ if (attr == MP_QSTR_peers_table) {
+ dest[0] = self->peers_table;
+ return;
+ }
+ dest[1] = MP_OBJ_SENTINEL; // Attribute not found
+}
+#endif // MICROPY_ESPNOW_RSSI
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ esp_espnow_type,
+ MP_QSTR_ESPNowBase,
+ MP_TYPE_FLAG_NONE,
+ make_new, espnow_make_new,
+ #if MICROPY_ESPNOW_RSSI
+ attr, espnow_attr,
+ #endif // MICROPY_ESPNOW_RSSI
+ protocol, &espnow_stream_p,
+ locals_dict, &esp_espnow_locals_dict
+ );
+
+const mp_obj_module_t mp_module_espnow = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&espnow_globals_dict,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow);
+MP_REGISTER_ROOT_POINTER(struct _esp_espnow_obj_t *espnow_singleton);
diff --git a/ports/esp32/modespnow.h b/ports/esp32/modespnow.h
new file mode 100644
index 000000000000..3c6280b1ced4
--- /dev/null
+++ b/ports/esp32/modespnow.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Glenn Moloney @glenn20
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+
+// Called from main.c:mp_task() to reset the espnow software stack
+mp_obj_t espnow_deinit(mp_obj_t _);
diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c
index a70f2fbedb59..31fa589aed0a 100644
--- a/ports/esp32/modmachine.c
+++ b/ports/esp32/modmachine.c
@@ -32,23 +32,14 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
+#include "esp_mac.h"
#include "esp_sleep.h"
#include "esp_pm.h"
-#if CONFIG_IDF_TARGET_ESP32
-#include "esp32/rom/rtc.h"
-#include "esp32/clk.h"
-#elif CONFIG_IDF_TARGET_ESP32S2
-#include "esp32s2/rom/rtc.h"
-#include "esp32s2/clk.h"
-#elif CONFIG_IDF_TARGET_ESP32S3
-#include "esp32s3/rom/rtc.h"
-#include "esp32s3/clk.h"
-#endif
-
#include "py/obj.h"
#include "py/runtime.h"
#include "shared/runtime/pyexec.h"
+#include "drivers/dht/dht.h"
#include "extmod/machine_bitstream.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_signal.h"
@@ -78,7 +69,7 @@ int esp_clk_cpu_freq(void);
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
- return mp_obj_new_int(esp_clk_cpu_freq());
+ return mp_obj_new_int(esp_rom_get_cpu_ticks_per_us() * 1000000);
} else {
// set
mp_int_t freq = mp_obj_get_int(args[0]) / 1000000;
@@ -109,7 +100,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (ret != ESP_OK) {
mp_raise_ValueError(NULL);
}
- while (esp_clk_cpu_freq() != freq * 1000000) {
+ while (esp_rom_get_cpu_ticks_per_us() != freq) {
vTaskDelay(1);
}
return mp_const_none;
@@ -216,6 +207,13 @@ STATIC mp_obj_t machine_reset_cause(size_t n_args, const mp_obj_t *pos_args, mp_
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_reset_cause_obj, 0, machine_reset_cause);
+NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
+ MICROPY_BOARD_ENTER_BOOTLOADER(n_args, args);
+ for (;;) {
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
+
void machine_init(void) {
is_soft_reset = 0;
}
@@ -271,7 +269,7 @@ STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
@@ -285,6 +283,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
@@ -295,6 +294,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_PULSE
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
#endif
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) },
@@ -307,7 +307,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
- #if CONFIG_IDF_TARGET_ESP32
+ #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
{ MP_ROM_QSTR(MP_QSTR_TouchPad), MP_ROM_PTR(&machine_touchpad_type) },
#endif
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&machine_adc_type) },
@@ -315,14 +315,14 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_DAC
{ MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&machine_dac_type) },
#endif
- { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hw_i2c_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
#if MICROPY_PY_MACHINE_I2S
{ MP_ROM_QSTR(MP_QSTR_I2S), MP_ROM_PTR(&machine_i2s_type) },
#endif
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) },
- { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hw_spi_type) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
@@ -351,6 +351,6 @@ const mp_obj_module_t mp_module_machine = {
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_umachine, mp_module_machine);
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
#endif // MICROPY_PY_MACHINE
diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h
index 4d2ab9020d16..24417f610746 100644
--- a/ports/esp32/modmachine.h
+++ b/ports/esp32/modmachine.h
@@ -16,8 +16,8 @@ extern const mp_obj_type_t machine_touchpad_type;
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_adcblock_type;
extern const mp_obj_type_t machine_dac_type;
-extern const mp_obj_type_t machine_hw_i2c_type;
-extern const mp_obj_type_t machine_hw_spi_type;
+extern const mp_obj_type_t machine_i2c_type;
+extern const mp_obj_type_t machine_spi_type;
extern const mp_obj_type_t machine_i2s_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_rtc_type;
@@ -31,5 +31,6 @@ void machine_pwm_deinit_all(void);
// TODO: void machine_rmt_deinit_all(void);
void machine_timer_deinit_all(void);
void machine_i2s_init0();
+NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args);
#endif // MICROPY_INCLUDED_ESP32_MODMACHINE_H
diff --git a/ports/esp32/modnetwork.c b/ports/esp32/modnetwork.c
deleted file mode 100644
index 7429274c1571..000000000000
--- a/ports/esp32/modnetwork.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * Development of the code in this file was sponsored by Microbric Pty Ltd
- * and Mnemote Pty Ltd
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016, 2017 Nick Moore @mnemote
- * Copyright (c) 2017 "Eric Poulsen"
- *
- * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
- * And the ESP IDF example code which is Public Domain / CC0
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-
-#include "py/runtime.h"
-#include "py/mperrno.h"
-#include "shared/netutils/netutils.h"
-#include "modnetwork.h"
-
-#include "esp_wifi.h"
-#include "esp_log.h"
-#include "lwip/dns.h"
-
-#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
-#define DNS_MAIN TCPIP_ADAPTER_DNS_MAIN
-#else
-#define DNS_MAIN ESP_NETIF_DNS_MAIN
-#endif
-
-#define MODNETWORK_INCLUDE_CONSTANTS (1)
-
-NORETURN void esp_exceptions_helper(esp_err_t e) {
- switch (e) {
- case ESP_ERR_WIFI_NOT_INIT:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Initialized"));
- case ESP_ERR_WIFI_NOT_STARTED:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Started"));
- case ESP_ERR_WIFI_NOT_STOPPED:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Stopped"));
- case ESP_ERR_WIFI_IF:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Interface"));
- case ESP_ERR_WIFI_MODE:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Mode"));
- case ESP_ERR_WIFI_STATE:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal State Error"));
- case ESP_ERR_WIFI_CONN:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal Error"));
- case ESP_ERR_WIFI_NVS:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal NVS Error"));
- case ESP_ERR_WIFI_MAC:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid MAC Address"));
- case ESP_ERR_WIFI_SSID:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi SSID Invalid"));
- case ESP_ERR_WIFI_PASSWORD:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Password"));
- case ESP_ERR_WIFI_TIMEOUT:
- mp_raise_OSError(MP_ETIMEDOUT);
- case ESP_ERR_WIFI_WAKE_FAIL:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Wakeup Failure"));
- case ESP_ERR_WIFI_WOULD_BLOCK:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Would Block"));
- case ESP_ERR_WIFI_NOT_CONNECT:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Connected"));
- case ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("TCP/IP Invalid Parameters"));
- case ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("TCP/IP IF Not Ready"));
- case ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED:
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("TCP/IP DHCP Client Start Failed"));
- case ESP_ERR_TCPIP_ADAPTER_NO_MEM:
- mp_raise_OSError(MP_ENOMEM);
- default:
- mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Wifi Unknown Error 0x%04x"), e);
- }
-}
-
-// This function is called by the system-event task and so runs in a different
-// thread to the main MicroPython task. It must not raise any Python exceptions.
-static esp_err_t event_handler(void *ctx, system_event_t *event) {
- switch (event->event_id) {
- #if MICROPY_PY_NETWORK_WLAN
- case SYSTEM_EVENT_STA_START:
- case SYSTEM_EVENT_STA_CONNECTED:
- case SYSTEM_EVENT_STA_GOT_IP:
- case SYSTEM_EVENT_STA_DISCONNECTED:
- network_wlan_event_handler(event);
- break;
- #endif
- case SYSTEM_EVENT_GOT_IP6:
- ESP_LOGI("network", "Got IPv6");
- break;
- case SYSTEM_EVENT_ETH_START:
- ESP_LOGI("ethernet", "start");
- break;
- case SYSTEM_EVENT_ETH_STOP:
- ESP_LOGI("ethernet", "stop");
- break;
- case SYSTEM_EVENT_ETH_CONNECTED:
- ESP_LOGI("ethernet", "LAN cable connected");
- break;
- case SYSTEM_EVENT_ETH_DISCONNECTED:
- ESP_LOGI("ethernet", "LAN cable disconnected");
- break;
- case SYSTEM_EVENT_ETH_GOT_IP:
- ESP_LOGI("ethernet", "Got IP");
- break;
- default:
- ESP_LOGI("network", "event %d", event->event_id);
- break;
- }
- return ESP_OK;
-}
-
-STATIC mp_obj_t esp_initialize() {
- static int initialized = 0;
- if (!initialized) {
- ESP_LOGD("modnetwork", "Initializing TCP/IP");
- tcpip_adapter_init();
- ESP_LOGD("modnetwork", "Initializing Event Loop");
- esp_exceptions(esp_event_loop_init(event_handler, NULL));
- ESP_LOGD("modnetwork", "esp_event_loop_init done");
- initialized = 1;
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_initialize_obj, esp_initialize);
-
-STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- tcpip_adapter_ip_info_t info;
- tcpip_adapter_dns_info_t dns_info;
- tcpip_adapter_get_ip_info(self->if_id, &info);
- tcpip_adapter_get_dns_info(self->if_id, DNS_MAIN, &dns_info);
- if (n_args == 1) {
- // get
- mp_obj_t tuple[4] = {
- netutils_format_ipv4_addr((uint8_t *)&info.ip, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&info.netmask, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&info.gw, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&dns_info.ip, NETUTILS_BIG),
- };
- return mp_obj_new_tuple(4, tuple);
- } else {
- // set
- if (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list)) {
- mp_obj_t *items;
- mp_obj_get_array_fixed_n(args[1], 4, &items);
- netutils_parse_ipv4_addr(items[0], (void *)&info.ip, NETUTILS_BIG);
- if (mp_obj_is_integer(items[1])) {
- // allow numeric netmask, i.e.:
- // 24 -> 255.255.255.0
- // 16 -> 255.255.0.0
- // etc...
- uint32_t *m = (uint32_t *)&info.netmask;
- *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
- } else {
- netutils_parse_ipv4_addr(items[1], (void *)&info.netmask, NETUTILS_BIG);
- }
- netutils_parse_ipv4_addr(items[2], (void *)&info.gw, NETUTILS_BIG);
- netutils_parse_ipv4_addr(items[3], (void *)&dns_info.ip, NETUTILS_BIG);
- // To set a static IP we have to disable DHCP first
- if (self->if_id == WIFI_IF_STA || self->if_id == ESP_IF_ETH) {
- esp_err_t e = tcpip_adapter_dhcpc_stop(self->if_id);
- if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) {
- esp_exceptions_helper(e);
- }
- esp_exceptions(tcpip_adapter_set_ip_info(self->if_id, &info));
- esp_exceptions(tcpip_adapter_set_dns_info(self->if_id, DNS_MAIN, &dns_info));
- } else if (self->if_id == WIFI_IF_AP) {
- esp_err_t e = tcpip_adapter_dhcps_stop(WIFI_IF_AP);
- if (e != ESP_OK && e != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED) {
- esp_exceptions_helper(e);
- }
- esp_exceptions(tcpip_adapter_set_ip_info(WIFI_IF_AP, &info));
- esp_exceptions(tcpip_adapter_set_dns_info(WIFI_IF_AP, DNS_MAIN, &dns_info));
- esp_exceptions(tcpip_adapter_dhcps_start(WIFI_IF_AP));
- }
- } else {
- // check for the correct string
- const char *mode = mp_obj_str_get_str(args[1]);
- if ((self->if_id != WIFI_IF_STA && self->if_id != ESP_IF_ETH) || strcmp("dhcp", mode)) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
- }
- esp_exceptions(tcpip_adapter_dhcpc_start(self->if_id));
- }
- return mp_const_none;
- }
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
-
-STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
-
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
-#define TEST_WIFI_AUTH_MAX 9
-#else
-#define TEST_WIFI_AUTH_MAX 8
-#endif
-_Static_assert(WIFI_AUTH_MAX == TEST_WIFI_AUTH_MAX, "Synchronize WIFI_AUTH_XXX constants with the ESP-IDF. Look at esp-idf/components/esp_wifi/include/esp_wifi_types.h");
-
-STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
- { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_initialize_obj) },
-
- #if MICROPY_PY_NETWORK_WLAN
- { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
- #endif
-
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
- { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&get_lan_obj) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&ppp_make_new_obj) },
- { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
-
- #if MODNETWORK_INCLUDE_CONSTANTS
-
- #if MICROPY_PY_NETWORK_WLAN
- { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)},
- { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)},
-
- { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) },
- { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) },
- { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) },
- { MP_ROM_QSTR(MP_QSTR_MODE_LR), MP_ROM_INT(WIFI_PROTOCOL_LR) },
-
- { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_ENTERPRISE), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA3_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) },
- #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0)
- { MP_ROM_QSTR(MP_QSTR_AUTH_WAPI_PSK), MP_ROM_INT(WIFI_AUTH_WAPI_PSK) },
- #endif
- { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
- #endif
-
- #if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
- { MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
- { MP_ROM_QSTR(MP_QSTR_PHY_IP101), MP_ROM_INT(PHY_IP101) },
- { MP_ROM_QSTR(MP_QSTR_PHY_RTL8201), MP_ROM_INT(PHY_RTL8201) },
- { MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) },
- #if ESP_IDF_VERSION_MINOR >= 3
- // PHY_KSZ8041 is new in ESP-IDF v4.3
- { MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) },
- #endif
-
- { MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)},
- { MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)},
- { MP_ROM_QSTR(MP_QSTR_ETH_STOPPED), MP_ROM_INT(ETH_STOPPED)},
- { MP_ROM_QSTR(MP_QSTR_ETH_CONNECTED), MP_ROM_INT(ETH_CONNECTED)},
- { MP_ROM_QSTR(MP_QSTR_ETH_DISCONNECTED), MP_ROM_INT(ETH_DISCONNECTED)},
- { MP_ROM_QSTR(MP_QSTR_ETH_GOT_IP), MP_ROM_INT(ETH_GOT_IP)},
- #endif
-
- { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)},
- { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)},
- { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STAT_GOT_IP)},
- // Errors from the ESP-IDF
- { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(WIFI_REASON_NO_AP_FOUND)},
- { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(WIFI_REASON_AUTH_FAIL)},
- { MP_ROM_QSTR(MP_QSTR_STAT_BEACON_TIMEOUT), MP_ROM_INT(WIFI_REASON_BEACON_TIMEOUT)},
- { MP_ROM_QSTR(MP_QSTR_STAT_ASSOC_FAIL), MP_ROM_INT(WIFI_REASON_ASSOC_FAIL)},
- { MP_ROM_QSTR(MP_QSTR_STAT_HANDSHAKE_TIMEOUT), MP_ROM_INT(WIFI_REASON_HANDSHAKE_TIMEOUT)},
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
-
-const mp_obj_module_t mp_module_network = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_network_globals,
-};
-
-// Note: This port doesn't define MICROPY_PY_NETWORK so this will not conflict
-// with the common implementation provided by extmod/modnetwork.c.
-MP_REGISTER_MODULE(MP_QSTR_network, mp_module_network);
diff --git a/ports/esp32/modnetwork.h b/ports/esp32/modnetwork.h
index 7bcfa0e6fcdb..79bf9973ca95 100644
--- a/ports/esp32/modnetwork.h
+++ b/ports/esp32/modnetwork.h
@@ -26,9 +26,10 @@
#ifndef MICROPY_INCLUDED_ESP32_MODNETWORK_H
#define MICROPY_INCLUDED_ESP32_MODNETWORK_H
-#include "esp_event.h"
+#include "esp_netif.h"
-enum { PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041 };
+enum { PHY_LAN8710, PHY_LAN8720, PHY_IP101, PHY_RTL8201, PHY_DP83848, PHY_KSZ8041, PHY_KSZ8081, PHY_KSZ8851SNL = 100, PHY_DM9051, PHY_W5500 };
+#define IS_SPI_PHY(NUM) (NUM >= 100)
enum { ETH_INITIALIZED, ETH_STARTED, ETH_STOPPED, ETH_CONNECTED, ETH_DISCONNECTED, ETH_GOT_IP };
// Cases similar to ESP8266 user_interface.h
@@ -39,16 +40,22 @@ enum {
STAT_GOT_IP = 1010,
};
-typedef struct _wlan_if_obj_t {
+typedef struct _base_if_obj_t {
mp_obj_base_t base;
- int if_id;
-} wlan_if_obj_t;
+ esp_interface_t if_id;
+ esp_netif_t *netif;
+ volatile bool active;
+} base_if_obj_t;
-MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj);
-MP_DECLARE_CONST_FUN_OBJ_KW(get_lan_obj);
-MP_DECLARE_CONST_FUN_OBJ_1(ppp_make_new_obj);
-MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj);
-MP_DECLARE_CONST_FUN_OBJ_KW(esp_config_obj);
+extern const mp_obj_type_t esp_network_wlan_type;
+
+MP_DECLARE_CONST_FUN_OBJ_0(esp_network_initialize_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_get_wlan_obj);
+MP_DECLARE_CONST_FUN_OBJ_KW(esp_network_get_lan_obj);
+MP_DECLARE_CONST_FUN_OBJ_1(esp_network_ppp_make_new_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_ifconfig_obj);
+MP_DECLARE_CONST_FUN_OBJ_KW(esp_network_config_obj);
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_phy_mode_obj);
NORETURN void esp_exceptions_helper(esp_err_t e);
@@ -58,7 +65,7 @@ static inline void esp_exceptions(esp_err_t e) {
}
}
-void usocket_events_deinit(void);
-void network_wlan_event_handler(system_event_t *event);
+void socket_events_deinit(void);
+void esp_initialise_wifi(void);
#endif
diff --git a/ports/esp32/modnetwork_globals.h b/ports/esp32/modnetwork_globals.h
new file mode 100644
index 000000000000..7326d453be5a
--- /dev/null
+++ b/ports/esp32/modnetwork_globals.h
@@ -0,0 +1,70 @@
+{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_network_initialize_obj) },
+
+#if MICROPY_PY_NETWORK_WLAN
+{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&esp_network_wlan_type) },
+#endif
+
+#if MICROPY_PY_NETWORK_LAN
+{ MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&esp_network_get_lan_obj) },
+#endif
+{ MP_ROM_QSTR(MP_QSTR_PPP), MP_ROM_PTR(&esp_network_ppp_make_new_obj) },
+{ MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_network_phy_mode_obj) },
+
+#if MICROPY_PY_NETWORK_WLAN
+{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(WIFI_IF_STA)},
+{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(WIFI_IF_AP)},
+
+{ MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) },
+{ MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) },
+{ MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) },
+{ MP_ROM_QSTR(MP_QSTR_MODE_LR), MP_ROM_INT(WIFI_PROTOCOL_LR) },
+
+{ MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_ENTERPRISE), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA3_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_WPA3_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_WPA3_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WAPI_PSK), MP_ROM_INT(WIFI_AUTH_WAPI_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_OWE), MP_ROM_INT(WIFI_AUTH_OWE) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
+#endif
+
+#if MICROPY_PY_NETWORK_LAN
+{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8710), MP_ROM_INT(PHY_LAN8710) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_IP101), MP_ROM_INT(PHY_IP101) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_RTL8201), MP_ROM_INT(PHY_RTL8201) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8041), MP_ROM_INT(PHY_KSZ8041) },
+{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8081), MP_ROM_INT(PHY_KSZ8081) },
+
+#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
+{ MP_ROM_QSTR(MP_QSTR_PHY_KSZ8851SNL), MP_ROM_INT(PHY_KSZ8851SNL) },
+#endif
+#if CONFIG_ETH_SPI_ETHERNET_DM9051
+{ MP_ROM_QSTR(MP_QSTR_PHY_DM9051), MP_ROM_INT(PHY_DM9051) },
+#endif
+#if CONFIG_ETH_SPI_ETHERNET_W5500
+{ MP_ROM_QSTR(MP_QSTR_PHY_W5500), MP_ROM_INT(PHY_W5500) },
+#endif
+
+{ MP_ROM_QSTR(MP_QSTR_ETH_INITIALIZED), MP_ROM_INT(ETH_INITIALIZED)},
+{ MP_ROM_QSTR(MP_QSTR_ETH_STARTED), MP_ROM_INT(ETH_STARTED)},
+{ MP_ROM_QSTR(MP_QSTR_ETH_STOPPED), MP_ROM_INT(ETH_STOPPED)},
+{ MP_ROM_QSTR(MP_QSTR_ETH_CONNECTED), MP_ROM_INT(ETH_CONNECTED)},
+{ MP_ROM_QSTR(MP_QSTR_ETH_DISCONNECTED), MP_ROM_INT(ETH_DISCONNECTED)},
+{ MP_ROM_QSTR(MP_QSTR_ETH_GOT_IP), MP_ROM_INT(ETH_GOT_IP)},
+#endif
+
+{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STAT_GOT_IP)},
+// Errors from the ESP-IDF
+{ MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(WIFI_REASON_NO_AP_FOUND)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(WIFI_REASON_AUTH_FAIL)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_BEACON_TIMEOUT), MP_ROM_INT(WIFI_REASON_BEACON_TIMEOUT)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_ASSOC_FAIL), MP_ROM_INT(WIFI_REASON_ASSOC_FAIL)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_HANDSHAKE_TIMEOUT), MP_ROM_INT(WIFI_REASON_HANDSHAKE_TIMEOUT)},
diff --git a/ports/esp32/modos.c b/ports/esp32/modos.c
new file mode 100644
index 000000000000..287f1d990021
--- /dev/null
+++ b/ports/esp32/modos.c
@@ -0,0 +1,65 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "esp_system.h"
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/misc.h"
+
+STATIC mp_obj_t mp_os_urandom(mp_obj_t num) {
+ mp_int_t n = mp_obj_get_int(num);
+ vstr_t vstr;
+ vstr_init_len(&vstr, n);
+ uint32_t r = 0;
+ for (int i = 0; i < n; i++) {
+ if ((i & 3) == 0) {
+ r = esp_random(); // returns 32-bit hardware random number
+ }
+ vstr.buf[i] = r;
+ r >>= 8;
+ }
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);
+
+#if MICROPY_PY_OS_DUPTERM_NOTIFY
+STATIC mp_obj_t mp_os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ for (;;) {
+ int c = mp_os_dupterm_rx_chr();
+ if (c < 0) {
+ break;
+ }
+ ringbuf_put(&stdin_ringbuf, c);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_dupterm_notify_obj, mp_os_dupterm_notify);
+#endif
diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c
index 9812eb347689..ba1fe096f694 100644
--- a/ports/esp32/modsocket.c
+++ b/ports/esp32/modsocket.c
@@ -46,7 +46,6 @@
#include "py/stream.h"
#include "py/mperrno.h"
#include "shared/netutils/netutils.h"
-#include "mdns.h"
#include "modnetwork.h"
#include "lwip/sockets.h"
@@ -59,6 +58,10 @@
#define MDNS_QUERY_TIMEOUT_MS (5000)
#define MDNS_LOCAL_SUFFIX ".local"
+#ifndef NO_QSTR
+#include "mdns.h"
+#endif
+
enum {
SOCKET_STATE_NEW,
SOCKET_STATE_CONNECTED,
@@ -73,7 +76,7 @@ typedef struct _socket_obj_t {
uint8_t proto;
uint8_t state;
unsigned int retries;
- #if MICROPY_PY_USOCKET_EVENTS
+ #if MICROPY_PY_SOCKET_EVENTS
mp_obj_t events_callback;
struct _socket_obj_t *events_next;
#endif
@@ -81,28 +84,28 @@ typedef struct _socket_obj_t {
void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms);
-#if MICROPY_PY_USOCKET_EVENTS
+#if MICROPY_PY_SOCKET_EVENTS
// Support for callbacks on asynchronous socket events (when socket becomes readable)
// This divisor is used to reduce the load on the system, so it doesn't poll sockets too often
#define USOCKET_EVENTS_DIVISOR (8)
-STATIC uint8_t usocket_events_divisor;
-STATIC socket_obj_t *usocket_events_head;
+STATIC uint8_t socket_events_divisor;
+STATIC socket_obj_t *socket_events_head;
-void usocket_events_deinit(void) {
- usocket_events_head = NULL;
+void socket_events_deinit(void) {
+ socket_events_head = NULL;
}
// Assumes the socket is not already in the linked list, and adds it
-STATIC void usocket_events_add(socket_obj_t *sock) {
- sock->events_next = usocket_events_head;
- usocket_events_head = sock;
+STATIC void socket_events_add(socket_obj_t *sock) {
+ sock->events_next = socket_events_head;
+ socket_events_head = sock;
}
// Assumes the socket is already in the linked list, and removes it
-STATIC void usocket_events_remove(socket_obj_t *sock) {
- for (socket_obj_t **s = &usocket_events_head;; s = &(*s)->events_next) {
+STATIC void socket_events_remove(socket_obj_t *sock) {
+ for (socket_obj_t **s = &socket_events_head;; s = &(*s)->events_next) {
if (*s == sock) {
*s = (*s)->events_next;
return;
@@ -111,20 +114,20 @@ STATIC void usocket_events_remove(socket_obj_t *sock) {
}
// Polls all registered sockets for readability and calls their callback if they are readable
-void usocket_events_handler(void) {
- if (usocket_events_head == NULL) {
+void socket_events_handler(void) {
+ if (socket_events_head == NULL) {
return;
}
- if (--usocket_events_divisor) {
+ if (--socket_events_divisor) {
return;
}
- usocket_events_divisor = USOCKET_EVENTS_DIVISOR;
+ socket_events_divisor = USOCKET_EVENTS_DIVISOR;
fd_set rfds;
FD_ZERO(&rfds);
int max_fd = 0;
- for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ for (socket_obj_t *s = socket_events_head; s != NULL; s = s->events_next) {
FD_SET(s->fd, &rfds);
max_fd = MAX(max_fd, s->fd);
}
@@ -137,14 +140,14 @@ void usocket_events_handler(void) {
}
// Call the callbacks
- for (socket_obj_t *s = usocket_events_head; s != NULL; s = s->events_next) {
+ for (socket_obj_t *s = socket_events_head; s != NULL; s = s->events_next) {
if (FD_ISSET(s->fd, &rfds)) {
mp_call_function_1_protected(s->events_callback, s);
}
}
}
-#endif // MICROPY_PY_USOCKET_EVENTS
+#endif // MICROPY_PY_SOCKET_EVENTS
static inline void check_for_exceptions(void) {
mp_handle_pending(true);
@@ -164,11 +167,7 @@ static int _socket_getaddrinfo3(const char *nodename, const char *servname,
memcpy(nodename_no_local, nodename, nodename_len - local_len);
nodename_no_local[nodename_len - local_len] = '\0';
- #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 1, 0)
- struct ip4_addr addr = {0};
- #else
esp_ip4_addr_t addr = {0};
- #endif
esp_err_t err = mdns_query_a(nodename_no_local, MDNS_QUERY_TIMEOUT_MS, &addr);
if (err != ESP_OK) {
@@ -299,7 +298,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
STATIC mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- int backlog = MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT;
+ int backlog = MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT;
if (n_args > 1) {
backlog = mp_obj_get_int(args[1]);
backlog = (backlog < 0) ? 0 : backlog;
@@ -396,18 +395,18 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
break;
}
- #if MICROPY_PY_USOCKET_EVENTS
+ #if MICROPY_PY_SOCKET_EVENTS
// level: SOL_SOCKET
// special "register callback" option
case 20: {
if (args[3] == mp_const_none) {
if (self->events_callback != MP_OBJ_NULL) {
- usocket_events_remove(self);
+ socket_events_remove(self);
self->events_callback = MP_OBJ_NULL;
}
} else {
if (self->events_callback == MP_OBJ_NULL) {
- usocket_events_add(self);
+ socket_events_add(self);
}
self->events_callback = args[3];
}
@@ -734,9 +733,9 @@ STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintpt
return ret;
} else if (request == MP_STREAM_CLOSE) {
if (socket->fd >= 0) {
- #if MICROPY_PY_USOCKET_EVENTS
+ #if MICROPY_PY_SOCKET_EVENTS
if (socket->events_callback != MP_OBJ_NULL) {
- usocket_events_remove(socket);
+ socket_events_remove(socket);
socket->events_callback = MP_OBJ_NULL;
}
#endif
@@ -836,7 +835,7 @@ STATIC mp_obj_t esp_socket_initialize() {
static int initialized = 0;
if (!initialized) {
ESP_LOGI("modsocket", "Initializing");
- tcpip_adapter_init();
+ esp_netif_init();
initialized = 1;
}
return mp_const_none;
@@ -844,7 +843,7 @@ STATIC mp_obj_t esp_socket_initialize() {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_socket_initialize_obj, esp_socket_initialize);
STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_socket) },
{ MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp_socket_initialize_obj) },
{ MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) },
{ MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&esp_socket_getaddrinfo_obj) },
@@ -864,12 +863,12 @@ STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
-const mp_obj_module_t mp_module_usocket = {
+const mp_obj_module_t mp_module_socket = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&mp_module_socket_globals,
};
-// Note: This port doesn't define MICROPY_PY_USOCKET or MICROPY_PY_LWIP so
+// Note: This port doesn't define MICROPY_PY_SOCKET or MICROPY_PY_LWIP so
// this will not conflict with the common implementation provided by
-// extmod/mod{lwip,usocket}.c.
-MP_REGISTER_MODULE(MP_QSTR_usocket, mp_module_usocket);
+// extmod/mod{lwip,socket}.c.
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_socket);
diff --git a/ports/esp32/modtime.c b/ports/esp32/modtime.c
new file mode 100644
index 000000000000..7a2b2150869e
--- /dev/null
+++ b/ports/esp32/modtime.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "py/obj.h"
+#include "shared/timeutils/timeutils.h"
+
+// Return the localtime as an 8-tuple.
+STATIC mp_obj_t mp_time_localtime_get(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_epoch_to_struct_time(tv.tv_sec, &tm);
+ mp_obj_t tuple[8] = {
+ tuple[0] = mp_obj_new_int(tm.tm_year),
+ tuple[1] = mp_obj_new_int(tm.tm_mon),
+ tuple[2] = mp_obj_new_int(tm.tm_mday),
+ tuple[3] = mp_obj_new_int(tm.tm_hour),
+ tuple[4] = mp_obj_new_int(tm.tm_min),
+ tuple[5] = mp_obj_new_int(tm.tm_sec),
+ tuple[6] = mp_obj_new_int(tm.tm_wday),
+ tuple[7] = mp_obj_new_int(tm.tm_yday),
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+
+// Return the number of seconds since the Epoch.
+STATIC mp_obj_t mp_time_time_get(void) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return mp_obj_new_int(tv.tv_sec);
+}
diff --git a/ports/esp32/modules/_boot.py b/ports/esp32/modules/_boot.py
index a7d9813090bf..651fc7b10cdd 100644
--- a/ports/esp32/modules/_boot.py
+++ b/ports/esp32/modules/_boot.py
@@ -1,10 +1,10 @@
import gc
-import uos
+import os
from flashbdev import bdev
try:
if bdev:
- uos.mount(bdev, "/")
+ os.mount(bdev, "/")
except OSError:
import inisetup
diff --git a/ports/esp32/modules/espnow.py b/ports/esp32/modules/espnow.py
new file mode 100644
index 000000000000..6956a3a93557
--- /dev/null
+++ b/ports/esp32/modules/espnow.py
@@ -0,0 +1,30 @@
+# espnow module for MicroPython on ESP32
+# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20
+
+from _espnow import *
+
+
+class ESPNow(ESPNowBase):
+ # Static buffers for alloc free receipt of messages with ESPNow.irecv().
+ _data = [None, bytearray(MAX_DATA_LEN)]
+ _none_tuple = (None, None)
+
+ def __init__(self):
+ super().__init__()
+
+ def irecv(self, timeout_ms=None):
+ n = self.recvinto(self._data, timeout_ms)
+ return self._data if n else self._none_tuple
+
+ def recv(self, timeout_ms=None):
+ n = self.recvinto(self._data, timeout_ms)
+ return [bytes(x) for x in self._data] if n else self._none_tuple
+
+ def irq(self, callback):
+ super().irq(callback, self)
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ return self.irecv() # Use alloc free irecv() method
diff --git a/ports/esp32/modules/inisetup.py b/ports/esp32/modules/inisetup.py
index 426a47a6b45e..2003864e9f3e 100644
--- a/ports/esp32/modules/inisetup.py
+++ b/ports/esp32/modules/inisetup.py
@@ -1,4 +1,4 @@
-import uos
+import os
from flashbdev import bdev
@@ -17,6 +17,10 @@ def check_bootsec():
def fs_corrupted():
import time
+ import micropython
+
+ # Allow this loop to be stopped via Ctrl-C.
+ micropython.kbd_intr(3)
while 1:
print(
@@ -33,9 +37,13 @@ def fs_corrupted():
def setup():
check_bootsec()
print("Performing initial setup")
- uos.VfsLfs2.mkfs(bdev)
- vfs = uos.VfsLfs2(bdev)
- uos.mount(vfs, "/")
+ if bdev.info()[4] == "vfs":
+ os.VfsLfs2.mkfs(bdev)
+ vfs = os.VfsLfs2(bdev)
+ elif bdev.info()[4] == "ffat":
+ os.VfsFat.mkfs(bdev)
+ vfs = os.VfsFat(bdev)
+ os.mount(vfs, "/")
with open("boot.py", "w") as f:
f.write(
"""\
diff --git a/ports/esp32/moduos.c b/ports/esp32/moduos.c
deleted file mode 100644
index bdfd19c5d20a..000000000000
--- a/ports/esp32/moduos.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * Development of the code in this file was sponsored by Microbric Pty Ltd
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Josef Gajdusek
- * Copyright (c) 2016 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "esp_system.h"
-
-#include "py/runtime.h"
-#include "py/mphal.h"
-#include "extmod/misc.h"
-
-STATIC mp_obj_t mp_uos_urandom(mp_obj_t num) {
- mp_int_t n = mp_obj_get_int(num);
- vstr_t vstr;
- vstr_init_len(&vstr, n);
- uint32_t r = 0;
- for (int i = 0; i < n; i++) {
- if ((i & 3) == 0) {
- r = esp_random(); // returns 32-bit hardware random number
- }
- vstr.buf[i] = r;
- r >>= 8;
- }
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_urandom_obj, mp_uos_urandom);
-
-#if MICROPY_PY_UOS_DUPTERM_NOTIFY
-STATIC mp_obj_t mp_uos_dupterm_notify(mp_obj_t obj_in) {
- (void)obj_in;
- for (;;) {
- int c = mp_uos_dupterm_rx_chr();
- if (c < 0) {
- break;
- }
- ringbuf_put(&stdin_ringbuf, c);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_dupterm_notify_obj, mp_uos_dupterm_notify);
-#endif
diff --git a/ports/esp32/modutime.c b/ports/esp32/modutime.c
deleted file mode 100644
index 631d0fe2997d..000000000000
--- a/ports/esp32/modutime.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * Development of the code in this file was sponsored by Microbric Pty Ltd
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/runtime.h"
-#include "shared/timeutils/timeutils.h"
-#include "extmod/utime_mphal.h"
-
-STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
- timeutils_struct_time_t tm;
- mp_int_t seconds;
- if (n_args == 0 || args[0] == mp_const_none) {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- seconds = tv.tv_sec;
- } else {
- seconds = mp_obj_get_int(args[0]);
- }
- timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
- mp_obj_t tuple[8] = {
- tuple[0] = mp_obj_new_int(tm.tm_year),
- tuple[1] = mp_obj_new_int(tm.tm_mon),
- tuple[2] = mp_obj_new_int(tm.tm_mday),
- tuple[3] = mp_obj_new_int(tm.tm_hour),
- tuple[4] = mp_obj_new_int(tm.tm_min),
- tuple[5] = mp_obj_new_int(tm.tm_sec),
- tuple[6] = mp_obj_new_int(tm.tm_wday),
- tuple[7] = mp_obj_new_int(tm.tm_yday),
- };
- return mp_obj_new_tuple(8, tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
-
-STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
- size_t len;
- mp_obj_t *elem;
- mp_obj_get_array(tuple, &len, &elem);
-
- // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
- if (len < 8 || len > 9) {
- mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9 (%d given)"), len);
- }
-
- return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
- mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
- mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
-
-STATIC mp_obj_t time_time(void) {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return mp_obj_new_int(tv.tv_sec);
-}
-MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
-
-STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
-
- { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
- { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
- { MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
-
-const mp_obj_module_t utime_module = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&time_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_utime, utime_module);
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index 957aa2e93bce..aa13eaf2fecf 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -6,9 +6,11 @@
#include
#include
+#include "esp_random.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "driver/i2s.h"
+#include "esp_wifi_types.h"
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
@@ -49,9 +51,6 @@
#define MICROPY_WARNINGS (1)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_STREAMS_POSIX_API (1)
-#define MICROPY_MODULE_FROZEN_STR (0)
-#define MICROPY_MODULE_FROZEN_MPY (1)
-#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
#define MICROPY_USE_INTERNAL_ERRNO (0) // errno.h from xtensa-esp32-elf/sys-include/sys
#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf
#define MICROPY_SCHEDULER_DEPTH (8)
@@ -62,12 +61,17 @@
#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_HELP_TEXT esp32_help_text
#define MICROPY_PY_IO_BUFFEREDWRITER (1)
-#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
+#define MICROPY_PY_TIME_TIME_TIME_NS (1)
+#define MICROPY_PY_TIME_INCLUDEFILE "ports/esp32/modtime.c"
#define MICROPY_PY_THREAD (1)
#define MICROPY_PY_THREAD_GIL (1)
#define MICROPY_PY_THREAD_GIL_VM_DIVISOR (32)
// extended modules
+#ifndef MICROPY_ESPNOW
+#define MICROPY_ESPNOW (1)
+#endif
#ifndef MICROPY_PY_BLUETOOTH
#define MICROPY_PY_BLUETOOTH (1)
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1)
@@ -78,24 +82,22 @@
#define MICROPY_BLUETOOTH_NIMBLE (1)
#define MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY (1)
#endif
-#define MICROPY_PY_UTIMEQ (1)
-#define MICROPY_PY_UHASHLIB_SHA1 (1)
-#define MICROPY_PY_UHASHLIB_SHA256 (1)
-#define MICROPY_PY_UCRYPTOLIB (1)
-#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (esp_random())
-#define MICROPY_PY_UOS_INCLUDEFILE "ports/esp32/moduos.c"
+#define MICROPY_PY_HASHLIB_SHA1 (1)
+#define MICROPY_PY_HASHLIB_SHA256 (1)
+#define MICROPY_PY_CRYPTOLIB (1)
+#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (esp_random())
+#define MICROPY_PY_OS_INCLUDEFILE "ports/esp32/modos.c"
#define MICROPY_PY_OS_DUPTERM (1)
-#define MICROPY_PY_UOS_DUPTERM_NOTIFY (1)
-#define MICROPY_PY_UOS_UNAME (1)
-#define MICROPY_PY_UOS_URANDOM (1)
+#define MICROPY_PY_OS_DUPTERM_NOTIFY (1)
+#define MICROPY_PY_OS_SYNC (1)
+#define MICROPY_PY_OS_UNAME (1)
+#define MICROPY_PY_OS_URANDOM (1)
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PWM (1)
-#define MICROPY_PY_MACHINE_PWM_INIT (1)
#define MICROPY_PY_MACHINE_PWM_DUTY (1)
-#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/esp32/machine_pwm.c"
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1 (1)
@@ -110,6 +112,20 @@
#ifndef MICROPY_PY_MACHINE_I2S
#define MICROPY_PY_MACHINE_I2S (1)
#endif
+#define MICROPY_PY_NETWORK (1)
+#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT
+#if CONFIG_IDF_TARGET_ESP32
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32"
+#elif CONFIG_IDF_TARGET_ESP32S2
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32s2"
+#elif CONFIG_IDF_TARGET_ESP32S3
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32s3"
+#elif CONFIG_IDF_TARGET_ESP32C3
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp32c3"
+#endif
+#endif
+#define MICROPY_PY_NETWORK_INCLUDEFILE "ports/esp32/modnetwork.h"
+#define MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE "ports/esp32/modnetwork_globals.h"
#ifndef MICROPY_PY_NETWORK_WLAN
#define MICROPY_PY_NETWORK_WLAN (1)
#endif
@@ -117,16 +133,14 @@
#define MICROPY_HW_ENABLE_SDCARD (1)
#endif
#define MICROPY_HW_SOFTSPI_MIN_DELAY (0)
-#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly
-#define MICROPY_PY_USSL (1)
+#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (esp_rom_get_cpu_ticks_per_us() * 1000000 / 200) // roughly
+#define MICROPY_PY_SSL (1)
#define MICROPY_SSL_MBEDTLS (1)
-#define MICROPY_PY_USSL_FINALISER (1)
-#define MICROPY_PY_UWEBSOCKET (1)
+#define MICROPY_PY_SSL_FINALISER (1)
+#define MICROPY_PY_WEBSOCKET (1)
#define MICROPY_PY_WEBREPL (1)
-#define MICROPY_PY_BTREE (1)
#define MICROPY_PY_ONEWIRE (1)
-#define MICROPY_PY_UPLATFORM (1)
-#define MICROPY_PY_USOCKET_EVENTS (MICROPY_PY_WEBREPL)
+#define MICROPY_PY_SOCKET_EVENTS (MICROPY_PY_WEBREPL)
#define MICROPY_PY_BLUETOOTH_RANDOM_ADDR (1)
#define MICROPY_PY_BLUETOOTH_DEFAULT_GAP_NAME ("ESP32")
@@ -149,13 +163,13 @@ void *esp_native_code_commit(void *, size_t, void *);
// the only disable interrupts on the current CPU. To full manage exclusion
// one should use portENTER_CRITICAL/portEXIT_CRITICAL instead.
#include "freertos/FreeRTOS.h"
-#define MICROPY_BEGIN_ATOMIC_SECTION() portENTER_CRITICAL_NESTED()
-#define MICROPY_END_ATOMIC_SECTION(state) portEXIT_CRITICAL_NESTED(state)
+#define MICROPY_BEGIN_ATOMIC_SECTION() portSET_INTERRUPT_MASK_FROM_ISR()
+#define MICROPY_END_ATOMIC_SECTION(state) portCLEAR_INTERRUPT_MASK_FROM_ISR(state)
-#if MICROPY_PY_USOCKET_EVENTS
-#define MICROPY_PY_USOCKET_EVENTS_HANDLER extern void usocket_events_handler(void); usocket_events_handler();
+#if MICROPY_PY_SOCKET_EVENTS
+#define MICROPY_PY_SOCKET_EVENTS_HANDLER extern void socket_events_handler(void); socket_events_handler();
#else
-#define MICROPY_PY_USOCKET_EVENTS_HANDLER
+#define MICROPY_PY_SOCKET_EVENTS_HANDLER
#endif
#if MICROPY_PY_THREAD
@@ -163,7 +177,7 @@ void *esp_native_code_commit(void *, size_t, void *);
do { \
extern void mp_handle_pending(bool); \
mp_handle_pending(true); \
- MICROPY_PY_USOCKET_EVENTS_HANDLER \
+ MICROPY_PY_SOCKET_EVENTS_HANDLER \
MP_THREAD_GIL_EXIT(); \
ulTaskNotifyTake(pdFALSE, 1); \
MP_THREAD_GIL_ENTER(); \
@@ -173,7 +187,7 @@ void *esp_native_code_commit(void *, size_t, void *);
do { \
extern void mp_handle_pending(bool); \
mp_handle_pending(true); \
- MICROPY_PY_USOCKET_EVENTS_HANDLER \
+ MICROPY_PY_SOCKET_EVENTS_HANDLER \
asm ("waiti 0"); \
} while (0);
#endif
@@ -213,8 +227,30 @@ typedef long mp_off_t;
#define MICROPY_HW_ENABLE_MDNS_RESPONDER (1)
#endif
+#ifndef MICROPY_BOARD_ENTER_BOOTLOADER
+#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args)
+#endif
+
#ifndef MICROPY_BOARD_STARTUP
#define MICROPY_BOARD_STARTUP boardctrl_startup
#endif
void boardctrl_startup(void);
+
+#ifndef MICROPY_PY_NETWORK_LAN
+#if CONFIG_IDF_TARGET_ESP32 || (CONFIG_ETH_USE_SPI_ETHERNET && (CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL || CONFIG_ETH_SPI_ETHERNET_DM9051 || CONFIG_ETH_SPI_ETHERNET_W5500))
+#define MICROPY_PY_NETWORK_LAN (1)
+#else
+#define MICROPY_PY_NETWORK_LAN (0)
+#endif
+#endif
+
+#if MICROPY_PY_NETWORK_LAN && CONFIG_ETH_USE_SPI_ETHERNET
+#ifndef MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ
+#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2
+#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (12)
+#else
+#define MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ (36)
+#endif
+#endif
+#endif
diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c
index 2aaeb9755f97..63a674c24b62 100644
--- a/ports/esp32/mphalport.c
+++ b/ports/esp32/mphalport.c
@@ -32,6 +32,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
+#include "esp_timer.h"
#include "py/obj.h"
#include "py/objstr.h"
@@ -88,6 +89,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) {
ret |= MP_STREAM_POLL_RD;
}
+ if (poll_flags & MP_STREAM_POLL_WR) {
+ ret |= MP_STREAM_POLL_WR;
+ }
return ret;
}
@@ -107,7 +111,7 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (release_gil) {
MP_THREAD_GIL_EXIT();
}
- #if CONFIG_USB_ENABLED
+ #if CONFIG_USB_OTG_SUPPORTED
usb_tx_strn(str, len);
#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
usb_serial_jtag_tx_strn(str, len);
@@ -118,7 +122,7 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
if (release_gil) {
MP_THREAD_GIL_ENTER();
}
- mp_uos_dupterm_tx_strn(str, len);
+ mp_os_dupterm_tx_strn(str, len);
}
uint32_t mp_hal_ticks_ms(void) {
@@ -135,7 +139,7 @@ void mp_hal_delay_ms(uint32_t ms) {
uint64_t t0 = esp_timer_get_time();
for (;;) {
mp_handle_pending(true);
- MICROPY_PY_USOCKET_EVENTS_HANDLER
+ MICROPY_PY_SOCKET_EVENTS_HANDLER
MP_THREAD_GIL_EXIT();
uint64_t t1 = esp_timer_get_time();
dt = t1 - t0;
diff --git a/ports/esp32/mphalport.h b/ports/esp32/mphalport.h
index c838bd228420..566d6609f110 100644
--- a/ports/esp32/mphalport.h
+++ b/ports/esp32/mphalport.h
@@ -35,6 +35,8 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
+#include "driver/spi_master.h"
+
#define MICROPY_PLATFORM_VERSION "IDF" IDF_VER
// The core that the MicroPython task(s) are pinned to.
@@ -42,10 +44,10 @@
// and avoid the Wifi/BLE timing problems on the same core.
// Best effort here to remain backwards compatible in rare version edge cases...
// See https://github.com/micropython/micropython/issues/5489 for history
-#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
-#define MP_TASK_COREID (1)
-#else
+#if CONFIG_FREERTOS_UNICORE
#define MP_TASK_COREID (0)
+#else
+#define MP_TASK_COREID (1)
#endif
extern TaskHandle_t mp_main_task_handle;
@@ -67,7 +69,7 @@ __attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
}
void mp_hal_delay_us(uint32_t);
-#define mp_hal_delay_us_fast(us) ets_delay_us(us)
+#define mp_hal_delay_us_fast(us) esp_rom_delay_us(us)
void mp_hal_set_interrupt_char(int c);
uint32_t mp_hal_get_cpu_freq(void);
@@ -84,18 +86,17 @@ void mp_hal_wake_main_task_from_isr(void);
#define mp_hal_pin_obj_t gpio_num_t
mp_hal_pin_obj_t machine_pin_get_id(mp_obj_t pin_in);
#define mp_hal_get_pin_obj(o) machine_pin_get_id(o)
-#define mp_obj_get_pin(o) machine_pin_get_id(o) // legacy name; only to support esp8266/modonewire
#define mp_hal_pin_name(p) (p)
static inline void mp_hal_pin_input(mp_hal_pin_obj_t pin) {
- gpio_pad_select_gpio(pin);
+ esp_rom_gpio_pad_select_gpio(pin);
gpio_set_direction(pin, GPIO_MODE_INPUT);
}
static inline void mp_hal_pin_output(mp_hal_pin_obj_t pin) {
- gpio_pad_select_gpio(pin);
+ esp_rom_gpio_pad_select_gpio(pin);
gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT);
}
static inline void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin) {
- gpio_pad_select_gpio(pin);
+ esp_rom_gpio_pad_select_gpio(pin);
gpio_set_direction(pin, GPIO_MODE_INPUT_OUTPUT_OD);
}
static inline void mp_hal_pin_od_low(mp_hal_pin_obj_t pin) {
@@ -111,4 +112,6 @@ static inline void mp_hal_pin_write(mp_hal_pin_obj_t pin, int v) {
gpio_set_level(pin, v);
}
+spi_host_device_t machine_hw_spi_get_host(mp_obj_t in);
+
#endif // INCLUDED_MPHALPORT_H
diff --git a/ports/esp32/mpnimbleport.c b/ports/esp32/mpnimbleport.c
index a58fcbdbf49f..8235275be6fd 100644
--- a/ports/esp32/mpnimbleport.c
+++ b/ports/esp32/mpnimbleport.c
@@ -46,13 +46,13 @@ STATIC void ble_host_task(void *param) {
void mp_bluetooth_nimble_port_hci_init(void) {
DEBUG_printf("mp_bluetooth_nimble_port_hci_init\n");
- esp_nimble_hci_and_controller_init();
+ esp_nimble_hci_init();
}
void mp_bluetooth_nimble_port_hci_deinit(void) {
DEBUG_printf("mp_bluetooth_nimble_port_hci_deinit\n");
- esp_nimble_hci_and_controller_deinit();
+ esp_nimble_hci_deinit();
}
void mp_bluetooth_nimble_port_start(void) {
diff --git a/ports/esp32/network_common.c b/ports/esp32/network_common.c
new file mode 100644
index 000000000000..082943e2aecc
--- /dev/null
+++ b/ports/esp32/network_common.c
@@ -0,0 +1,161 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Development of the code in this file was sponsored by Microbric Pty Ltd
+ * and Mnemote Pty Ltd
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016, 2017 Nick Moore @mnemote
+ * Copyright (c) 2017 "Eric Poulsen"
+ *
+ * Based on esp8266/modnetwork.c which is Copyright (c) 2015 Paul Sokolovsky
+ * And the ESP IDF example code which is Public Domain / CC0
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "shared/netutils/netutils.h"
+#include "modnetwork.h"
+
+#include "esp_log.h"
+#include "esp_netif.h"
+#include "esp_wifi.h"
+// #include "lwip/dns.h"
+
+NORETURN void esp_exceptions_helper(esp_err_t e) {
+ switch (e) {
+ case ESP_ERR_WIFI_NOT_INIT:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Initialized"));
+ case ESP_ERR_WIFI_NOT_STARTED:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Started"));
+ case ESP_ERR_WIFI_NOT_STOPPED:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Stopped"));
+ case ESP_ERR_WIFI_IF:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Interface"));
+ case ESP_ERR_WIFI_MODE:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Mode"));
+ case ESP_ERR_WIFI_STATE:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal State Error"));
+ case ESP_ERR_WIFI_CONN:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal Error"));
+ case ESP_ERR_WIFI_NVS:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Internal NVS Error"));
+ case ESP_ERR_WIFI_MAC:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid MAC Address"));
+ case ESP_ERR_WIFI_SSID:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi SSID Invalid"));
+ case ESP_ERR_WIFI_PASSWORD:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Password"));
+ case ESP_ERR_WIFI_TIMEOUT:
+ mp_raise_OSError(MP_ETIMEDOUT);
+ case ESP_ERR_WIFI_WAKE_FAIL:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Wakeup Failure"));
+ case ESP_ERR_WIFI_WOULD_BLOCK:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Would Block"));
+ case ESP_ERR_WIFI_NOT_CONNECT:
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Connected"));
+ default:
+ mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("Wifi Unknown Error 0x%04x"), e);
+ }
+}
+
+STATIC mp_obj_t esp_initialize() {
+ static int initialized = 0;
+ if (!initialized) {
+ esp_exceptions(esp_netif_init());
+ initialized = 1;
+ }
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(esp_network_initialize_obj, esp_initialize);
+
+STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
+ base_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ esp_netif_ip_info_t info;
+ esp_netif_dns_info_t dns_info;
+ esp_netif_get_ip_info(self->netif, &info);
+ esp_netif_get_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &dns_info);
+ if (n_args == 1) {
+ // get
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr((uint8_t *)&info.ip, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&info.netmask, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&info.gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&dns_info.ip, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else {
+ // set
+ if (mp_obj_is_type(args[1], &mp_type_tuple) || mp_obj_is_type(args[1], &mp_type_list)) {
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(args[1], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (void *)&info.ip, NETUTILS_BIG);
+ if (mp_obj_is_integer(items[1])) {
+ // allow numeric netmask, i.e.:
+ // 24 -> 255.255.255.0
+ // 16 -> 255.255.0.0
+ // etc...
+ uint32_t *m = (uint32_t *)&info.netmask;
+ *m = esp_netif_htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
+ } else {
+ netutils_parse_ipv4_addr(items[1], (void *)&info.netmask, NETUTILS_BIG);
+ }
+ netutils_parse_ipv4_addr(items[2], (void *)&info.gw, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[3], (void *)&dns_info.ip, NETUTILS_BIG);
+ // To set a static IP we have to disable DHCP first
+ if (self->if_id == ESP_IF_WIFI_STA || self->if_id == ESP_IF_ETH) {
+ esp_err_t e = esp_netif_dhcpc_stop(self->netif);
+ if (e != ESP_OK && e != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
+ esp_exceptions_helper(e);
+ }
+ esp_exceptions(esp_netif_set_ip_info(self->netif, &info));
+ esp_exceptions(esp_netif_set_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &dns_info));
+ } else if (self->if_id == ESP_IF_WIFI_AP) {
+ esp_err_t e = esp_netif_dhcps_stop(self->netif);
+ if (e != ESP_OK && e != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
+ esp_exceptions_helper(e);
+ }
+ esp_exceptions(esp_netif_set_ip_info(self->netif, &info));
+ esp_exceptions(esp_netif_set_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &dns_info));
+ esp_exceptions(esp_netif_dhcps_start(self->netif));
+ }
+ } else {
+ // check for the correct string
+ const char *mode = mp_obj_str_get_str(args[1]);
+ if ((self->if_id != ESP_IF_WIFI_STA && self->if_id != ESP_IF_ETH) || strcmp("dhcp", mode)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
+ }
+ esp_exceptions(esp_netif_dhcpc_start(self->netif));
+ }
+ return mp_const_none;
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_ifconfig_obj, 1, 2, esp_ifconfig);
+
+STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_phy_mode_obj, 0, 1, esp_phy_mode);
+
+_Static_assert(WIFI_AUTH_MAX == 10, "Synchronize WIFI_AUTH_XXX constants with the ESP-IDF. Look at esp-idf/components/esp_wifi/include/esp_wifi_types.h");
diff --git a/ports/esp32/network_lan.c b/ports/esp32/network_lan.c
index c57d7815d7ca..fe3ff6f772a8 100644
--- a/ports/esp32/network_lan.c
+++ b/ports/esp32/network_lan.c
@@ -32,34 +32,35 @@
#include "esp_idf_version.h"
-// LAN only for ESP32 (not ESP32S2) and only for ESP-IDF v4.1 and higher
-#if (ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 1) && (CONFIG_IDF_TARGET_ESP32)
+#if MICROPY_PY_NETWORK_LAN
#include "esp_eth.h"
#include "esp_eth_mac.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
+#if CONFIG_ETH_USE_SPI_ETHERNET
+#include "driver/spi_master.h"
+#endif
#include "modnetwork.h"
typedef struct _lan_if_obj_t {
- mp_obj_base_t base;
- int if_id; // MUST BE FIRST to match wlan_if_obj_t
+ base_if_obj_t base;
bool initialized;
- bool active;
- uint8_t mdc_pin;
- uint8_t mdio_pin;
+ int8_t mdc_pin;
+ int8_t mdio_pin;
int8_t phy_power_pin;
+ int8_t phy_cs_pin;
+ int8_t phy_int_pin;
uint8_t phy_addr;
uint8_t phy_type;
esp_eth_phy_t *phy;
- esp_netif_t *eth_netif;
esp_eth_handle_t eth_handle;
} lan_if_obj_t;
const mp_obj_type_t lan_if_type;
-STATIC lan_if_obj_t lan_obj = {{&lan_if_type}, ESP_IF_ETH, false, false};
+STATIC lan_if_obj_t lan_obj = {{{&lan_if_type}, ESP_IF_ETH, NULL}, false, false};
STATIC uint8_t eth_status = 0;
static void eth_event_handler(void *arg, esp_event_base_t event_base,
@@ -97,14 +98,20 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
return MP_OBJ_FROM_PTR(&lan_obj);
}
- enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type };
+ enum { ARG_id, ARG_mdc, ARG_mdio, ARG_power, ARG_phy_addr, ARG_phy_type,
+ ARG_spi, ARG_cs, ARG_int, ARG_ref_clk_mode, ARG_ref_clk };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
- { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_mdc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_mdio, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_power, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_int, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_ref_clk, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@@ -116,38 +123,101 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
}
}
- self->mdc_pin = machine_pin_get_id(args[ARG_mdc].u_obj);
- self->mdio_pin = machine_pin_get_id(args[ARG_mdio].u_obj);
- self->phy_power_pin = args[ARG_power].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[ARG_power].u_obj);
+ #define GET_PIN(XXX) args[XXX].u_obj == mp_const_none ? -1 : machine_pin_get_id(args[XXX].u_obj);
+
+ self->mdc_pin = GET_PIN(ARG_mdc);
+ self->mdio_pin = GET_PIN(ARG_mdio);
+ self->phy_power_pin = GET_PIN(ARG_power);
+ self->phy_cs_pin = GET_PIN(ARG_cs);
+ self->phy_int_pin = GET_PIN(ARG_int);
if (args[ARG_phy_addr].u_int < 0x00 || args[ARG_phy_addr].u_int > 0x1f) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy address"));
}
self->phy_addr = args[ARG_phy_addr].u_int;
- if (args[ARG_phy_type].u_int != PHY_LAN8720 &&
+ if (args[ARG_phy_type].u_int != PHY_LAN8710 &&
+ args[ARG_phy_type].u_int != PHY_LAN8720 &&
args[ARG_phy_type].u_int != PHY_IP101 &&
args[ARG_phy_type].u_int != PHY_RTL8201 &&
- #if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
args[ARG_phy_type].u_int != PHY_KSZ8041 &&
+ args[ARG_phy_type].u_int != PHY_KSZ8081 &&
+ #if CONFIG_ETH_USE_SPI_ETHERNET
+ #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
+ args[ARG_phy_type].u_int != PHY_KSZ8851SNL &&
+ #endif
+ #if CONFIG_ETH_SPI_ETHERNET_DM9051
+ args[ARG_phy_type].u_int != PHY_DM9051 &&
+ #endif
+ #if CONFIG_ETH_SPI_ETHERNET_W5500
+ args[ARG_phy_type].u_int != PHY_W5500 &&
+ #endif
#endif
args[ARG_phy_type].u_int != PHY_DP83848) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy type"));
}
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
- mac_config.smi_mdc_gpio_num = self->mdc_pin;
- mac_config.smi_mdio_gpio_num = self->mdio_pin;
- esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
+ #if CONFIG_IDF_TARGET_ESP32
+ eth_esp32_emac_config_t esp32_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
+ #endif
+
+ esp_eth_mac_t *mac = NULL;
+
+ #if CONFIG_IDF_TARGET_ESP32
+ // Dynamic ref_clk configuration.
+ if (args[ARG_ref_clk_mode].u_int != -1) {
+ // Map the GPIO_MODE constants to EMAC_CLK constants.
+ esp32_config.clock_config.rmii.clock_mode =
+ args[ARG_ref_clk_mode].u_int == GPIO_MODE_INPUT ? EMAC_CLK_EXT_IN : EMAC_CLK_OUT;
+ }
+ if (args[ARG_ref_clk].u_obj != mp_const_none) {
+ esp32_config.clock_config.rmii.clock_gpio = machine_pin_get_id(args[ARG_ref_clk].u_obj);
+ }
+ #endif
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = self->phy_addr;
phy_config.reset_gpio_num = self->phy_power_pin;
self->phy = NULL;
+ #if CONFIG_ETH_USE_SPI_ETHERNET
+ spi_device_handle_t spi_handle = NULL;
+ if (IS_SPI_PHY(args[ARG_phy_type].u_int)) {
+ spi_device_interface_config_t devcfg = {
+ .mode = 0,
+ .clock_speed_hz = MICROPY_PY_NETWORK_LAN_SPI_CLOCK_SPEED_MZ * 1000 * 1000,
+ .queue_size = 20,
+ .spics_io_num = self->phy_cs_pin,
+ };
+ switch (args[ARG_phy_type].u_int) {
+ #if CONFIG_ETH_SPI_ETHERNET_DM9051
+ case PHY_DM9051: {
+ devcfg.command_bits = 1;
+ devcfg.address_bits = 7;
+ break;
+ }
+ #endif
+ #if CONFIG_ETH_SPI_ETHERNET_W5500
+ case PHY_W5500: {
+ devcfg.command_bits = 16;
+ devcfg.address_bits = 8;
+ break;
+ }
+ #endif
+ }
+ spi_host_device_t host = machine_hw_spi_get_host(args[ARG_spi].u_obj);
+ if (spi_bus_add_device(host, &devcfg, &spi_handle) != ESP_OK) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("spi_bus_add_device failed"));
+ }
+ }
+ #endif
+
switch (args[ARG_phy_type].u_int) {
+ #if CONFIG_IDF_TARGET_ESP32
+ case PHY_LAN8710:
case PHY_LAN8720:
- self->phy = esp_eth_phy_new_lan8720(&phy_config);
+ self->phy = esp_eth_phy_new_lan87xx(&phy_config);
break;
case PHY_IP101:
self->phy = esp_eth_phy_new_ip101(&phy_config);
@@ -159,24 +229,58 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
self->phy = esp_eth_phy_new_dp83848(&phy_config);
break;
case PHY_KSZ8041:
- #if ESP_IDF_VERSION_MINOR >= 3 // KSZ8041 is new in ESP-IDF v4.3
- self->phy = esp_eth_phy_new_ksz8041(&phy_config);
+ case PHY_KSZ8081:
+ self->phy = esp_eth_phy_new_ksz80xx(&phy_config);
break;
- #endif
- default:
- mp_raise_ValueError(MP_ERROR_TEXT("unknown phy"));
+ #endif
+ #if CONFIG_ETH_USE_SPI_ETHERNET
+ #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
+ case PHY_KSZ8851SNL: {
+ eth_ksz8851snl_config_t chip_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle);
+ chip_config.int_gpio_num = self->phy_int_pin;
+ mac = esp_eth_mac_new_ksz8851snl(&chip_config, &mac_config);
+ self->phy = esp_eth_phy_new_ksz8851snl(&phy_config);
+ break;
+ }
+ #endif
+ #if CONFIG_ETH_SPI_ETHERNET_DM9051
+ case PHY_DM9051: {
+ eth_dm9051_config_t chip_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
+ chip_config.int_gpio_num = self->phy_int_pin;
+ mac = esp_eth_mac_new_dm9051(&chip_config, &mac_config);
+ self->phy = esp_eth_phy_new_dm9051(&phy_config);
+ break;
+ }
+ #endif
+ #if CONFIG_ETH_SPI_ETHERNET_W5500
+ case PHY_W5500: {
+ eth_w5500_config_t chip_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
+ chip_config.int_gpio_num = self->phy_int_pin;
+ mac = esp_eth_mac_new_w5500(&chip_config, &mac_config);
+ self->phy = esp_eth_phy_new_w5500(&phy_config);
+ break;
+ }
+ #endif
+ #endif
+ }
+
+ #if CONFIG_IDF_TARGET_ESP32
+ if (!IS_SPI_PHY(args[ARG_phy_type].u_int)) {
+ if (self->mdc_pin == -1 || self->mdio_pin == -1) {
+ mp_raise_ValueError(MP_ERROR_TEXT("mdc and mdio must be specified"));
+ }
+ esp32_config.smi_mdc_gpio_num = self->mdc_pin;
+ esp32_config.smi_mdio_gpio_num = self->mdio_pin;
+ mac = esp_eth_mac_new_esp32(&esp32_config, &mac_config);
}
+ #endif
if (esp_netif_init() != ESP_OK) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_init failed"));
}
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
- self->eth_netif = esp_netif_new(&cfg);
-
- if (esp_eth_set_default_handlers(self->eth_netif) != ESP_OK) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_eth_set_default_handlers failed (invalid parameter)"));
- }
+ self->base.netif = esp_netif_new(&cfg);
if (esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_event_handler_register failed"));
@@ -190,7 +294,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
esp_err_t esp_err = esp_eth_driver_install(&config, &self->eth_handle);
if (esp_err == ESP_OK) {
- self->active = false;
+ self->base.active = false;
self->initialized = true;
} else {
if (esp_err == ESP_ERR_INVALID_ARG) {
@@ -202,7 +306,7 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
}
}
- if (esp_netif_attach(self->eth_netif, esp_eth_new_netif_glue(self->eth_handle)) != ESP_OK) {
+ if (esp_netif_attach(self->base.netif, esp_eth_new_netif_glue(self->eth_handle)) != ESP_OK) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("esp_netif_attach failed"));
}
@@ -210,26 +314,26 @@ STATIC mp_obj_t get_lan(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
return MP_OBJ_FROM_PTR(&lan_obj);
}
-MP_DEFINE_CONST_FUN_OBJ_KW(get_lan_obj, 0, get_lan);
+MP_DEFINE_CONST_FUN_OBJ_KW(esp_network_get_lan_obj, 0, get_lan);
STATIC mp_obj_t lan_active(size_t n_args, const mp_obj_t *args) {
lan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args > 1) {
if (mp_obj_is_true(args[1])) {
- self->active = (esp_eth_start(self->eth_handle) == ESP_OK);
- if (!self->active) {
+ self->base.active = (esp_eth_start(self->eth_handle) == ESP_OK);
+ if (!self->base.active) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("ethernet enable failed"));
}
} else {
- self->active = !(esp_eth_stop(self->eth_handle) == ESP_OK);
- if (self->active) {
+ self->base.active = !(esp_eth_stop(self->eth_handle) == ESP_OK);
+ if (self->base.active) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("ethernet disable failed"));
}
}
}
- return mp_obj_new_bool(self->active);
+ return mp_obj_new_bool(self->base.active);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lan_active_obj, 1, 2, lan_active);
@@ -240,7 +344,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_status_obj, lan_status);
STATIC mp_obj_t lan_isconnected(mp_obj_t self_in) {
lan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
- return self->active ? mp_obj_new_bool(self->phy->get_link(self->phy) == ETH_LINK_UP) : mp_const_false;
+ return self->base.active ? mp_obj_new_bool(self->phy->get_link(self->phy) == ETH_LINK_UP) : mp_const_false;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lan_isconnected_obj, lan_isconnected);
@@ -261,7 +365,12 @@ STATIC mp_obj_t lan_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs
if (bufinfo.len != 6) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
}
- esp_eth_ioctl(self->eth_handle, ETH_CMD_S_MAC_ADDR, bufinfo.buf);
+ if (
+ (esp_eth_ioctl(self->eth_handle, ETH_CMD_S_MAC_ADDR, bufinfo.buf) != ESP_OK) ||
+ (esp_netif_set_mac(self->base.netif, bufinfo.buf) != ESP_OK)
+ ) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed setting MAC address"));
+ }
break;
}
default:
@@ -297,7 +406,7 @@ STATIC const mp_rom_map_elem_t lan_if_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&lan_isconnected_obj) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lan_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&lan_config_obj) },
- { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_network_ifconfig_obj) },
};
STATIC MP_DEFINE_CONST_DICT(lan_if_locals_dict, lan_if_locals_dict_table);
diff --git a/ports/esp32/network_ppp.c b/ports/esp32/network_ppp.c
index 703cdc7889fd..caad7eb48bfe 100644
--- a/ports/esp32/network_ppp.c
+++ b/ports/esp32/network_ppp.c
@@ -32,6 +32,7 @@
#include "py/stream.h"
#include "shared/netutils/netutils.h"
#include "modmachine.h"
+#include "ppp_set_auth.h"
#include "netif/ppp/ppp.h"
#include "netif/ppp/pppos.h"
@@ -91,7 +92,7 @@ STATIC mp_obj_t ppp_make_new(mp_obj_t stream) {
return MP_OBJ_FROM_PTR(self);
}
-MP_DEFINE_CONST_FUN_OBJ_1(ppp_make_new_obj, ppp_make_new);
+MP_DEFINE_CONST_FUN_OBJ_1(esp_network_ppp_make_new_obj, ppp_make_new);
static u32_t ppp_output_callback(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) {
ppp_if_obj_t *self = ctx;
diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c
index f0b458e6ddfe..8287731c31b8 100644
--- a/ports/esp32/network_wlan.c
+++ b/ports/esp32/network_wlan.c
@@ -35,11 +35,16 @@
#include "py/objlist.h"
#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/modnetwork.h"
#include "modnetwork.h"
#include "esp_wifi.h"
#include "esp_log.h"
+
+#ifndef NO_QSTR
#include "mdns.h"
+#endif
#if MICROPY_PY_NETWORK_WLAN
@@ -47,8 +52,10 @@
#error WIFI_MODE_STA and WIFI_MODE_AP are supposed to be bitfields!
#endif
-STATIC const wlan_if_obj_t wlan_sta_obj;
-STATIC const wlan_if_obj_t wlan_ap_obj;
+typedef base_if_obj_t wlan_if_obj_t;
+
+STATIC wlan_if_obj_t wlan_sta_obj;
+STATIC wlan_if_obj_t wlan_ap_obj;
// Set to "true" if esp_wifi_start() was called
static bool wifi_started = false;
@@ -73,38 +80,27 @@ static uint8_t wifi_sta_reconnects;
// This function is called by the system-event task and so runs in a different
// thread to the main MicroPython task. It must not raise any Python exceptions.
-void network_wlan_event_handler(system_event_t *event) {
- switch (event->event_id) {
- case SYSTEM_EVENT_STA_START:
+static void network_wlan_wifi_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
+ switch (event_id) {
+ case WIFI_EVENT_STA_START:
ESP_LOGI("wifi", "STA_START");
+ wlan_sta_obj.active = true;
wifi_sta_reconnects = 0;
break;
- case SYSTEM_EVENT_STA_CONNECTED:
- ESP_LOGI("network", "CONNECTED");
+
+ case WIFI_EVENT_STA_STOP:
+ wlan_sta_obj.active = false;
break;
- case SYSTEM_EVENT_STA_GOT_IP:
- ESP_LOGI("network", "GOT_IP");
- wifi_sta_connected = true;
- wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
- #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
- if (!mdns_initialised) {
- mdns_init();
- #if MICROPY_HW_ENABLE_MDNS_RESPONDER
- const char *hostname = NULL;
- if (tcpip_adapter_get_hostname(WIFI_IF_STA, &hostname) != ESP_OK || hostname == NULL) {
- hostname = "esp32";
- }
- mdns_hostname_set(hostname);
- mdns_instance_name_set(hostname);
- #endif
- mdns_initialised = true;
- }
- #endif
+
+ case WIFI_EVENT_STA_CONNECTED:
+ ESP_LOGI("network", "CONNECTED");
break;
- case SYSTEM_EVENT_STA_DISCONNECTED: {
+
+ case WIFI_EVENT_STA_DISCONNECTED: {
// This is a workaround as ESP32 WiFi libs don't currently
// auto-reassociate.
- system_event_sta_disconnected_t *disconn = &event->event_info.disconnected;
+
+ wifi_event_sta_disconnected_t *disconn = event_data;
char *message = "";
wifi_sta_disconn_reason = disconn->reason;
switch (disconn->reason) {
@@ -149,6 +145,38 @@ void network_wlan_event_handler(system_event_t *event) {
}
break;
}
+
+ case WIFI_EVENT_AP_START:
+ wlan_ap_obj.active = true;
+ break;
+
+ case WIFI_EVENT_AP_STOP:
+ wlan_ap_obj.active = false;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void network_wlan_ip_event_handler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
+ switch (event_id) {
+ case IP_EVENT_STA_GOT_IP:
+ ESP_LOGI("network", "GOT_IP");
+ wifi_sta_connected = true;
+ wifi_sta_disconn_reason = 0; // Success so clear error. (in case of new error will be replaced anyway)
+ #if MICROPY_HW_ENABLE_MDNS_QUERIES || MICROPY_HW_ENABLE_MDNS_RESPONDER
+ if (!mdns_initialised) {
+ mdns_init();
+ #if MICROPY_HW_ENABLE_MDNS_RESPONDER
+ mdns_hostname_set(mod_network_hostname);
+ mdns_instance_name_set(mod_network_hostname);
+ #endif
+ mdns_initialised = true;
+ }
+ #endif
+ break;
+
default:
break;
}
@@ -157,31 +185,50 @@ void network_wlan_event_handler(system_event_t *event) {
STATIC void require_if(mp_obj_t wlan_if, int if_no) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
if (self->if_id != if_no) {
- mp_raise_msg(&mp_type_OSError, if_no == WIFI_IF_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required"));
+ mp_raise_msg(&mp_type_OSError, if_no == ESP_IF_WIFI_STA ? MP_ERROR_TEXT("STA required") : MP_ERROR_TEXT("AP required"));
}
}
-STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
- static int initialized = 0;
- if (!initialized) {
+void esp_initialise_wifi(void) {
+ static int wifi_initialized = 0;
+ if (!wifi_initialized) {
+ esp_exceptions(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, network_wlan_wifi_event_handler, NULL, NULL));
+ esp_exceptions(esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, network_wlan_ip_event_handler, NULL, NULL));
+
+ wlan_sta_obj.base.type = &esp_network_wlan_type;
+ wlan_sta_obj.if_id = ESP_IF_WIFI_STA;
+ wlan_sta_obj.netif = esp_netif_create_default_wifi_sta();
+ wlan_sta_obj.active = false;
+
+ wlan_ap_obj.base.type = &esp_network_wlan_type;
+ wlan_ap_obj.if_id = ESP_IF_WIFI_AP;
+ wlan_ap_obj.netif = esp_netif_create_default_wifi_ap();
+ wlan_ap_obj.active = false;
+
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_LOGD("modnetwork", "Initializing WiFi");
esp_exceptions(esp_wifi_init(&cfg));
esp_exceptions(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+
ESP_LOGD("modnetwork", "Initialized");
- initialized = 1;
+ wifi_initialized = 1;
}
+}
+
+STATIC mp_obj_t network_wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+ esp_initialise_wifi();
- int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : WIFI_IF_STA;
- if (idx == WIFI_IF_STA) {
+ int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : ESP_IF_WIFI_STA;
+ if (idx == ESP_IF_WIFI_STA) {
return MP_OBJ_FROM_PTR(&wlan_sta_obj);
- } else if (idx == WIFI_IF_AP) {
+ } else if (idx == ESP_IF_WIFI_AP) {
return MP_OBJ_FROM_PTR(&wlan_ap_obj);
} else {
mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier"));
}
}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
@@ -193,7 +240,7 @@ STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) {
esp_exceptions(esp_wifi_get_mode(&mode));
}
- int bit = (self->if_id == WIFI_IF_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
+ int bit = (self->if_id == ESP_IF_WIFI_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
if (n_args > 1) {
bool active = mp_obj_is_true(args[1]);
@@ -210,6 +257,11 @@ STATIC mp_obj_t network_wlan_active(size_t n_args, const mp_obj_t *args) {
wifi_started = true;
}
}
+
+ // Wait for the interface to be in the correct state.
+ while (self->active != active) {
+ MICROPY_EVENT_POLL_HOOK;
+ }
}
return (mode & bit) ? mp_const_true : mp_const_false;
@@ -253,6 +305,8 @@ STATIC mp_obj_t network_wlan_connect(size_t n_args, const mp_obj_t *pos_args, mp
esp_exceptions(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_sta_config));
}
+ esp_exceptions(esp_netif_set_hostname(wlan_sta_obj.netif, mod_network_hostname));
+
wifi_sta_reconnects = 0;
// connect to the WiFi AP
MP_THREAD_GIL_EXIT();
@@ -274,7 +328,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_disconnect_obj, network_wlan_disco
STATIC mp_obj_t network_wlan_status(size_t n_args, const mp_obj_t *args) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args == 1) {
- if (self->if_id == WIFI_IF_STA) {
+ if (self->if_id == ESP_IF_WIFI_STA) {
// Case of no arg is only for the STA interface
if (wifi_sta_connected) {
// Happy path, connected with IP
@@ -299,7 +353,7 @@ STATIC mp_obj_t network_wlan_status(size_t n_args, const mp_obj_t *args) {
switch ((uintptr_t)args[1]) {
case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_stations): {
// return list of connected stations, only if in soft-AP mode
- require_if(args[0], WIFI_IF_AP);
+ require_if(args[0], ESP_IF_WIFI_AP);
wifi_sta_list_t station_list;
esp_exceptions(esp_wifi_ap_get_sta_list(&station_list));
wifi_sta_info_t *stations = (wifi_sta_info_t *)station_list.sta;
@@ -313,7 +367,7 @@ STATIC mp_obj_t network_wlan_status(size_t n_args, const mp_obj_t *args) {
}
case (uintptr_t)MP_OBJ_NEW_QSTR(MP_QSTR_rssi): {
// return signal of AP, only in STA mode
- require_if(args[0], WIFI_IF_STA);
+ require_if(args[0], ESP_IF_WIFI_STA);
wifi_ap_record_t info;
esp_exceptions(esp_wifi_sta_get_ap_info(&info));
@@ -372,7 +426,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_wlan_scan_obj, network_wlan_scan);
STATIC mp_obj_t network_wlan_isconnected(mp_obj_t self_in) {
wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->if_id == WIFI_IF_STA) {
+ if (self->if_id == ESP_IF_WIFI_STA) {
return mp_obj_new_bool(wifi_sta_connected);
} else {
wifi_sta_list_t sta;
@@ -389,7 +443,7 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- bool is_wifi = self->if_id == WIFI_IF_AP || self->if_id == WIFI_IF_STA;
+ bool is_wifi = self->if_id == ESP_IF_WIFI_AP || self->if_id == ESP_IF_WIFI_STA;
wifi_config_t cfg;
if (is_wifi) {
@@ -417,7 +471,7 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
}
case MP_QSTR_ssid:
case MP_QSTR_essid: {
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
size_t len;
const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
len = MIN(len, sizeof(cfg.ap.ssid));
@@ -426,19 +480,19 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
break;
}
case MP_QSTR_hidden: {
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
break;
}
case MP_QSTR_security:
case MP_QSTR_authmode: {
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
break;
}
case MP_QSTR_key:
case MP_QSTR_password: {
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
size_t len;
const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
len = MIN(len, sizeof(cfg.ap.password) - 1);
@@ -467,18 +521,23 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
}
case MP_QSTR_hostname:
case MP_QSTR_dhcp_hostname: {
- const char *s = mp_obj_str_get_str(kwargs->table[i].value);
- esp_exceptions(tcpip_adapter_set_hostname(self->if_id, s));
+ // TODO: Deprecated. Use network.hostname(name) instead.
+ size_t len;
+ const char *str = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ if (len >= MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN) {
+ mp_raise_ValueError(NULL);
+ }
+ strcpy(mod_network_hostname, str);
break;
}
case MP_QSTR_max_clients: {
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
cfg.ap.max_connection = mp_obj_get_int(kwargs->table[i].value);
break;
}
case MP_QSTR_reconnects: {
int reconnects = mp_obj_get_int(kwargs->table[i].value);
- req_if = WIFI_IF_STA;
+ req_if = ESP_IF_WIFI_STA;
// parameter reconnects == -1 means to retry forever.
// here means conf_wifi_sta_reconnects == 0 to retry forever.
conf_wifi_sta_reconnects = (reconnects == -1) ? 0 : reconnects + 1;
@@ -493,6 +552,10 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
esp_exceptions(esp_wifi_set_protocol(self->if_id, mp_obj_get_int(kwargs->table[i].value)));
break;
}
+ case MP_QSTR_pm: {
+ esp_exceptions(esp_wifi_set_ps(mp_obj_get_int(kwargs->table[i].value)));
+ break;
+ }
default:
goto unknown;
}
@@ -522,8 +585,8 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
case MP_QSTR_mac: {
uint8_t mac[6];
switch (self->if_id) {
- case WIFI_IF_AP: // fallthrough intentional
- case WIFI_IF_STA:
+ case ESP_IF_WIFI_AP: // fallthrough intentional
+ case ESP_IF_WIFI_STA:
esp_exceptions(esp_wifi_get_mac(self->if_id, mac));
return mp_obj_new_bytes(mac, sizeof(mac));
default:
@@ -533,23 +596,23 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
case MP_QSTR_ssid:
case MP_QSTR_essid:
switch (self->if_id) {
- case WIFI_IF_STA:
+ case ESP_IF_WIFI_STA:
val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
break;
- case WIFI_IF_AP:
+ case ESP_IF_WIFI_AP:
val = mp_obj_new_str((char *)cfg.ap.ssid, cfg.ap.ssid_len);
break;
default:
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
}
break;
case MP_QSTR_hidden:
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
val = mp_obj_new_bool(cfg.ap.ssid_hidden);
break;
case MP_QSTR_security:
case MP_QSTR_authmode:
- req_if = WIFI_IF_AP;
+ req_if = ESP_IF_WIFI_AP;
val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
break;
case MP_QSTR_channel: {
@@ -561,9 +624,9 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
}
case MP_QSTR_hostname:
case MP_QSTR_dhcp_hostname: {
- const char *s;
- esp_exceptions(tcpip_adapter_get_hostname(self->if_id, &s));
- val = mp_obj_new_str(s, strlen(s));
+ // TODO: Deprecated. Use network.hostname() instead.
+ req_if = ESP_IF_WIFI_STA;
+ val = mp_obj_new_str(mod_network_hostname, strlen(mod_network_hostname));
break;
}
case MP_QSTR_max_clients: {
@@ -571,7 +634,7 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
break;
}
case MP_QSTR_reconnects:
- req_if = WIFI_IF_STA;
+ req_if = ESP_IF_WIFI_STA;
int rec = conf_wifi_sta_reconnects - 1;
val = MP_OBJ_NEW_SMALL_INT(rec);
break;
@@ -587,6 +650,12 @@ STATIC mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_
val = MP_OBJ_NEW_SMALL_INT(protocol_bitmap);
break;
}
+ case MP_QSTR_pm: {
+ wifi_ps_type_t ps_type;
+ esp_exceptions(esp_wifi_get_ps(&ps_type));
+ val = MP_OBJ_NEW_SMALL_INT(ps_type);
+ break;
+ }
default:
goto unknown;
}
@@ -611,18 +680,21 @@ STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_wlan_scan_obj) },
{ MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_wlan_isconnected_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_wlan_config_obj) },
- { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_network_ifconfig_obj) },
+
+ // Constants
+ { MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(WIFI_PS_NONE) },
+ { MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(WIFI_PS_MIN_MODEM) },
+ { MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(WIFI_PS_MAX_MODEM) },
};
STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
- wlan_if_type,
+ esp_network_wlan_type,
MP_QSTR_WLAN,
MP_TYPE_FLAG_NONE,
+ make_new, network_wlan_make_new,
locals_dict, &wlan_if_locals_dict
);
-STATIC const wlan_if_obj_t wlan_sta_obj = {{&wlan_if_type}, WIFI_IF_STA};
-STATIC const wlan_if_obj_t wlan_ap_obj = {{&wlan_if_type}, WIFI_IF_AP};
-
#endif // MICROPY_PY_NETWORK_WLAN
diff --git a/ports/esp32/partitions-32MiB-ota.csv b/ports/esp32/partitions-32MiB-ota.csv
new file mode 100644
index 000000000000..7366a2ad8df7
--- /dev/null
+++ b/ports/esp32/partitions-32MiB-ota.csv
@@ -0,0 +1,10 @@
+# Partition table for MicroPython with OTA support using 32MB flash
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x4000,
+otadata, data, ota, 0xd000, 0x2000,
+phy_init, data, phy, 0xf000, 0x1000,
+ota_0, app, ota_0, 0x10000, 0x270000,
+ota_1, app, ota_1, 0x280000, 0x270000,
+vfs, data, fat, 0x4f0000, 0x1B10000,
diff --git a/ports/esp32/partitions-32MiB.csv b/ports/esp32/partitions-32MiB.csv
new file mode 100644
index 000000000000..31591c99495f
--- /dev/null
+++ b/ports/esp32/partitions-32MiB.csv
@@ -0,0 +1,7 @@
+# Notes: the offset of the partition table itself is set in
+# $IDF_PATH/components/partition_table/Kconfig.projbuild.
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x6000,
+phy_init, data, phy, 0xf000, 0x1000,
+factory, app, factory, 0x10000, 0x1F0000,
+vfs, data, fat, 0x200000, 0x1E00000,
diff --git a/ports/esp32/ppp_set_auth.c b/ports/esp32/ppp_set_auth.c
new file mode 100644
index 000000000000..88ab668d48d3
--- /dev/null
+++ b/ports/esp32/ppp_set_auth.c
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// The pppapi_set_auth function was made static in the ESP-IDF, so it's re-added here.
+// See ESP-IDF commit c67f4c2b4c2bb4b7740f988fc0f8a3e911e56afe
+
+#include "ppp_set_auth.h"
+
+#ifdef CONFIG_ESP_NETIF_TCPIP_LWIP
+
+#include "netif/ppp/pppapi.h"
+
+typedef struct {
+ struct tcpip_api_call_data call;
+ ppp_pcb *ppp;
+ u8_t authtype;
+ const char *user;
+ const char *passwd;
+} set_auth_msg_t;
+
+static err_t pppapi_do_ppp_set_auth(struct tcpip_api_call_data *m) {
+ set_auth_msg_t *msg = (set_auth_msg_t *)m;
+ ppp_set_auth(msg->ppp, msg->authtype, msg->user, msg->passwd);
+ return ERR_OK;
+}
+
+void pppapi_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd) {
+ set_auth_msg_t msg = { .ppp = pcb, .authtype = authtype, .user = user, .passwd = passwd};
+ tcpip_api_call(pppapi_do_ppp_set_auth, &msg.call);
+}
+
+#endif
diff --git a/ports/esp32/ppp_set_auth.h b/ports/esp32/ppp_set_auth.h
new file mode 100644
index 000000000000..67676ef4d6c7
--- /dev/null
+++ b/ports/esp32/ppp_set_auth.h
@@ -0,0 +1,22 @@
+/*
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// The pppapi_set_auth function was made static in the ESP-IDF, so it's re-added here.
+// See ESP-IDF commit c67f4c2b4c2bb4b7740f988fc0f8a3e911e56afe
+
+#pragma once
+
+#include "esp_netif.h"
+
+#ifdef CONFIG_ESP_NETIF_TCPIP_LWIP
+
+#include "lwip/netif.h"
+
+typedef struct ppp_pcb_s ppp_pcb;
+
+void pppapi_set_auth(ppp_pcb *pcb, u8_t authtype, const char *user, const char *passwd);
+
+#endif
diff --git a/ports/esp32/uart.c b/ports/esp32/uart.c
index f6493dc79679..358d43470995 100644
--- a/ports/esp32/uart.c
+++ b/ports/esp32/uart.c
@@ -28,77 +28,93 @@
#include
-#include "driver/uart.h"
-#include "soc/uart_periph.h"
+#include "hal/uart_hal.h"
#include "py/runtime.h"
#include "py/mphal.h"
#include "uart.h"
+// Backwards compatibility for when MICROPY_HW_UART_REPL was a ESP-IDF UART
+// driver enum. Only UART_NUM_0 was supported with that version of the driver.
+#define UART_NUM_0 0
+
STATIC void uart_irq_handler(void *arg);
+// Declaring the HAL structure on the stack saves a tiny amount of static RAM
+#define REPL_HAL_DEFN() { .dev = UART_LL_GET_HW(MICROPY_HW_UART_REPL) }
+
+// RXFIFO Full interrupt threshold. Set the same as the ESP-IDF UART driver
+#define RXFIFO_FULL_THR (SOC_UART_FIFO_LEN - 8)
+
+// RXFIFO RX timeout threshold. This is in bit periods, so 10==one byte. Same as ESP-IDF UART driver.
+#define RXFIFO_RX_TIMEOUT (10)
+
void uart_stdout_init(void) {
- uart_config_t uartcfg = {
- .baud_rate = MICROPY_HW_UART_REPL_BAUD,
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .rx_flow_ctrl_thresh = 0
- };
- uart_param_config(MICROPY_HW_UART_REPL, &uartcfg);
-
- const uint32_t rxbuf = 129; // IDF requires > 128 min
- const uint32_t txbuf = 0;
-
- uart_driver_install(MICROPY_HW_UART_REPL, rxbuf, txbuf, 0, NULL, 0);
-
- uart_isr_handle_t handle;
- uart_isr_free(MICROPY_HW_UART_REPL);
- uart_isr_register(MICROPY_HW_UART_REPL, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle);
- uart_enable_rx_intr(MICROPY_HW_UART_REPL);
+ uart_hal_context_t repl_hal = REPL_HAL_DEFN();
+ uint32_t sclk_freq;
+
+ #if UART_SCLK_DEFAULT == SOC_MOD_CLK_APB
+ sclk_freq = APB_CLK_FREQ; // Assumes no frequency scaling
+ #else
+ // ESP32-H2 and ESP32-C2, I think
+ #error "This SoC uses a different default UART SCLK source, code needs updating."
+ #endif
+
+ uart_hal_init(&repl_hal, MICROPY_HW_UART_REPL); // Sets defaults: 8n1, no flow control
+ uart_hal_set_baudrate(&repl_hal, MICROPY_HW_UART_REPL_BAUD, sclk_freq);
+ uart_hal_rxfifo_rst(&repl_hal);
+ uart_hal_txfifo_rst(&repl_hal);
+
+ ESP_ERROR_CHECK(
+ esp_intr_alloc(uart_periph_signal[MICROPY_HW_UART_REPL].irq,
+ ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM,
+ uart_irq_handler,
+ NULL,
+ NULL)
+ );
+
+ // Enable RX interrupts
+ uart_hal_set_rxfifo_full_thr(&repl_hal, RXFIFO_FULL_THR);
+ uart_hal_set_rx_timeout(&repl_hal, RXFIFO_RX_TIMEOUT);
+ uart_hal_ena_intr_mask(&repl_hal, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
}
int uart_stdout_tx_strn(const char *str, size_t len) {
+ uart_hal_context_t repl_hal = REPL_HAL_DEFN();
size_t remaining = len;
+ uint32_t written = 0;
// TODO add a timeout
for (;;) {
- int ret = uart_tx_chars(MICROPY_HW_UART_REPL, str, remaining);
- if (ret == -1) {
- return -1;
- }
- remaining -= ret;
- if (remaining <= 0) {
+ uart_hal_write_txfifo(&repl_hal, (const void *)str, remaining, &written);
+
+ if (written >= remaining) {
break;
}
- str += ret;
+ remaining -= written;
+ str += written;
ulTaskNotifyTake(pdFALSE, 1);
}
- return len - remaining;
+ return len;
}
// all code executed in ISR must be in IRAM, and any const data must be in DRAM
STATIC void IRAM_ATTR uart_irq_handler(void *arg) {
- volatile uart_dev_t *uart = &UART0;
- #if CONFIG_IDF_TARGET_ESP32S3
- uart->int_clr.rxfifo_full_int_clr = 1;
- uart->int_clr.rxfifo_tout_int_clr = 1;
- #else
- uart->int_clr.rxfifo_full = 1;
- uart->int_clr.rxfifo_tout = 1;
- uart->int_clr.frm_err = 1;
- #endif
- while (uart->status.rxfifo_cnt) {
- #if CONFIG_IDF_TARGET_ESP32
- uint8_t c = uart->fifo.rw_byte;
- #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
- uint8_t c = READ_PERI_REG(UART_FIFO_AHB_REG(0)); // UART0
- #endif
- if (c == mp_interrupt_char) {
+ uint8_t rbuf[SOC_UART_FIFO_LEN];
+ int len;
+ uart_hal_context_t repl_hal = REPL_HAL_DEFN();
+
+ uart_hal_clr_intsts_mask(&repl_hal, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_FRAM_ERR);
+
+ len = uart_hal_get_rxfifo_len(&repl_hal);
+
+ uart_hal_read_rxfifo(&repl_hal, rbuf, &len);
+
+ for (int i = 0; i < len; i++) {
+ if (rbuf[i] == mp_interrupt_char) {
mp_sched_keyboard_interrupt();
} else {
// this is an inline function so will be in IRAM
- ringbuf_put(&stdin_ringbuf, c);
+ ringbuf_put(&stdin_ringbuf, rbuf[i]);
}
}
}
diff --git a/ports/esp32/uart.h b/ports/esp32/uart.h
index e3c7482e7b48..6410db24c957 100644
--- a/ports/esp32/uart.h
+++ b/ports/esp32/uart.h
@@ -30,11 +30,11 @@
// Whether to enable the REPL on a UART.
#ifndef MICROPY_HW_ENABLE_UART_REPL
-#define MICROPY_HW_ENABLE_UART_REPL (!CONFIG_USB_ENABLED && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
+#define MICROPY_HW_ENABLE_UART_REPL (!CONFIG_USB_OTG_SUPPORTED && !CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG)
#endif
#ifndef MICROPY_HW_UART_REPL
-#define MICROPY_HW_UART_REPL (UART_NUM_0)
+#define MICROPY_HW_UART_REPL (0)
#endif
#ifndef MICROPY_HW_UART_REPL_BAUD
diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c
index 5a613d24412c..b9d99676d3c5 100644
--- a/ports/esp32/usb.c
+++ b/ports/esp32/usb.c
@@ -28,15 +28,17 @@
#include "py/mphal.h"
#include "usb.h"
-#if CONFIG_USB_ENABLED
+#if CONFIG_USB_OTG_SUPPORTED
+#include "esp_timer.h"
+#ifndef NO_QSTR
#include "tinyusb.h"
#include "tusb_cdc_acm.h"
+#endif
#define CDC_ITF TINYUSB_CDC_ACM_0
-static uint8_t usb_rx_buf[CONFIG_USB_CDC_RX_BUFSIZE];
-static uint8_t usb_cdc_connected;
+static uint8_t usb_rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE];
static void usb_callback_rx(int itf, cdcacm_event_t *event) {
// TODO: what happens if more chars come in during this function, are they lost?
@@ -59,36 +61,35 @@ static void usb_callback_rx(int itf, cdcacm_event_t *event) {
}
}
-void usb_callback_line_state_changed(int itf, cdcacm_event_t *event) {
- int dtr = event->line_state_changed_data.dtr;
- int rts = event->line_state_changed_data.rts;
- // If dtr && rts are both true, the CDC is connected to a HOST.
- usb_cdc_connected = dtr && rts;
-}
-
void usb_init(void) {
// Initialise the USB with defaults.
tinyusb_config_t tusb_cfg = {0};
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
// Initialise the USB serial interface.
- tinyusb_config_cdcacm_t amc_cfg = {
+ tinyusb_config_cdcacm_t acm_cfg = {
.usb_dev = TINYUSB_USBDEV_0,
.cdc_port = CDC_ITF,
.rx_unread_buf_sz = 256,
.callback_rx = &usb_callback_rx,
- .callback_rx_wanted_char = NULL,
- .callback_line_state_changed = &usb_callback_line_state_changed,
- .callback_line_coding_changed = NULL
+ #ifdef MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB
+ .callback_rx_wanted_char = &MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB,
+ #endif
+ #ifdef MICROPY_HW_USB_CUSTOM_LINE_STATE_CB
+ .callback_line_state_changed = &MICROPY_HW_USB_CUSTOM_LINE_STATE_CB,
+ #endif
+ #ifdef MICROPY_HW_USB_CUSTOM_LINE_CODING_CB
+ .callback_line_coding_changed = &MICROPY_HW_USB_CUSTOM_LINE_CODING_CB,
+ #endif
};
- usb_cdc_connected = 0;
- ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
+ ESP_ERROR_CHECK(tusb_cdc_acm_init(&acm_cfg));
}
void usb_tx_strn(const char *str, size_t len) {
// Write out the data to the CDC interface, but only while the USB host is connected.
- while (usb_cdc_connected && len) {
+ uint64_t timeout = esp_timer_get_time() + (uint64_t)(MICROPY_HW_USB_CDC_TX_TIMEOUT_MS * 1000);
+ while (tud_cdc_n_connected(CDC_ITF) && len && esp_timer_get_time() < timeout) {
size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len);
str += l;
len -= l;
@@ -96,4 +97,4 @@ void usb_tx_strn(const char *str, size_t len) {
}
}
-#endif // CONFIG_USB_ENABLED
+#endif // CONFIG_USB_OTG_SUPPORTED
diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h
index a1037803337f..a4c7d40701df 100644
--- a/ports/esp32/usb.h
+++ b/ports/esp32/usb.h
@@ -26,6 +26,8 @@
#ifndef MICROPY_INCLUDED_ESP32_USB_H
#define MICROPY_INCLUDED_ESP32_USB_H
+#define MICROPY_HW_USB_CDC_TX_TIMEOUT_MS (500)
+
void usb_init(void);
void usb_tx_strn(const char *str, size_t len);
diff --git a/ports/esp32/usb_serial_jtag.c b/ports/esp32/usb_serial_jtag.c
index a7d06a355a2e..3289a1b5c078 100644
--- a/ports/esp32/usb_serial_jtag.c
+++ b/ports/esp32/usb_serial_jtag.c
@@ -79,9 +79,9 @@ void usb_serial_jtag_tx_strn(const char *str, size_t len) {
if (l > USB_SERIAL_JTAG_PACKET_SZ_BYTES) {
l = USB_SERIAL_JTAG_PACKET_SZ_BYTES;
}
- portTickType start_tick = xTaskGetTickCount();
+ TickType_t start_tick = xTaskGetTickCount();
while (!usb_serial_jtag_ll_txfifo_writable()) {
- portTickType now_tick = xTaskGetTickCount();
+ TickType_t now_tick = xTaskGetTickCount();
if (!terminal_connected || now_tick > (start_tick + pdMS_TO_TICKS(200))) {
terminal_connected = false;
return;
diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile
index 168d1d9f6ab6..1cdcafa031bc 100644
--- a/ports/esp8266/Makefile
+++ b/ports/esp8266/Makefile
@@ -1,15 +1,21 @@
-# Select the board to build for: if not given on the command line,
-# then default to GENERIC.
+# Select the board to build for:
+ifdef BOARD_DIR
+# Custom board path - remove trailing slash and get the final component of
+# the path as the board name.
+BOARD ?= $(notdir $(BOARD_DIR:/=))
+else
+# If not given on the command line, then default to GENERIC.
BOARD ?= GENERIC
-
-# If the build directory is not given, make it reflect the board name.
-BUILD ?= build-$(BOARD)
-
BOARD_DIR ?= boards/$(BOARD)
+endif
+
ifeq ($(wildcard $(BOARD_DIR)/.),)
$(error Invalid BOARD specified: $(BOARD_DIR))
endif
+# If the build directory is not given, make it reflect the board name.
+BUILD ?= build-$(BOARD)
+
include ../../py/mkenv.mk
# Optional
@@ -21,7 +27,7 @@ QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
# MicroPython feature configurations
MICROPY_ROM_TEXT_COMPRESSION ?= 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_AXTLS = 1
AXTLS_DEFS_EXTRA = -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=4096
BTREE_DEFS_EXTRA = -DDEFPSIZE=1024 -DMINCACHE=3
@@ -64,6 +70,11 @@ LD_FILES ?= boards/esp8266_2m.ld
LDFLAGS += -nostdlib -T $(LD_FILES) -Map=$(@:.elf=.map) --cref
LIBS += -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211
+ifeq ($(MICROPY_ESPNOW),1)
+CFLAGS += -DMICROPY_ESPNOW=1
+LIBS += -lespnow
+endif
+
LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
LIBS += -L$(dir $(LIBGCC_FILE_NAME)) -lgcc
@@ -100,14 +111,18 @@ SRC_C = \
machine_wdt.c \
machine_hspi.c \
modesp.c \
- modnetwork.c \
- modutime.c \
+ network_wlan.c \
ets_alt_task.c \
fatfs_port.c \
posix_helpers.c \
hspi.c \
$(wildcard $(BOARD_DIR)/*.c) \
+ifeq ($(MICROPY_ESPNOW),1)
+SRC_C += \
+ modespnow.c
+endif
+
LIB_SRC_C = $(addprefix lib/,\
libm/math.c \
libm/fmodf.c \
@@ -185,12 +200,6 @@ $(BUILD)/uart.o: $(CONFVARS_FILE)
FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
-ifneq ($(FROZEN_MANIFEST),)
-CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
-CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
-endif
-
.PHONY: deploy
deploy: $(BUILD)/firmware-combined.bin
diff --git a/ports/esp8266/README.md b/ports/esp8266/README.md
index b54d8958d77d..1e0cae213937 100644
--- a/ports/esp8266/README.md
+++ b/ports/esp8266/README.md
@@ -1,10 +1,9 @@
MicroPython port to ESP8266
===========================
-This is an experimental port of MicroPython for the WiFi modules based
-on Espressif ESP8266 chip.
-
-WARNING: The port is experimental and many APIs are subject to change.
+This is a port of MicroPython to the Espressif ESP8266 WiFi microcontroller.
+MicroPython runs on this chip without any underlying operating system, using
+the ESP8266 NONOS SDK.
Supported features include:
- REPL (Python prompt) over UART0.
diff --git a/ports/esp8266/boards/GENERIC/board.md b/ports/esp8266/boards/GENERIC/board.md
index b93ca509f89c..fa0cf410d66f 100644
--- a/ports/esp8266/boards/GENERIC/board.md
+++ b/ports/esp8266/boards/GENERIC/board.md
@@ -6,7 +6,7 @@ Note: v1.12-334 and newer (including v1.13) require an ESP8266 module with
2MiB of flash or more, and use littlefs as the filesystem by default. When
upgrading from older firmware please backup your files first, and either
erase all flash before upgrading, or after upgrading execute
-`uos.VfsLfs2.mkfs(bdev)`.
+`os.VfsLfs2.mkfs(bdev)`.
### OTA builds
Over-The-Air (OTA) builds of the ESP8266 firmware are also provided.
diff --git a/ports/esp8266/boards/GENERIC/manifest.py b/ports/esp8266/boards/GENERIC/manifest.py
index ef708846241f..fd9c41dc5423 100644
--- a/ports/esp8266/boards/GENERIC/manifest.py
+++ b/ports/esp8266/boards/GENERIC/manifest.py
@@ -1,8 +1,8 @@
# base modules
include("$(PORT_DIR)/boards/manifest.py")
-# uasyncio
-include("$(MPY_DIR)/extmod/uasyncio")
+# asyncio
+include("$(MPY_DIR)/extmod/asyncio")
# drivers
require("ssd1306")
diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.h b/ports/esp8266/boards/GENERIC/mpconfigboard.h
index 1d9b8e6f70dd..52c93f83a368 100644
--- a/ports/esp8266/boards/GENERIC/mpconfigboard.h
+++ b/ports/esp8266/boards/GENERIC/mpconfigboard.h
@@ -11,4 +11,4 @@
#define MICROPY_READER_VFS (MICROPY_VFS)
#define MICROPY_VFS (1)
-#define MICROPY_PY_UCRYPTOLIB (1)
+#define MICROPY_PY_CRYPTOLIB (1)
diff --git a/ports/esp8266/boards/GENERIC/mpconfigboard.mk b/ports/esp8266/boards/GENERIC/mpconfigboard.mk
index 6861317218b3..8d7babdc8448 100644
--- a/ports/esp8266/boards/GENERIC/mpconfigboard.mk
+++ b/ports/esp8266/boards/GENERIC/mpconfigboard.mk
@@ -1,5 +1,6 @@
LD_FILES = boards/esp8266_2m.ld
+MICROPY_ESPNOW ?= 1
MICROPY_PY_BTREE ?= 1
MICROPY_VFS_FAT ?= 1
MICROPY_VFS_LFS2 ?= 1
diff --git a/ports/esp8266/boards/GENERIC_1M/board.md b/ports/esp8266/boards/GENERIC_1M/board.md
index 4a0e67707871..17cc6e3a6bdf 100644
--- a/ports/esp8266/boards/GENERIC_1M/board.md
+++ b/ports/esp8266/boards/GENERIC_1M/board.md
@@ -2,4 +2,4 @@ The following are daily builds of the ESP8266 firmware tailored for modules with
only 1MiB of flash. This firmware uses littlefs as the filesystem.
When upgrading from older firmware that uses a FAT filesystem please backup your files
first, and either erase all flash before upgrading, or after upgrading execute
-`uos.VfsLfs2.mkfs(bdev)`.
+`os.VfsLfs2.mkfs(bdev)`.
diff --git a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h
index cf5127686cc2..41752e692b31 100644
--- a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h
+++ b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.h
@@ -13,5 +13,5 @@
#define MICROPY_PY_FSTRINGS (0)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
-#define MICROPY_PY_UASYNCIO (0)
-#define MICROPY_PY_UCRYPTOLIB (1)
+#define MICROPY_PY_ASYNCIO (0)
+#define MICROPY_PY_CRYPTOLIB (1)
diff --git a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk
index fdbb0d82451e..adc31702e0de 100644
--- a/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk
+++ b/ports/esp8266/boards/GENERIC_1M/mpconfigboard.mk
@@ -1,4 +1,5 @@
LD_FILES = boards/esp8266_1m.ld
+MICROPY_ESPNOW ?= 1
MICROPY_PY_BTREE ?= 1
MICROPY_VFS_LFS2 ?= 1
diff --git a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h
index b0adb7081c99..c29e23d5ad11 100644
--- a/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h
+++ b/ports/esp8266/boards/GENERIC_512K/mpconfigboard.h
@@ -8,6 +8,6 @@
#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
#define MICROPY_PY_SYS_STDIO_BUFFER (0)
-#define MICROPY_PY_UASYNCIO (0)
-#define MICROPY_PY_URE_SUB (0)
+#define MICROPY_PY_ASYNCIO (0)
+#define MICROPY_PY_RE_SUB (0)
#define MICROPY_PY_FRAMEBUF (0)
diff --git a/ports/esp8266/boards/esp8266_common.ld b/ports/esp8266/boards/esp8266_common.ld
index c2d62e9dd4ce..083e84d9afe5 100644
--- a/ports/esp8266/boards/esp8266_common.ld
+++ b/ports/esp8266/boards/esp8266_common.ld
@@ -83,6 +83,7 @@ SECTIONS
*libnet80211.a:(.literal.* .text.*)
*libwpa.a:(.literal.* .text.*)
*libwpa2.a:(.literal.* .text.*)
+ *libespnow.a:(.literal.* .text.*)
/* we put some specific text in this section */
@@ -163,12 +164,11 @@ SECTIONS
*machine_hspi.o(.literal*, .text*)
*hspi.o(.literal*, .text*)
*modesp.o(.literal* .text*)
- *modnetwork.o(.literal* .text*)
- *moduos.o(.literal* .text*)
- *modutime.o(.literal* .text*)
+ *modos.o(.literal* .text*)
*modlwip.o(.literal* .text*)
*modsocket.o(.literal* .text*)
*modonewire.o(.literal* .text*)
+ *network_wlan.o(.literal* .text*)
*esp_mphal.o(.literal* .text*)
/* we put as much rodata as possible in this section */
diff --git a/ports/esp8266/boards/manifest.py b/ports/esp8266/boards/manifest.py
index 53975f6a6baf..17f58feac88a 100644
--- a/ports/esp8266/boards/manifest.py
+++ b/ports/esp8266/boards/manifest.py
@@ -1,8 +1,7 @@
freeze("$(PORT_DIR)/modules")
+# require("aioespnow")
+require("bundle-networking")
require("dht")
require("ds18x20")
-require("mip")
require("neopixel")
-require("ntptime")
require("onewire")
-require("webrepl")
diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c
index 3cb4807333c4..7606bd4f6313 100644
--- a/ports/esp8266/esp_mphal.c
+++ b/ports/esp8266/esp_mphal.c
@@ -62,6 +62,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) {
ret |= MP_STREAM_POLL_RD;
}
+ if (poll_flags & MP_STREAM_POLL_WR) {
+ ret |= mp_os_dupterm_poll(poll_flags);
+ }
return ret;
}
@@ -92,7 +95,7 @@ void mp_hal_debug_str(const char *str) {
#endif
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
- mp_uos_dupterm_tx_strn(str, len);
+ mp_os_dupterm_tx_strn(str, len);
}
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
@@ -143,7 +146,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
}
lock = 1;
while (1) {
- int c = mp_uos_dupterm_rx_chr();
+ int c = mp_os_dupterm_rx_chr();
if (c < 0) {
break;
}
diff --git a/ports/esp8266/esppwm.c b/ports/esp8266/esppwm.c
index 6164e2fc8b11..d7ac44a1786c 100644
--- a/ports/esp8266/esppwm.c
+++ b/ports/esp8266/esppwm.c
@@ -165,7 +165,7 @@ pwm_start(void) {
}
}
PWM_DBG("2channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\n", *local_channel, local_single[0].h_time, local_single[1].h_time, local_single[2].h_time, local_single[3].h_time);
- // step 4: cacl delt time
+ // step 4: calc delta time
for (i = *local_channel - 1; i > 0; i--) {
local_single[i].h_time -= local_single[i - 1].h_time;
}
@@ -389,7 +389,6 @@ pwm_add(uint8_t pin_id, uint32_t pin_mux, uint32_t pin_func) {
pwm.duty[i] = 0;
pwm_gpio |= (1 << pin_num[channel]);
PIN_FUNC_SELECT(pin_mux, pin_func);
- GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel]))) & (~GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); // disable open drain;
pwm_channel_num++;
UNLOCK_PWM(critical); // leave critical
return channel;
diff --git a/ports/esp8266/help.c b/ports/esp8266/help.c
index a755a10a7617..a9cb27bad51c 100644
--- a/ports/esp8266/help.c
+++ b/ports/esp8266/help.c
@@ -29,7 +29,8 @@
const char esp_help_text[] =
"Welcome to MicroPython!\n"
"\n"
- "For online docs please visit http://docs.micropython.org/en/latest/esp8266/ .\n"
+ "For online docs please visit http://docs.micropython.org/\n"
+ "\n"
"For diagnostic information to include in bug reports execute 'import port_diag'.\n"
"\n"
"Basic WiFi configuration:\n"
diff --git a/ports/esp8266/hspi_register.h b/ports/esp8266/hspi_register.h
index 50ef2fdca3e1..0d0cf2f747b8 100644
--- a/ports/esp8266/hspi_register.h
+++ b/ports/esp8266/hspi_register.h
@@ -79,7 +79,7 @@
#define SPI_MOSI_DELAY_NUM 0x00000007
#define SPI_MOSI_DELAY_NUM_S 23
#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk
- //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk
+ //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negative edge of clk
//mode 2 : Do not use this mode.
#define SPI_MOSI_DELAY_MODE_S 21
#define SPI_MISO_DELAY_NUM 0x00000007
diff --git a/ports/esp8266/machine_pin.c b/ports/esp8266/machine_pin.c
index ea17728e2359..344197da9472 100644
--- a/ports/esp8266/machine_pin.c
+++ b/ports/esp8266/machine_pin.c
@@ -46,13 +46,15 @@
(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port)) & ~GPIO_PIN_INT_TYPE_MASK) \
| GPIO_PIN_INT_TYPE_SET(trig))) \
-#define GPIO_MODE_INPUT (0)
-#define GPIO_MODE_OUTPUT (1)
-#define GPIO_MODE_OPEN_DRAIN (2) // synthesised
-#define GPIO_PULL_NONE (0)
-#define GPIO_PULL_UP (1)
-// Removed in SDK 1.1.0
-// #define GPIO_PULL_DOWN (2)
+#define ENABLE_OPEN_DRAIN(phys_port) \
+ (GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(phys_port)), \
+ GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(phys_port))) \
+ | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)))
+
+#define DISABLE_OPEN_DRAIN(phys_port) \
+ (GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(phys_port)), \
+ GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(phys_port))) \
+ & ~GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))) \
typedef struct _pin_irq_obj_t {
mp_obj_base_t base;
@@ -84,7 +86,7 @@ const pyb_pin_obj_t pyb_pin_obj[16 + 1] = {
{{&pyb_pin_type}, 16, -1, -1},
};
-STATIC uint8_t pin_mode[16 + 1];
+uint8_t pin_mode[16 + 1];
// forward declaration
STATIC const pin_irq_obj_t pin_irq_obj[16];
@@ -120,11 +122,22 @@ void MP_FASTCODE(pin_intr_handler_part2)(uint32_t status) {
}
pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in) {
- if (mp_obj_get_type(pin_in) != &pyb_pin_type) {
- mp_raise_ValueError(MP_ERROR_TEXT("expecting a pin"));
+ if (mp_obj_is_type(pin_in, &pyb_pin_type)) {
+ return pin_in;
+ }
+ // Get the wanted pin object.
+ if (mp_obj_is_small_int(pin_in)) {
+ int wanted_pin = mp_obj_get_int(pin_in);
+ if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
+ pyb_pin_obj_t *pin = (pyb_pin_obj_t *)&pyb_pin_obj[wanted_pin];
+ if (pin->base.type != NULL) {
+ return pin;
+ }
+ }
}
- pyb_pin_obj_t *self = pin_in;
- return self;
+ // At this place a check for named pins may be added.
+ //
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
}
uint mp_obj_get_pin(mp_obj_t pin_in) {
@@ -173,9 +186,7 @@ void mp_hal_pin_open_drain(mp_hal_pin_obj_t pin_id) {
ETS_GPIO_INTR_DISABLE();
PIN_FUNC_SELECT(pin->periph, pin->func);
- GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)),
- GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin->phys_port)))
- | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); // open drain
+ ENABLE_OPEN_DRAIN(pin->phys_port);
GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS,
GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << pin->phys_port));
ETS_GPIO_INTR_ENABLE();
@@ -279,6 +290,7 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, size_t n_args, cons
mp_raise_ValueError(MP_ERROR_TEXT("Pin(16) doesn't support pull"));
}
} else {
+ DISABLE_OPEN_DRAIN(self->phys_port);
PIN_FUNC_SELECT(self->periph, self->func);
#if 0
// Removed in SDK 1.1.0
@@ -309,14 +321,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
// get the wanted pin object
- int wanted_pin = mp_obj_get_int(args[0]);
- pyb_pin_obj_t *pin = NULL;
- if (0 <= wanted_pin && wanted_pin < MP_ARRAY_SIZE(pyb_pin_obj)) {
- pin = (pyb_pin_obj_t *)&pyb_pin_obj[wanted_pin];
- }
- if (pin == NULL || pin->base.type == NULL) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
- }
+ pyb_pin_obj_t *pin = mp_obj_get_pin_obj(args[0]);
if (n_args > 1 || n_kw > 0) {
// pin mode given, so configure this GPIO
diff --git a/ports/esp8266/machine_pwm.c b/ports/esp8266/machine_pwm.c
index 00547195f9a9..58c8fa915fd5 100644
--- a/ports/esp8266/machine_pwm.c
+++ b/ports/esp8266/machine_pwm.c
@@ -25,6 +25,7 @@
*/
#include "py/runtime.h"
+#include "py/mphal.h"
#include "modmachine.h"
#include "esppwm.h"
@@ -34,8 +35,11 @@ typedef struct _machine_pwm_obj_t {
pyb_pin_obj_t *pin;
uint8_t active;
uint8_t channel;
+ int32_t duty_ns;
} machine_pwm_obj_t;
+STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty);
+
STATIC bool pwm_inited = false;
/******************************************************************************/
@@ -52,10 +56,12 @@ STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
}
STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_freq, ARG_duty };
+ enum { ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_duty, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = -1} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@@ -73,6 +79,19 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self, size_t n_args, c
if (args[ARG_duty].u_int != -1) {
pwm_set_duty(args[ARG_duty].u_int, self->channel);
}
+ if (args[ARG_duty_u16].u_int != -1) {
+ pwm_set_duty(args[ARG_duty_u16].u_int * 1000 / 65536, self->channel);
+ }
+ if (args[ARG_duty_ns].u_int != -1) {
+ uint32_t freq = pwm_get_freq(0);
+ if (freq > 0) {
+ pwm_set_duty((uint64_t)args[ARG_duty_ns].u_int * freq / 1000000, self->channel);
+ }
+ }
+
+ if (pin_mode[self->pin->phys_port] == GPIO_MODE_OPEN_DRAIN) {
+ mp_hal_pin_open_drain(self->pin->phys_port);
+ }
pwm_start();
}
@@ -86,6 +105,7 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
self->pin = pin;
self->active = 0;
self->channel = -1;
+ self->duty_ns = -1;
// start the PWM subsystem if it's not already running
if (!pwm_inited) {
@@ -113,22 +133,57 @@ STATIC mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
STATIC void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
pwm_set_freq(freq, 0);
- pwm_start();
+ if (self->duty_ns != -1) {
+ mp_machine_pwm_duty_set_ns(self, self->duty_ns);
+ } else {
+ pwm_start();
+ }
}
-STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
+STATIC void set_active(machine_pwm_obj_t *self, bool set_pin) {
if (!self->active) {
pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
self->active = 1;
+ if (set_pin && pin_mode[self->pin->phys_port] == GPIO_MODE_OPEN_DRAIN) {
+ mp_hal_pin_open_drain(self->pin->phys_port);
+ }
}
+}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get(machine_pwm_obj_t *self) {
+ set_active(self, true);
return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel));
}
STATIC void mp_machine_pwm_duty_set(machine_pwm_obj_t *self, mp_int_t duty) {
- if (!self->active) {
- pwm_add(self->pin->phys_port, self->pin->periph, self->pin->func);
- self->active = 1;
- }
+ set_active(self, false);
+ self->duty_ns = -1;
pwm_set_duty(duty, self->channel);
pwm_start();
}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
+ set_active(self, true);
+ return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel) * 65536 / 1024);
+}
+
+STATIC void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty) {
+ set_active(self, false);
+ self->duty_ns = -1;
+ pwm_set_duty(duty * 1024 / 65536, self->channel);
+ pwm_start();
+}
+
+STATIC mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
+ set_active(self, true);
+ uint32_t freq = pwm_get_freq(0);
+ return MP_OBJ_NEW_SMALL_INT(pwm_get_duty(self->channel) * 976563 / freq);
+}
+
+STATIC void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty) {
+ set_active(self, false);
+ self->duty_ns = duty;
+ uint32_t freq = pwm_get_freq(0);
+ pwm_set_duty(duty * freq / 976562, self->channel); // 1e9/1024 = 976562.5
+ pwm_start();
+}
diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c
index 583540a81c76..3083fe364e77 100644
--- a/ports/esp8266/main.c
+++ b/ports/esp8266/main.c
@@ -45,6 +45,10 @@
#include "gccollect.h"
#include "user_interface.h"
+#if MICROPY_ESPNOW
+#include "modespnow.h"
+#endif
+
STATIC char heap[38 * 1024];
STATIC void mp_reset(void) {
@@ -70,11 +74,15 @@ STATIC void mp_reset(void) {
args[1] = MP_OBJ_NEW_SMALL_INT(115200);
args[0] = MP_OBJ_TYPE_GET_SLOT(&pyb_uart_type, make_new)(&pyb_uart_type, 2, 0, args);
args[1] = MP_OBJ_NEW_SMALL_INT(1);
- mp_uos_dupterm_obj.fun.var(2, args);
+ mp_os_dupterm_obj.fun.var(2, args);
}
+ #if MICROPY_ESPNOW
+ espnow_deinit(mp_const_none);
+ #endif
+
#if MICROPY_MODULE_FROZEN
- pyexec_frozen_module("_boot.py");
+ pyexec_frozen_module("_boot.py", false);
pyexec_file_if_exists("boot.py");
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
pyexec_file_if_exists("main.py");
diff --git a/ports/esp8266/makeimg.py b/ports/esp8266/makeimg.py
index 4d31cc079960..662e6f83204a 100644
--- a/ports/esp8266/makeimg.py
+++ b/ports/esp8266/makeimg.py
@@ -14,7 +14,6 @@
md5 = hashlib.md5()
with open(sys.argv[3], "wb") as fout:
-
with open(sys.argv[1], "rb") as f:
data_flash = f.read()
fout.write(data_flash)
diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c
index 645de7fe9b0a..95595faebc79 100644
--- a/ports/esp8266/modesp.c
+++ b/ports/esp8266/modesp.c
@@ -31,7 +31,6 @@
#include "py/persistentcode.h"
#include "py/mperrno.h"
#include "py/mphal.h"
-#include "drivers/dht/dht.h"
#include "uart.h"
#include "user_interface.h"
#include "mem.h"
@@ -202,8 +201,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw);
STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
- esp_apa102_write(mp_obj_get_pin_obj(clockPin)->phys_port,
- mp_obj_get_pin_obj(dataPin)->phys_port,
+ esp_apa102_write(mp_obj_get_pin(clockPin),
+ mp_obj_get_pin(dataPin),
(uint8_t *)bufinfo.buf, bufinfo.len);
return mp_const_none;
}
@@ -355,7 +354,6 @@ STATIC const mp_rom_map_elem_t esp_module_globals_table[] = {
#if MICROPY_ESP8266_APA102
{ MP_ROM_QSTR(MP_QSTR_apa102_write), MP_ROM_PTR(&esp_apa102_write_obj) },
#endif
- { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_freemem), MP_ROM_PTR(&esp_freemem_obj) },
{ MP_ROM_QSTR(MP_QSTR_meminfo), MP_ROM_PTR(&esp_meminfo_obj) },
{ MP_ROM_QSTR(MP_QSTR_check_fw), MP_ROM_PTR(&esp_check_fw_obj) },
diff --git a/ports/esp8266/modespnow.c b/ports/esp8266/modespnow.c
new file mode 100644
index 000000000000..1f89204676c0
--- /dev/null
+++ b/ports/esp8266/modespnow.c
@@ -0,0 +1,507 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2020 Nick Moore
+ * Copyright (c) 2018 shawwwn
+ * Copyright (c) 2020-2021 Glenn Moloney @glenn20
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#include
+#include
+#include
+
+#include "py/runtime.h"
+
+#if MICROPY_ESPNOW
+
+#include "c_types.h"
+#include "espnow.h"
+
+#include "py/mphal.h"
+#include "py/mperrno.h"
+#include "py/qstr.h"
+#include "py/objstr.h"
+#include "py/objarray.h"
+#include "py/stream.h"
+#include "py/binary.h"
+#include "py/ringbuf.h"
+
+#include "mpconfigport.h"
+
+#include "modespnow.h"
+
+// For the esp8266
+#define ESP_NOW_MAX_DATA_LEN (250)
+#define ESP_NOW_KEY_LEN (16)
+#define ESP_NOW_ETH_ALEN (6)
+#define ESP_NOW_SEND_SUCCESS (0)
+#define ESP_ERR_ESPNOW_NO_MEM (-77777)
+#define ESP_OK (0)
+#define ESP_NOW_MAX_TOTAL_PEER_NUM (20)
+#define ESP_NOW_MAX_ENCRYPT_PEER_NUM (6)
+#define ESP_ERR_ESPNOW_NOT_INIT (0x300 + 100 + 1)
+typedef int esp_err_t;
+
+static const uint8_t ESPNOW_MAGIC = 0x99;
+
+// Use this for peeking at the header of the next packet in the buffer.
+typedef struct {
+ uint8_t magic; // = ESPNOW_MAGIC
+ uint8_t msg_len; // Length of the message
+} __attribute__((packed)) espnow_hdr_t;
+
+// ESPNow packet format for the receive buffer.
+typedef struct {
+ espnow_hdr_t hdr; // The header
+ uint8_t peer[6]; // Peer address
+ uint8_t msg[0]; // Message is up to 250 bytes
+} __attribute__((packed)) espnow_pkt_t;
+
+// The maximum length of an espnow packet (bytes)
+static const size_t MAX_PACKET_LEN = (
+ sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN);
+
+// Enough for 2 full-size packets: 2 * (6 + 2 + 250) = 516 bytes
+// Will allocate an additional 7 bytes for buffer overhead
+#define DEFAULT_RECV_BUFFER_SIZE \
+ (2 * (sizeof(espnow_pkt_t) + ESP_NOW_MAX_DATA_LEN))
+
+// Default timeout (millisec) to wait for incoming ESPNow messages (5 minutes).
+#define DEFAULT_RECV_TIMEOUT_MS (5 * 60 * 1000)
+
+// Number of milliseconds to wait for pending responses to sent packets.
+// This is a fallback which should never be reached.
+#define PENDING_RESPONSES_TIMEOUT_MS 100
+
+// The data structure for the espnow_singleton.
+typedef struct _esp_espnow_obj_t {
+ mp_obj_base_t base;
+ ringbuf_t *recv_buffer; // A buffer for received packets
+ size_t recv_buffer_size; // Size of recv buffer
+ size_t recv_timeout_ms; // Timeout for irecv()
+ size_t tx_packets; // Count of sent packets
+ volatile size_t tx_responses; // # of sent packet responses received
+ volatile size_t tx_failures; // # of sent packet responses failed
+} esp_espnow_obj_t;
+
+// Initialised below.
+const mp_obj_type_t esp_espnow_type;
+
+static esp_espnow_obj_t espnow_singleton = {
+ .base.type = &esp_espnow_type,
+ .recv_buffer = NULL,
+ .recv_buffer_size = DEFAULT_RECV_BUFFER_SIZE,
+ .recv_timeout_ms = DEFAULT_RECV_TIMEOUT_MS,
+};
+
+// ### Initialisation and Config functions
+//
+
+static void check_esp_err(int e) {
+ if (e != 0) {
+ mp_raise_OSError(e);
+ }
+}
+
+// Return a pointer to the ESPNow module singleton
+// If state == INITIALISED check the device has been initialised.
+// Raises OSError if not initialised and state == INITIALISED.
+static esp_espnow_obj_t *_get_singleton() {
+ return &espnow_singleton;
+}
+
+static esp_espnow_obj_t *_get_singleton_initialised() {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (self->recv_buffer == NULL) {
+ // Throw an espnow not initialised error
+ check_esp_err(ESP_ERR_ESPNOW_NOT_INIT);
+ }
+ return self;
+}
+
+// Allocate and initialise the ESPNow module as a singleton.
+// Returns the initialised espnow_singleton.
+STATIC mp_obj_t espnow_make_new(const mp_obj_type_t *type, size_t n_args,
+ size_t n_kw, const mp_obj_t *all_args) {
+
+ return _get_singleton();
+}
+
+// Forward declare the send and recv ESPNow callbacks
+STATIC void send_cb(uint8_t *mac_addr, uint8_t status);
+
+STATIC void recv_cb(uint8_t *mac_addr, uint8_t *data, uint8_t len);
+
+// ESPNow.deinit(): De-initialise the ESPNOW software stack, disable callbacks
+// and deallocate the recv data buffers.
+// Note: this function is called from main.c:mp_task() to cleanup before soft
+// reset, so cannot be declared STATIC and must guard against self == NULL;.
+mp_obj_t espnow_deinit(mp_obj_t _) {
+ esp_espnow_obj_t *self = _get_singleton();
+ if (self->recv_buffer != NULL) {
+ // esp_now_unregister_recv_cb();
+ esp_now_deinit();
+ self->recv_buffer->buf = NULL;
+ self->recv_buffer = NULL;
+ self->tx_packets = self->tx_responses;
+ }
+ MP_STATE_PORT(espnow_buffer) = NULL;
+ return mp_const_none;
+}
+
+// ESPNow.active(): Initialise the data buffers and ESP-NOW functions.
+// Initialise the Espressif ESPNOW software stack, register callbacks and
+// allocate the recv data buffers.
+// Returns True if interface is active, else False.
+STATIC mp_obj_t espnow_active(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = args[0];
+ if (n_args > 1) {
+ if (mp_obj_is_true(args[1])) {
+ if (self->recv_buffer == NULL) { // Already initialised
+ self->recv_buffer = m_new_obj(ringbuf_t);
+ ringbuf_alloc(self->recv_buffer, self->recv_buffer_size);
+ MP_STATE_PORT(espnow_buffer) = self->recv_buffer;
+ esp_now_init();
+ esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
+ esp_now_register_recv_cb(recv_cb);
+ esp_now_register_send_cb(send_cb);
+ }
+ } else {
+ espnow_deinit(self);
+ }
+ }
+ return mp_obj_new_bool(self->recv_buffer != NULL);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_active_obj, 1, 2, espnow_active);
+
+// ESPNow.config(): Initialise the data buffers and ESP-NOW functions.
+// Initialise the Espressif ESPNOW software stack, register callbacks and
+// allocate the recv data buffers.
+// Returns True if interface is active, else False.
+STATIC mp_obj_t espnow_config(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ esp_espnow_obj_t *self = _get_singleton();
+ enum { ARG_rxbuf, ARG_timeout_ms };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_rxbuf, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_timeout_ms, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
+ MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ if (args[ARG_rxbuf].u_int >= 0) {
+ self->recv_buffer_size = args[ARG_rxbuf].u_int;
+ }
+ if (args[ARG_timeout_ms].u_int >= 0) {
+ self->recv_timeout_ms = args[ARG_timeout_ms].u_int;
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(espnow_config_obj, 1, espnow_config);
+
+// ### The ESP_Now send and recv callback routines
+//
+
+// Callback triggered when a sent packet is acknowledged by the peer (or not).
+// Just count the number of responses and number of failures.
+// These are used in the send()/write() logic.
+STATIC void send_cb(uint8_t *mac_addr, uint8_t status) {
+ esp_espnow_obj_t *self = _get_singleton();
+ self->tx_responses++;
+ if (status != ESP_NOW_SEND_SUCCESS) {
+ self->tx_failures++;
+ }
+}
+
+// Callback triggered when an ESP-Now packet is received.
+// Write the peer MAC address and the message into the recv_buffer as an
+// ESPNow packet.
+// If the buffer is full, drop the message and increment the dropped count.
+// Schedules the user callback if one has been registered (ESPNow.config()).
+STATIC void recv_cb(uint8_t *mac_addr, uint8_t *msg, uint8_t msg_len) {
+ esp_espnow_obj_t *self = _get_singleton();
+ ringbuf_t *buf = self->recv_buffer;
+ // TODO: Test this works with ">".
+ if (buf == NULL || sizeof(espnow_pkt_t) + msg_len >= ringbuf_free(buf)) {
+ return;
+ }
+ espnow_hdr_t header;
+ header.magic = ESPNOW_MAGIC;
+ header.msg_len = msg_len;
+
+ ringbuf_put_bytes(buf, (uint8_t *)&header, sizeof(header));
+ ringbuf_put_bytes(buf, mac_addr, ESP_NOW_ETH_ALEN);
+ ringbuf_put_bytes(buf, msg, msg_len);
+}
+
+// Return C pointer to byte memory string/bytes/bytearray in obj.
+// Raise ValueError if the length does not match expected len.
+static uint8_t *_get_bytes_len_rw(mp_obj_t obj, size_t len, mp_uint_t rw) {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(obj, &bufinfo, rw);
+ if (bufinfo.len != len) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
+ }
+ return (uint8_t *)bufinfo.buf;
+}
+
+static uint8_t *_get_bytes_len(mp_obj_t obj, size_t len) {
+ return _get_bytes_len_rw(obj, len, MP_BUFFER_READ);
+}
+
+static uint8_t *_get_bytes_len_w(mp_obj_t obj, size_t len) {
+ return _get_bytes_len_rw(obj, len, MP_BUFFER_WRITE);
+}
+
+// ### Handling espnow packets in the recv buffer
+//
+
+// Copy data from the ring buffer - wait if buffer is empty up to timeout_ms
+// 0: Success
+// -1: Not enough data available to complete read (try again later)
+// -2: Requested read is larger than buffer - will never succeed
+static int ringbuf_get_bytes_wait(ringbuf_t *r, uint8_t *data, size_t len, mp_int_t timeout_ms) {
+ mp_uint_t start = mp_hal_ticks_ms();
+ int status = 0;
+ while (((status = ringbuf_get_bytes(r, data, len)) == -1)
+ && (timeout_ms < 0 || (mp_uint_t)(mp_hal_ticks_ms() - start) < (mp_uint_t)timeout_ms)) {
+ MICROPY_EVENT_POLL_HOOK;
+ }
+ return status;
+}
+
+// ESPNow.recvinto([timeout_ms, []]):
+// Returns a list of byte strings: (peer_addr, message) where peer_addr is
+// the MAC address of the sending peer.
+// Arguments:
+// timeout_ms: timeout in milliseconds (or None).
+// buffers: list of bytearrays to store values: [peer, message].
+// Default timeout is set with ESPNow.config(timeout=milliseconds).
+// Return (None, None) on timeout.
+STATIC mp_obj_t espnow_recvinto(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ size_t timeout_ms = ((n_args > 2 && args[2] != mp_const_none)
+ ? mp_obj_get_int(args[2]) : self->recv_timeout_ms);
+
+ mp_obj_list_t *list = MP_OBJ_TO_PTR(args[1]);
+ if (!mp_obj_is_type(list, &mp_type_list) || list->len < 2) {
+ mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recvinto(): Invalid argument"));
+ }
+ mp_obj_array_t *msg = MP_OBJ_TO_PTR(list->items[1]);
+ size_t msg_size = msg->len + msg->free;
+ if (mp_obj_is_type(msg, &mp_type_bytearray)) {
+ msg->len = msg_size; // Make all the space in msg array available
+ msg->free = 0;
+ }
+ uint8_t *peer_buf = _get_bytes_len_w(list->items[0], ESP_NOW_ETH_ALEN);
+ uint8_t *msg_buf = _get_bytes_len_w(msg, ESP_NOW_MAX_DATA_LEN);
+
+ // Read the packet header from the incoming buffer
+ espnow_hdr_t hdr;
+ if (ringbuf_get_bytes_wait(self->recv_buffer, (uint8_t *)&hdr, sizeof(hdr), timeout_ms) < 0) {
+ return MP_OBJ_NEW_SMALL_INT(0); // Timeout waiting for packet
+ }
+ int msg_len = hdr.msg_len;
+
+ // Check the message packet header format and read the message data
+ if (hdr.magic != ESPNOW_MAGIC
+ || msg_len > ESP_NOW_MAX_DATA_LEN
+ || ringbuf_get_bytes(self->recv_buffer, peer_buf, ESP_NOW_ETH_ALEN) < 0
+ || ringbuf_get_bytes(self->recv_buffer, msg_buf, msg_len) < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("ESPNow.recv(): buffer error"));
+ }
+ if (mp_obj_is_type(msg, &mp_type_bytearray)) {
+ // Set the length of the message bytearray.
+ msg->len = msg_len;
+ msg->free = msg_size - msg_len;
+ }
+
+ return MP_OBJ_NEW_SMALL_INT(msg_len);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_recvinto_obj, 2, 3, espnow_recvinto);
+
+// Used by espnow_send() for sends() with sync==True.
+// Wait till all pending sent packet responses have been received.
+// ie. self->tx_responses == self->tx_packets.
+// Return the number of responses where status != ESP_NOW_SEND_SUCCESS.
+static void _wait_for_pending_responses(esp_espnow_obj_t *self) {
+ for (int i = 0; i < PENDING_RESPONSES_TIMEOUT_MS; i++) {
+ if (self->tx_responses >= self->tx_packets) {
+ return;
+ }
+ mp_hal_delay_ms(1); // Allow other tasks to run
+ }
+ // Note: the loop timeout is just a fallback - in normal operation
+ // we should never reach that timeout.
+}
+
+// ESPNow.send(peer_addr, message, [sync (=true)])
+// ESPNow.send(message)
+// Send a message to the peer's mac address. Optionally wait for a response.
+// If sync == True, wait for response after sending.
+// Returns:
+// True if sync==False and message sent successfully.
+// True if sync==True and message is received successfully by all recipients
+// False if sync==True and message is not received by at least one recipient
+// Raises: EAGAIN if the internal espnow buffers are full.
+STATIC mp_obj_t espnow_send(size_t n_args, const mp_obj_t *args) {
+ esp_espnow_obj_t *self = _get_singleton_initialised();
+
+ bool sync = n_args <= 3 || args[3] == mp_const_none || mp_obj_is_true(args[3]);
+ // Get a pointer to the buffer of obj
+ mp_buffer_info_t message;
+ mp_get_buffer_raise(args[2], &message, MP_BUFFER_READ);
+
+ // Bugfix: esp_now_send() generates a panic if message buffer points
+ // to an address in ROM (eg. a statically interned QSTR).
+ // Fix: if message is not in gc pool, copy to a temp buffer.
+ static char temp[ESP_NOW_MAX_DATA_LEN]; // Static to save code space
+ byte *p = (byte *)message.buf;
+ // if (p < MP_STATE_MEM(area.gc_pool_start) || MP_STATE_MEM(area.gc_pool_end) < p) {
+ if (MP_STATE_MEM(area.gc_pool_end) < p) {
+ // If buffer is not in GC pool copy from ROM to stack
+ memcpy(temp, message.buf, message.len);
+ message.buf = temp;
+ }
+
+ if (sync) {
+ // If the last call was sync==False there may be outstanding responses.
+ // We need to wait for all pending responses if this call has sync=True.
+ _wait_for_pending_responses(self);
+ }
+ int saved_failures = self->tx_failures;
+
+ check_esp_err(
+ esp_now_send(_get_bytes_len(args[1], ESP_NOW_ETH_ALEN), message.buf, message.len));
+ self->tx_packets++;
+ if (sync) {
+ // Wait for message to be received by peer
+ _wait_for_pending_responses(self);
+ }
+ // Return False if sync and any peers did not respond.
+ return mp_obj_new_bool(!(sync && self->tx_failures != saved_failures));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_send_obj, 3, 4, espnow_send);
+
+// ### Peer Management Functions
+//
+
+// Set the ESP-NOW Primary Master Key (pmk) (for encrypted communications).
+// Raise OSError if not initialised.
+// Raise ValueError if key is not a bytes-like object exactly 16 bytes long.
+STATIC mp_obj_t espnow_set_pmk(mp_obj_t _, mp_obj_t key) {
+ check_esp_err(esp_now_set_kok(_get_bytes_len(key, ESP_NOW_KEY_LEN), ESP_NOW_KEY_LEN));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_set_pmk_obj, espnow_set_pmk);
+
+// ESPNow.add_peer(peer_mac, [lmk, [channel, [ifidx, [encrypt]]]])
+// Positional args set to None will be left at defaults.
+// Raise OSError if not initialised.
+// Raise ValueError if mac or LMK are not bytes-like objects or wrong length.
+// Raise TypeError if invalid keyword args or too many positional args.
+// Return None.
+STATIC mp_obj_t espnow_add_peer(size_t n_args, const mp_obj_t *args) {
+ check_esp_err(
+ esp_now_add_peer(
+ _get_bytes_len(args[1], ESP_NOW_ETH_ALEN),
+ ESP_NOW_ROLE_COMBO,
+ (n_args > 3) ? mp_obj_get_int(args[3]) : 0,
+ (n_args > 2) ? _get_bytes_len(args[2], ESP_NOW_KEY_LEN) : NULL,
+ ESP_NOW_KEY_LEN));
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(espnow_add_peer_obj, 2, 4, espnow_add_peer);
+
+// ESPNow.del_peer(peer_mac): Unregister peer_mac.
+// Raise OSError if not initialised.
+// Raise ValueError if peer is not a bytes-like objects or wrong length.
+// Return None.
+STATIC mp_obj_t espnow_del_peer(mp_obj_t _, mp_obj_t peer) {
+ esp_now_del_peer(_get_bytes_len(peer, ESP_NOW_ETH_ALEN));
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(espnow_del_peer_obj, espnow_del_peer);
+
+STATIC const mp_rom_map_elem_t esp_espnow_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&espnow_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&espnow_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_recvinto), MP_ROM_PTR(&espnow_recvinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&espnow_send_obj) },
+
+ // Peer management functions
+ { MP_ROM_QSTR(MP_QSTR_set_pmk), MP_ROM_PTR(&espnow_set_pmk_obj) },
+ { MP_ROM_QSTR(MP_QSTR_add_peer), MP_ROM_PTR(&espnow_add_peer_obj) },
+ { MP_ROM_QSTR(MP_QSTR_del_peer), MP_ROM_PTR(&espnow_del_peer_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(esp_espnow_locals_dict, esp_espnow_locals_dict_table);
+
+STATIC const mp_rom_map_elem_t espnow_globals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__espnow) },
+ { MP_ROM_QSTR(MP_QSTR_ESPNowBase), MP_ROM_PTR(&esp_espnow_type) },
+ { MP_ROM_QSTR(MP_QSTR_MAX_DATA_LEN), MP_ROM_INT(ESP_NOW_MAX_DATA_LEN)},
+ { MP_ROM_QSTR(MP_QSTR_ADDR_LEN), MP_ROM_INT(ESP_NOW_ETH_ALEN)},
+ { MP_ROM_QSTR(MP_QSTR_KEY_LEN), MP_ROM_INT(ESP_NOW_KEY_LEN)},
+ { MP_ROM_QSTR(MP_QSTR_MAX_TOTAL_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_TOTAL_PEER_NUM)},
+ { MP_ROM_QSTR(MP_QSTR_MAX_ENCRYPT_PEER_NUM), MP_ROM_INT(ESP_NOW_MAX_ENCRYPT_PEER_NUM)},
+};
+STATIC MP_DEFINE_CONST_DICT(espnow_globals_dict, espnow_globals_dict_table);
+
+// ### Dummy Buffer Protocol support
+// ...so asyncio can poll.ipoll() on this device
+
+// Support ioctl(MP_STREAM_POLL, ) for asyncio
+STATIC mp_uint_t espnow_stream_ioctl(mp_obj_t self_in, mp_uint_t request,
+ uintptr_t arg, int *errcode) {
+ if (request != MP_STREAM_POLL) {
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+ esp_espnow_obj_t *self = _get_singleton();
+ return (self->recv_buffer == NULL) ? 0 : // If not initialised
+ arg ^ ((ringbuf_avail(self->recv_buffer) == 0) ? MP_STREAM_POLL_RD : 0);
+}
+
+STATIC const mp_stream_p_t espnow_stream_p = {
+ .ioctl = espnow_stream_ioctl,
+};
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ esp_espnow_type,
+ MP_QSTR_ESPNowBase,
+ MP_TYPE_FLAG_NONE,
+ make_new, espnow_make_new,
+ protocol, &espnow_stream_p,
+ locals_dict, &esp_espnow_locals_dict
+ );
+
+const mp_obj_module_t mp_module_espnow = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&espnow_globals_dict,
+};
+
+MP_REGISTER_MODULE(MP_QSTR__espnow, mp_module_espnow);
+MP_REGISTER_ROOT_POINTER(void *espnow_buffer);
+#endif
diff --git a/ports/esp8266/modespnow.h b/ports/esp8266/modespnow.h
new file mode 100644
index 000000000000..b42a615db885
--- /dev/null
+++ b/ports/esp8266/modespnow.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Glenn Moloney @glenn20
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Called from main.c:mp_task() to reset the espnow software stack
+mp_obj_t espnow_deinit(mp_obj_t _);
diff --git a/ports/esp8266/modmachine.c b/ports/esp8266/modmachine.c
index af46cbbfe747..64346b4debdc 100644
--- a/ports/esp8266/modmachine.c
+++ b/ports/esp8266/modmachine.c
@@ -31,6 +31,7 @@
#include "py/obj.h"
#include "py/runtime.h"
#include "shared/runtime/pyexec.h"
+#include "drivers/dht/dht.h"
// This needs to be set before we include the RTOS headers
#define USE_US_TIMER 1
@@ -395,7 +396,7 @@ mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t
}
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
@@ -418,6 +419,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#endif
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
@@ -454,6 +456,6 @@ const mp_obj_module_t mp_module_machine = {
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_umachine, mp_module_machine);
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
#endif // MICROPY_PY_MACHINE
diff --git a/ports/esp8266/modmachine.h b/ports/esp8266/modmachine.h
index 4a73d3b8e801..9b7a5e3cb226 100644
--- a/ports/esp8266/modmachine.h
+++ b/ports/esp8266/modmachine.h
@@ -21,6 +21,16 @@ typedef struct _pyb_pin_obj_t {
const pyb_pin_obj_t pyb_pin_obj[16 + 1];
+#define GPIO_MODE_INPUT (0)
+#define GPIO_MODE_OUTPUT (1)
+#define GPIO_MODE_OPEN_DRAIN (2) // synthesised
+#define GPIO_PULL_NONE (0)
+#define GPIO_PULL_UP (1)
+// Removed in SDK 1.1.0
+// #define GPIO_PULL_DOWN (2)
+
+extern uint8_t pin_mode[16 + 1];
+
void pin_init0(void);
uint mp_obj_get_pin(mp_obj_t pin_in);
diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c
deleted file mode 100644
index ec62528a0834..000000000000
--- a/ports/esp8266/modnetwork.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015-2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-#include
-
-#include "py/objlist.h"
-#include "py/runtime.h"
-#include "py/mphal.h"
-#include "shared/netutils/netutils.h"
-#include "queue.h"
-#include "user_interface.h"
-#include "espconn.h"
-#include "spi_flash.h"
-#include "ets_alt_task.h"
-#include "lwip/dns.h"
-
-#define MODNETWORK_INCLUDE_CONSTANTS (1)
-
-typedef struct _wlan_if_obj_t {
- mp_obj_base_t base;
- int if_id;
-} wlan_if_obj_t;
-
-void error_check(bool status, const char *msg);
-const mp_obj_type_t wlan_if_type;
-
-STATIC const wlan_if_obj_t wlan_objs[] = {
- {{&wlan_if_type}, STATION_IF},
- {{&wlan_if_type}, SOFTAP_IF},
-};
-
-STATIC void require_if(mp_obj_t wlan_if, int if_no) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
- if (self->if_id != if_no) {
- error_check(false, if_no == STATION_IF ? "STA required" : "AP required");
- }
-}
-
-STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args) {
- int idx = 0;
- if (n_args > 0) {
- idx = mp_obj_get_int(args[0]);
- if (idx < 0 || idx >= sizeof(wlan_objs)) {
- mp_raise_ValueError(NULL);
- }
- }
- return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
-
-STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- uint32_t mode = wifi_get_opmode();
- if (n_args > 1) {
- int mask = self->if_id == STATION_IF ? STATION_MODE : SOFTAP_MODE;
- if (mp_obj_get_int(args[1]) != 0) {
- mode |= mask;
- } else {
- mode &= ~mask;
- }
- if (mode != NULL_MODE) {
- wifi_fpm_do_wakeup();
- wifi_fpm_close();
- }
- error_check(wifi_set_opmode(mode), "Cannot update i/f status");
- if (mode == NULL_MODE) {
- // Wait for the interfaces to go down before forcing power management
- while (wifi_get_opmode() != NULL_MODE) {
- ets_loop_iter();
- }
- wifi_fpm_open();
- wifi_fpm_do_sleep(0xfffffff);
- }
- return mp_const_none;
- }
-
- // Get active status
- if (self->if_id == STATION_IF) {
- return mp_obj_new_bool(mode & STATION_MODE);
- } else {
- return mp_obj_new_bool(mode & SOFTAP_MODE);
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
-
-STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_ssid, ARG_key, ARG_bssid };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
- { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
- };
-
- // parse args
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- require_if(pos_args[0], STATION_IF);
- struct station_config config = {{0}};
- size_t len;
- const char *p;
- bool set_config = false;
-
- // set parameters based on given args
- if (args[ARG_ssid].u_obj != mp_const_none) {
- p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
- len = MIN(len, sizeof(config.ssid));
- memcpy(config.ssid, p, len);
- set_config = true;
- }
- if (args[ARG_key].u_obj != mp_const_none) {
- p = mp_obj_str_get_data(args[ARG_key].u_obj, &len);
- len = MIN(len, sizeof(config.password));
- memcpy(config.password, p, len);
- set_config = true;
- }
- if (args[ARG_bssid].u_obj != mp_const_none) {
- p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
- if (len != sizeof(config.bssid)) {
- mp_raise_ValueError(NULL);
- }
- config.bssid_set = 1;
- memcpy(config.bssid, p, sizeof(config.bssid));
- set_config = true;
- }
-
- if (set_config) {
- error_check(wifi_station_set_config(&config), "Cannot set STA config");
- }
- error_check(wifi_station_connect(), "Cannot connect to AP");
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect);
-
-STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
- require_if(self_in, STATION_IF);
- error_check(wifi_station_disconnect(), "Cannot disconnect from AP");
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
-
-STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- if (n_args == 1) {
- // Get link status
- if (self->if_id == STATION_IF) {
- return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
- }
- return MP_OBJ_NEW_SMALL_INT(-1);
- } else {
- // Get specific status parameter
- switch (mp_obj_str_get_qstr(args[1])) {
- case MP_QSTR_rssi:
- if (self->if_id == STATION_IF) {
- return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi());
- }
- }
- mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
-
-STATIC mp_obj_t *esp_scan_list = NULL;
-
-STATIC void esp_scan_cb(void *result, STATUS status) {
- if (esp_scan_list == NULL) {
- // called unexpectedly
- return;
- }
- if (result && status == 0) {
- // we need to catch any memory errors
- nlr_buf_t nlr;
- if (nlr_push(&nlr) == 0) {
- for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) {
- mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
- #if 1
- // struct bss_info::ssid_len is not documented in SDK API Guide,
- // but is present in SDK headers since 1.4.0
- t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len);
- #else
- t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char *)bs->ssid));
- #endif
- t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid));
- t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel);
- t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi);
- t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode);
- t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden);
- mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
- }
- nlr_pop();
- } else {
- mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
- // indicate error
- *esp_scan_list = MP_OBJ_NULL;
- }
- } else {
- // indicate error
- *esp_scan_list = MP_OBJ_NULL;
- }
- esp_scan_list = NULL;
-}
-
-STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
- require_if(self_in, STATION_IF);
- if ((wifi_get_opmode() & STATION_MODE) == 0) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
- }
- mp_obj_t list = mp_obj_new_list(0, NULL);
- esp_scan_list = &list;
- struct scan_config config = {0};
- config.show_hidden = 1;
- wifi_station_scan(&config, (scan_done_cb_t)esp_scan_cb);
- while (esp_scan_list != NULL) {
- // our esp_scan_cb is called via ets_loop_iter so it's safe to set the
- // esp_scan_list variable to NULL without disabling interrupts
- if (MP_STATE_THREAD(mp_pending_exception) != NULL) {
- esp_scan_list = NULL;
- mp_handle_pending(true);
- }
- ets_loop_iter();
- }
- if (list == MP_OBJ_NULL) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("scan failed"));
- }
- return list;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
-
-/// \method isconnected()
-/// Return True if connected to an AP and an IP address has been assigned,
-/// false otherwise.
-STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->if_id == STATION_IF) {
- if (wifi_station_get_connect_status() == STATION_GOT_IP) {
- return mp_const_true;
- }
- } else {
- if (wifi_softap_get_station_num() > 0) {
- return mp_const_true;
- }
- }
- return mp_const_false;
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
-
-STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- struct ip_info info;
- ip_addr_t dns_addr;
- wifi_get_ip_info(self->if_id, &info);
- if (n_args == 1) {
- // get
- dns_addr = dns_getserver(0);
- mp_obj_t tuple[4] = {
- netutils_format_ipv4_addr((uint8_t *)&info.ip, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&info.netmask, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&info.gw, NETUTILS_BIG),
- netutils_format_ipv4_addr((uint8_t *)&dns_addr, NETUTILS_BIG),
- };
- return mp_obj_new_tuple(4, tuple);
- } else if (args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) {
- // use DHCP to configure the IP addresses
- require_if(args[0], STATION_IF);
- wifi_station_dhcpc_start();
- return mp_const_none;
- } else {
- // set
- mp_obj_t *items;
- bool restart_dhcp_server = false;
- mp_obj_get_array_fixed_n(args[1], 4, &items);
- netutils_parse_ipv4_addr(items[0], (void *)&info.ip, NETUTILS_BIG);
- if (mp_obj_is_integer(items[1])) {
- // allow numeric netmask, i.e.:
- // 24 -> 255.255.255.0
- // 16 -> 255.255.0.0
- // etc...
- uint32_t *m = (uint32_t *)&info.netmask;
- *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
- } else {
- netutils_parse_ipv4_addr(items[1], (void *)&info.netmask, NETUTILS_BIG);
- }
- netutils_parse_ipv4_addr(items[2], (void *)&info.gw, NETUTILS_BIG);
- netutils_parse_ipv4_addr(items[3], (void *)&dns_addr, NETUTILS_BIG);
- // To set a static IP we have to disable DHCP first
- if (self->if_id == STATION_IF) {
- wifi_station_dhcpc_stop();
- } else {
- restart_dhcp_server = wifi_softap_dhcps_status();
- wifi_softap_dhcps_stop();
- }
- if (!wifi_set_ip_info(self->if_id, &info)) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("wifi_set_ip_info() failed"));
- }
- dns_setserver(0, &dns_addr);
- if (restart_dhcp_server) {
- wifi_softap_dhcps_start();
- }
- return mp_const_none;
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
-
-STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
- if (n_args != 1 && kwargs->used != 0) {
- mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
- }
-
- wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- union {
- struct station_config sta;
- struct softap_config ap;
- } cfg;
-
- if (self->if_id == STATION_IF) {
- error_check(wifi_station_get_config(&cfg.sta), "can't get STA config");
- } else {
- error_check(wifi_softap_get_config(&cfg.ap), "can't get AP config");
- }
-
- int req_if = -1;
-
- if (kwargs->used != 0) {
-
- for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
- if (mp_map_slot_is_filled(kwargs, i)) {
- switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
- case MP_QSTR_mac: {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
- if (bufinfo.len != 6) {
- mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
- }
- wifi_set_macaddr(self->if_id, bufinfo.buf);
- break;
- }
- case MP_QSTR_ssid:
- case MP_QSTR_essid: {
- req_if = SOFTAP_IF;
- size_t len;
- const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
- len = MIN(len, sizeof(cfg.ap.ssid));
- memcpy(cfg.ap.ssid, s, len);
- cfg.ap.ssid_len = len;
- break;
- }
- case MP_QSTR_hidden: {
- req_if = SOFTAP_IF;
- cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
- break;
- }
- case MP_QSTR_security:
- case MP_QSTR_authmode: {
- req_if = SOFTAP_IF;
- cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
- break;
- }
- case MP_QSTR_key:
- case MP_QSTR_password: {
- req_if = SOFTAP_IF;
- size_t len;
- const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
- len = MIN(len, sizeof(cfg.ap.password) - 1);
- memcpy(cfg.ap.password, s, len);
- cfg.ap.password[len] = 0;
- break;
- }
- case MP_QSTR_channel: {
- req_if = SOFTAP_IF;
- cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
- break;
- }
- case MP_QSTR_hostname:
- case MP_QSTR_dhcp_hostname: {
- req_if = STATION_IF;
- if (self->if_id == STATION_IF) {
- const char *s = mp_obj_str_get_str(kwargs->table[i].value);
- wifi_station_set_hostname((char *)s);
- }
- break;
- }
- case MP_QSTR_protocol: {
- wifi_set_phy_mode(mp_obj_get_int(kwargs->table[i].value));
- break;
- }
- default:
- goto unknown;
- }
- }
- }
-
- // We post-check interface requirements to save on code size
- if (req_if >= 0) {
- require_if(args[0], req_if);
- }
-
- if (self->if_id == STATION_IF) {
- error_check(wifi_station_set_config(&cfg.sta), "can't set STA config");
- } else {
- error_check(wifi_softap_set_config(&cfg.ap), "can't set AP config");
- }
-
- return mp_const_none;
- }
-
- // Get config
-
- if (n_args != 2) {
- mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
- }
-
- mp_obj_t val;
-
- qstr key = mp_obj_str_get_qstr(args[1]);
- switch (key) {
- case MP_QSTR_mac: {
- uint8_t mac[6];
- wifi_get_macaddr(self->if_id, mac);
- return mp_obj_new_bytes(mac, sizeof(mac));
- }
- case MP_QSTR_ssid:
- case MP_QSTR_essid:
- if (self->if_id == STATION_IF) {
- val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
- } else {
- val = mp_obj_new_str((char *)cfg.ap.ssid, cfg.ap.ssid_len);
- }
- break;
- case MP_QSTR_hidden:
- req_if = SOFTAP_IF;
- val = mp_obj_new_bool(cfg.ap.ssid_hidden);
- break;
- case MP_QSTR_security:
- case MP_QSTR_authmode:
- req_if = SOFTAP_IF;
- val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
- break;
- case MP_QSTR_channel:
- req_if = SOFTAP_IF;
- val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
- break;
- case MP_QSTR_hostname:
- case MP_QSTR_dhcp_hostname: {
- req_if = STATION_IF;
- char *s = wifi_station_get_hostname();
- if (s == NULL) {
- val = MP_OBJ_NEW_QSTR(MP_QSTR_);
- } else {
- val = mp_obj_new_str(s, strlen(s));
- }
- break;
- }
- case MP_QSTR_protocol: {
- val = mp_obj_new_int(wifi_get_phy_mode());
- break;
- }
- default:
- goto unknown;
- }
-
- // We post-check interface requirements to save on code size
- if (req_if >= 0) {
- require_if(args[0], req_if);
- }
-
- return val;
-
-unknown:
- mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
-
-STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
- { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
- { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
- { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
- { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
- { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
- { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
- { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
-
-MP_DEFINE_CONST_OBJ_TYPE(
- wlan_if_type,
- MP_QSTR_WLAN,
- MP_TYPE_FLAG_NONE,
- locals_dict, &wlan_if_locals_dict
- );
-
-STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
- if (n_args == 0) {
- return mp_obj_new_int(wifi_get_phy_mode());
- } else {
- wifi_set_phy_mode(mp_obj_get_int(args[0]));
- return mp_const_none;
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_phy_mode_obj, 0, 1, esp_phy_mode);
-
-STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
- { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
- { MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_phy_mode_obj) },
-
- #if MODNETWORK_INCLUDE_CONSTANTS
- { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},
- { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},
-
- { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},
- { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},
- { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},
- { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},
- { MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},
- { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},
-
- { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },
- { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },
- { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },
-
- { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },
- { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
- #endif
-};
-
-STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals_table);
-
-const mp_obj_module_t network_module = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&mp_module_network_globals,
-};
-
-// Note: This port doesn't define MICROPY_PY_NETWORK so this will not conflict
-// with the common implementation provided by extmod/modnetwork.c.
-MP_REGISTER_MODULE(MP_QSTR_network, network_module);
diff --git a/ports/esp8266/modnetwork.h b/ports/esp8266/modnetwork.h
new file mode 100644
index 000000000000..5fd142e71eef
--- /dev/null
+++ b/ports/esp8266/modnetwork.h
@@ -0,0 +1,3 @@
+extern const mp_obj_type_t esp_network_wlan_type;
+
+MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_phy_mode_obj);
diff --git a/ports/esp8266/modnetwork_globals.h b/ports/esp8266/modnetwork_globals.h
new file mode 100644
index 000000000000..1a04568024b5
--- /dev/null
+++ b/ports/esp8266/modnetwork_globals.h
@@ -0,0 +1,22 @@
+{ MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&esp_network_wlan_type) },
+{ MP_ROM_QSTR(MP_QSTR_phy_mode), MP_ROM_PTR(&esp_network_phy_mode_obj) },
+
+{ MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(STATION_IF)},
+{ MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(SOFTAP_IF)},
+
+{ MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STATION_IDLE)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STATION_CONNECTING)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(STATION_WRONG_PASSWORD)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(STATION_NO_AP_FOUND)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_CONNECT_FAIL), MP_ROM_INT(STATION_CONNECT_FAIL)},
+{ MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STATION_GOT_IP)},
+
+{ MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(PHY_MODE_11B) },
+{ MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(PHY_MODE_11G) },
+{ MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(PHY_MODE_11N) },
+
+{ MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(AUTH_OPEN) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(AUTH_WEP) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(AUTH_WPA_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(AUTH_WPA2_PSK) },
+{ MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(AUTH_WPA_WPA2_PSK) },
diff --git a/ports/esp8266/modos.c b/ports/esp8266/modos.c
new file mode 100644
index 000000000000..78072d4f4486
--- /dev/null
+++ b/ports/esp8266/modos.c
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 Josef Gajdusek
+ * Copyright (c) 2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+
+#include "py/objtuple.h"
+#include "py/objstr.h"
+#include "extmod/misc.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat.h"
+#include "extmod/vfs_lfs.h"
+#include "genhdr/mpversion.h"
+#include "esp_mphal.h"
+#include "user_interface.h"
+
+STATIC const char *mp_os_uname_release(void) {
+ return system_get_sdk_version();
+}
+
+STATIC mp_obj_t mp_os_urandom(mp_obj_t num) {
+ mp_int_t n = mp_obj_get_int(num);
+ vstr_t vstr;
+ vstr_init_len(&vstr, n);
+ for (int i = 0; i < n; i++) {
+ vstr.buf[i] = *WDEV_HWRNG;
+ }
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);
+
+void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached) {
+ if (mp_obj_get_type(stream_attached) == &pyb_uart_type) {
+ ++uart_attached_to_dupterm;
+ }
+ if (mp_obj_get_type(stream_detached) == &pyb_uart_type) {
+ --uart_attached_to_dupterm;
+ }
+}
+
+STATIC mp_obj_t mp_os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ mp_hal_signal_dupterm_input();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_dupterm_notify_obj, mp_os_dupterm_notify);
diff --git a/ports/esp8266/modtime.c b/ports/esp8266/modtime.c
new file mode 100644
index 000000000000..21dd3cbcd909
--- /dev/null
+++ b/ports/esp8266/modtime.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2023 Damien P. George
+ * Copyright (c) 2015 Josef Gajdusek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "shared/timeutils/timeutils.h"
+#include "modmachine.h"
+
+// Return the localtime as an 8-tuple.
+STATIC mp_obj_t mp_time_localtime_get(void) {
+ mp_int_t seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000;
+ timeutils_struct_time_t tm;
+ timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
+ mp_obj_t tuple[8] = {
+ tuple[0] = mp_obj_new_int(tm.tm_year),
+ tuple[1] = mp_obj_new_int(tm.tm_mon),
+ tuple[2] = mp_obj_new_int(tm.tm_mday),
+ tuple[3] = mp_obj_new_int(tm.tm_hour),
+ tuple[4] = mp_obj_new_int(tm.tm_min),
+ tuple[5] = mp_obj_new_int(tm.tm_sec),
+ tuple[6] = mp_obj_new_int(tm.tm_wday),
+ tuple[7] = mp_obj_new_int(tm.tm_yday),
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+
+// Returns the number of seconds, as an integer, since the Epoch.
+STATIC mp_obj_t mp_time_time_get(void) {
+ // get date and time
+ return mp_obj_new_int(pyb_rtc_get_us_since_epoch() / 1000 / 1000);
+}
diff --git a/ports/esp8266/modules/_boot.py b/ports/esp8266/modules/_boot.py
index 1f77d8802463..06b372990a52 100644
--- a/ports/esp8266/modules/_boot.py
+++ b/ports/esp8266/modules/_boot.py
@@ -1,12 +1,12 @@
import gc
gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)
-import uos
+import os
from flashbdev import bdev
if bdev:
try:
- uos.mount(bdev, "/")
+ os.mount(bdev, "/")
except:
import inisetup
diff --git a/ports/esp8266/modules/espnow.py b/ports/esp8266/modules/espnow.py
new file mode 100644
index 000000000000..1d2b946552e7
--- /dev/null
+++ b/ports/esp8266/modules/espnow.py
@@ -0,0 +1,37 @@
+# espnow module for MicroPython on ESP8266
+# MIT license; Copyright (c) 2022 Glenn Moloney @glenn20
+
+from _espnow import *
+from select import poll, POLLIN
+
+
+class ESPNow(ESPNowBase):
+ # Static buffers for alloc free receipt of messages with ESPNow.irecv().
+ _data = [bytearray(ADDR_LEN), bytearray(MAX_DATA_LEN)]
+ _none_tuple = (None, None)
+
+ def __init__(self):
+ super().__init__()
+ self._poll = poll() # For any() method below...
+ self._poll.register(self, POLLIN)
+
+ def irecv(self, timeout_ms=None):
+ n = self.recvinto(self._data, timeout_ms)
+ return self._data if n else self._none_tuple
+
+ def recv(self, timeout_ms=None):
+ n = self.recvinto(self._data, timeout_ms)
+ return [bytes(x) for x in self._data] if n else self._none_tuple
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ return self.irecv() # Use alloc free irecv() method
+
+ def any(self): # For the ESP8266 which does not have ESPNow.any()
+ try:
+ next(self._poll.ipoll(0))
+ return True
+ except StopIteration:
+ return False
diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py
index e5ce00138ecc..3f3edcf6d0af 100644
--- a/ports/esp8266/modules/inisetup.py
+++ b/ports/esp8266/modules/inisetup.py
@@ -1,13 +1,13 @@
-import uos
+import os
import network
from flashbdev import bdev
def wifi():
- import ubinascii
+ import binascii
ap_if = network.WLAN(network.AP_IF)
- ssid = b"MicroPython-%s" % ubinascii.hexlify(ap_if.config("mac")[-3:])
+ ssid = b"MicroPython-%s" % binascii.hexlify(ap_if.config("mac")[-3:])
ap_if.config(ssid=ssid, security=network.AUTH_WPA_WPA2_PSK, key=b"micropythoN")
@@ -26,13 +26,17 @@ def check_bootsec():
def fs_corrupted():
import time
+ import micropython
+
+ # Allow this loop to be stopped via Ctrl-C.
+ micropython.kbd_intr(3)
while 1:
print(
"""\
The filesystem starting at sector %d with size %d sectors looks corrupt.
You may want to make a flash snapshot and try to recover it. Otherwise,
-format it with uos.VfsLfs2.mkfs(bdev), or completely erase the flash and
+format it with os.VfsLfs2.mkfs(bdev), or completely erase the flash and
reprogram MicroPython.
"""
% (bdev.start_sec, bdev.blocks)
@@ -44,17 +48,17 @@ def setup():
check_bootsec()
print("Performing initial setup")
wifi()
- uos.VfsLfs2.mkfs(bdev)
- vfs = uos.VfsLfs2(bdev)
- uos.mount(vfs, "/")
+ os.VfsLfs2.mkfs(bdev)
+ vfs = os.VfsLfs2(bdev)
+ os.mount(vfs, "/")
with open("boot.py", "w") as f:
f.write(
"""\
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
-import uos, machine
-#uos.dupterm(None, 1) # disable REPL on UART(0)
+import os, machine
+#os.dupterm(None, 1) # disable REPL on UART(0)
import gc
#import webrepl
#webrepl.start()
diff --git a/ports/esp8266/modules/port_diag.py b/ports/esp8266/modules/port_diag.py
index f2c69ecacd96..4eea6a6d90d3 100644
--- a/ports/esp8266/modules/port_diag.py
+++ b/ports/esp8266/modules/port_diag.py
@@ -5,7 +5,6 @@
def main():
-
ROM = uctypes.bytearray_at(0x40200000, 16)
fid = esp.flash_id()
diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c
deleted file mode 100644
index a023796fd3b6..000000000000
--- a/ports/esp8266/moduos.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2015 Josef Gajdusek
- * Copyright (c) 2016 Paul Sokolovsky
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-
-#include "py/objtuple.h"
-#include "py/objstr.h"
-#include "extmod/misc.h"
-#include "extmod/vfs.h"
-#include "extmod/vfs_fat.h"
-#include "extmod/vfs_lfs.h"
-#include "genhdr/mpversion.h"
-#include "esp_mphal.h"
-#include "user_interface.h"
-
-STATIC const char *mp_uos_uname_release(void) {
- return system_get_sdk_version();
-}
-
-STATIC mp_obj_t mp_uos_urandom(mp_obj_t num) {
- mp_int_t n = mp_obj_get_int(num);
- vstr_t vstr;
- vstr_init_len(&vstr, n);
- for (int i = 0; i < n; i++) {
- vstr.buf[i] = *WDEV_HWRNG;
- }
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_urandom_obj, mp_uos_urandom);
-
-void mp_uos_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t stream_attached) {
- if (mp_obj_get_type(stream_attached) == &pyb_uart_type) {
- ++uart_attached_to_dupterm;
- }
- if (mp_obj_get_type(stream_detached) == &pyb_uart_type) {
- --uart_attached_to_dupterm;
- }
-}
-
-STATIC mp_obj_t mp_uos_dupterm_notify(mp_obj_t obj_in) {
- (void)obj_in;
- mp_hal_signal_dupterm_input();
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_dupterm_notify_obj, mp_uos_dupterm_notify);
diff --git a/ports/esp8266/modutime.c b/ports/esp8266/modutime.c
deleted file mode 100644
index 08508f8818a6..000000000000
--- a/ports/esp8266/modutime.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- * Copyright (c) 2015 Josef Gajdusek
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include
-#include
-
-#include "py/gc.h"
-#include "py/runtime.h"
-#include "py/mphal.h"
-#include "py/smallint.h"
-#include "shared/timeutils/timeutils.h"
-#include "modmachine.h"
-#include "user_interface.h"
-#include "extmod/utime_mphal.h"
-
-/// \module time - time related functions
-///
-/// The `time` module provides functions for getting the current time and date,
-/// and for sleeping.
-
-/// \function localtime([secs])
-/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
-/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
-/// If secs is not provided or None, then the current time from the RTC is used.
-/// year includes the century (for example 2014)
-/// month is 1-12
-/// mday is 1-31
-/// hour is 0-23
-/// minute is 0-59
-/// second is 0-59
-/// weekday is 0-6 for Mon-Sun.
-/// yearday is 1-366
-STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
- timeutils_struct_time_t tm;
- mp_int_t seconds;
- if (n_args == 0 || args[0] == mp_const_none) {
- seconds = pyb_rtc_get_us_since_epoch() / 1000 / 1000;
- } else {
- seconds = mp_obj_get_int(args[0]);
- }
- timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
- mp_obj_t tuple[8] = {
- tuple[0] = mp_obj_new_int(tm.tm_year),
- tuple[1] = mp_obj_new_int(tm.tm_mon),
- tuple[2] = mp_obj_new_int(tm.tm_mday),
- tuple[3] = mp_obj_new_int(tm.tm_hour),
- tuple[4] = mp_obj_new_int(tm.tm_min),
- tuple[5] = mp_obj_new_int(tm.tm_sec),
- tuple[6] = mp_obj_new_int(tm.tm_wday),
- tuple[7] = mp_obj_new_int(tm.tm_yday),
- };
- return mp_obj_new_tuple(8, tuple);
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
-
-/// \function mktime()
-/// This is inverse function of localtime. It's argument is a full 8-tuple
-/// which expresses a time as per localtime. It returns an integer which is
-/// the number of seconds since Jan 1, 2000.
-STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
- size_t len;
- mp_obj_t *elem;
- mp_obj_get_array(tuple, &len, &elem);
-
- // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
- if (len < 8 || len > 9) {
- mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9 (%d given)"), len);
- }
-
- return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
- mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
- mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
-}
-MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
-
-/// \function time()
-/// Returns the number of seconds, as an integer, since the Epoch.
-STATIC mp_obj_t time_time(void) {
- // get date and time
- return mp_obj_new_int(pyb_rtc_get_us_since_epoch() / 1000 / 1000);
-}
-MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
-
-STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
-
- { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
- { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
- { MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
-
-const mp_obj_module_t utime_module = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&time_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_utime, utime_module);
diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h
index ded56663b32b..18b2e47e29dc 100644
--- a/ports/esp8266/mpconfigport.h
+++ b/ports/esp8266/mpconfigport.h
@@ -19,7 +19,6 @@
#define MICROPY_OPT_MATH_FACTORIAL (0)
#define MICROPY_REPL_EMACS_KEYS (0)
#define MICROPY_PY_BUILTINS_COMPLEX (0)
-#define MICROPY_MODULE_ATTR_DELEGATION (0)
#define MICROPY_PY_FUNCTION_ATTRS (0)
#define MICROPY_PY_DELATTR_SETATTR (0)
#define MICROPY_PY_BUILTINS_STR_CENTER (0)
@@ -36,8 +35,8 @@
#define MICROPY_PY_MATH_FACTORIAL (0)
#define MICROPY_PY_MATH_ISCLOSE (0)
#define MICROPY_PY_SYS_PS1_PS2 (0)
-#define MICROPY_PY_UBINASCII_CRC32 (0)
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS (0)
+#define MICROPY_PY_BINASCII_CRC32 (0)
+#define MICROPY_PY_RANDOM_EXTRA_FUNCS (0)
// Configure other options.
#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
@@ -54,9 +53,11 @@
#define MICROPY_REPL_EVENT_DRIVEN (0)
#define MICROPY_USE_INTERNAL_ERRNO (1)
#define MICROPY_PY_BUILTINS_HELP_TEXT esp_help_text
-#define MICROPY_PY_UHASHLIB_SHA1 (MICROPY_PY_USSL && MICROPY_SSL_AXTLS)
-#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (*WDEV_HWRNG)
-#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL && MICROPY_SSL_AXTLS)
+#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (*WDEV_HWRNG)
+#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
+#define MICROPY_PY_TIME_TIME_TIME_NS (1)
+#define MICROPY_PY_TIME_INCLUDEFILE "ports/esp8266/modtime.c"
#define MICROPY_PY_LWIP (1)
#define MICROPY_PY_LWIP_SOCK_RAW (1)
#define MICROPY_PY_MACHINE (1)
@@ -64,25 +65,31 @@
#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PWM (1)
-#define MICROPY_PY_MACHINE_PWM_INIT (1)
#define MICROPY_PY_MACHINE_PWM_DUTY (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/esp8266/machine_pwm.c"
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_SOFTI2C (1)
#define MICROPY_PY_MACHINE_SPI (1)
#define MICROPY_PY_MACHINE_SOFTSPI (1)
-#define MICROPY_PY_UWEBSOCKET (1)
+#define MICROPY_PY_NETWORK (1)
+#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-esp8266"
+#endif
+#define MICROPY_PY_NETWORK_INCLUDEFILE "ports/esp8266/modnetwork.h"
+#define MICROPY_PY_NETWORK_MODULE_GLOBALS_INCLUDEFILE "ports/esp8266/modnetwork_globals.h"
+#define MICROPY_PY_WEBSOCKET (1)
#define MICROPY_PY_ONEWIRE (1)
#define MICROPY_PY_WEBREPL (1)
#define MICROPY_PY_WEBREPL_DELAY (20)
#define MICROPY_PY_WEBREPL_STATIC_FILEBUF (1)
-#define MICROPY_PY_UOS_INCLUDEFILE "ports/esp8266/moduos.c"
+#define MICROPY_PY_OS_INCLUDEFILE "ports/esp8266/modos.c"
#define MICROPY_PY_OS_DUPTERM (2)
-#define MICROPY_PY_UOS_DUPTERM_NOTIFY (1)
-#define MICROPY_PY_UOS_DUPTERM_STREAM_DETACHED_ATTACHED (1)
-#define MICROPY_PY_UOS_UNAME (1)
-#define MICROPY_PY_UOS_UNAME_RELEASE_DYNAMIC (1)
-#define MICROPY_PY_UOS_URANDOM (1)
+#define MICROPY_PY_OS_DUPTERM_NOTIFY (1)
+#define MICROPY_PY_OS_DUPTERM_STREAM_DETACHED_ATTACHED (1)
+#define MICROPY_PY_OS_SYNC (1)
+#define MICROPY_PY_OS_UNAME (1)
+#define MICROPY_PY_OS_UNAME_RELEASE_DYNAMIC (1)
+#define MICROPY_PY_OS_URANDOM (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
#define MICROPY_WARNINGS (1)
diff --git a/ports/esp8266/network_wlan.c b/ports/esp8266/network_wlan.c
new file mode 100644
index 000000000000..348d7f63550c
--- /dev/null
+++ b/ports/esp8266/network_wlan.c
@@ -0,0 +1,547 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2016 Paul Sokolovsky
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include
+#include
+
+#include "py/objlist.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "extmod/modnetwork.h"
+#include "shared/netutils/netutils.h"
+#include "queue.h"
+#include "user_interface.h"
+#include "espconn.h"
+#include "spi_flash.h"
+#include "ets_alt_task.h"
+#include "lwip/dns.h"
+#include "modnetwork.h"
+
+typedef struct _wlan_if_obj_t {
+ mp_obj_base_t base;
+ int if_id;
+} wlan_if_obj_t;
+
+void error_check(bool status, const char *msg);
+
+STATIC const wlan_if_obj_t wlan_objs[] = {
+ {{&esp_network_wlan_type}, STATION_IF},
+ {{&esp_network_wlan_type}, SOFTAP_IF},
+};
+
+STATIC void require_if(mp_obj_t wlan_if, int if_no) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
+ if (self->if_id != if_no) {
+ error_check(false, if_no == STATION_IF ? "STA required" : "AP required");
+ }
+}
+
+STATIC mp_obj_t esp_wlan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ int idx = 0;
+ if (n_args > 0) {
+ idx = mp_obj_get_int(args[0]);
+ if (idx < 0 || idx >= sizeof(wlan_objs)) {
+ mp_raise_ValueError(NULL);
+ }
+ }
+ return MP_OBJ_FROM_PTR(&wlan_objs[idx]);
+}
+
+STATIC mp_obj_t esp_active(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ uint32_t mode = wifi_get_opmode();
+ if (n_args > 1) {
+ int mask = self->if_id == STATION_IF ? STATION_MODE : SOFTAP_MODE;
+ if (mp_obj_get_int(args[1]) != 0) {
+ mode |= mask;
+ } else {
+ mode &= ~mask;
+ }
+ if (mode != NULL_MODE) {
+ wifi_fpm_do_wakeup();
+ wifi_fpm_close();
+ }
+ error_check(wifi_set_opmode(mode), "Cannot update i/f status");
+ if (mode == NULL_MODE) {
+ // Wait for the interfaces to go down before forcing power management
+ while (wifi_get_opmode() != NULL_MODE) {
+ ets_loop_iter();
+ }
+ wifi_fpm_open();
+ wifi_fpm_do_sleep(0xfffffff);
+ }
+ return mp_const_none;
+ }
+
+ // Get active status
+ if (self->if_id == STATION_IF) {
+ return mp_obj_new_bool(mode & STATION_MODE);
+ } else {
+ return mp_obj_new_bool(mode & SOFTAP_MODE);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_active_obj, 1, 2, esp_active);
+
+STATIC mp_obj_t esp_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_ssid, ARG_key, ARG_bssid };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+
+ // parse args
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ require_if(pos_args[0], STATION_IF);
+ struct station_config config = {{0}};
+ size_t len;
+ const char *p;
+ bool set_config = false;
+
+ // set parameters based on given args
+ if (args[ARG_ssid].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
+ len = MIN(len, sizeof(config.ssid));
+ memcpy(config.ssid, p, len);
+ set_config = true;
+ }
+ if (args[ARG_key].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_key].u_obj, &len);
+ len = MIN(len, sizeof(config.password));
+ memcpy(config.password, p, len);
+ set_config = true;
+ }
+ if (args[ARG_bssid].u_obj != mp_const_none) {
+ p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
+ if (len != sizeof(config.bssid)) {
+ mp_raise_ValueError(NULL);
+ }
+ config.bssid_set = 1;
+ memcpy(config.bssid, p, sizeof(config.bssid));
+ set_config = true;
+ }
+
+ if (set_config) {
+ error_check(wifi_station_set_config(&config), "Cannot set STA config");
+ }
+
+ wifi_station_set_hostname(mod_network_hostname);
+
+ error_check(wifi_station_connect(), "Cannot connect to AP");
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_connect_obj, 1, esp_connect);
+
+STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) {
+ require_if(self_in, STATION_IF);
+ error_check(wifi_station_disconnect(), "Cannot disconnect from AP");
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_disconnect_obj, esp_disconnect);
+
+STATIC mp_obj_t esp_status(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ if (n_args == 1) {
+ // Get link status
+ if (self->if_id == STATION_IF) {
+ return MP_OBJ_NEW_SMALL_INT(wifi_station_get_connect_status());
+ }
+ return MP_OBJ_NEW_SMALL_INT(-1);
+ } else {
+ // Get specific status parameter
+ switch (mp_obj_str_get_qstr(args[1])) {
+ case MP_QSTR_rssi:
+ if (self->if_id == STATION_IF) {
+ return MP_OBJ_NEW_SMALL_INT(wifi_station_get_rssi());
+ }
+ }
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_status_obj, 1, 2, esp_status);
+
+STATIC mp_obj_t *esp_scan_list = NULL;
+
+STATIC void esp_scan_cb(void *result, STATUS status) {
+ if (esp_scan_list == NULL) {
+ // called unexpectedly
+ return;
+ }
+ if (result && status == 0) {
+ // we need to catch any memory errors
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) {
+ mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
+ #if 1
+ // struct bss_info::ssid_len is not documented in SDK API Guide,
+ // but is present in SDK headers since 1.4.0
+ t->items[0] = mp_obj_new_bytes(bs->ssid, bs->ssid_len);
+ #else
+ t->items[0] = mp_obj_new_bytes(bs->ssid, strlen((char *)bs->ssid));
+ #endif
+ t->items[1] = mp_obj_new_bytes(bs->bssid, sizeof(bs->bssid));
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(bs->channel);
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi);
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode);
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden);
+ mp_obj_list_append(*esp_scan_list, MP_OBJ_FROM_PTR(t));
+ }
+ nlr_pop();
+ } else {
+ mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
+ // indicate error
+ *esp_scan_list = MP_OBJ_NULL;
+ }
+ } else {
+ // indicate error
+ *esp_scan_list = MP_OBJ_NULL;
+ }
+ esp_scan_list = NULL;
+}
+
+STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
+ require_if(self_in, STATION_IF);
+ if ((wifi_get_opmode() & STATION_MODE) == 0) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
+ }
+ mp_obj_t list = mp_obj_new_list(0, NULL);
+ esp_scan_list = &list;
+ struct scan_config config = {0};
+ config.show_hidden = 1;
+ wifi_station_scan(&config, (scan_done_cb_t)esp_scan_cb);
+ while (esp_scan_list != NULL) {
+ // our esp_scan_cb is called via ets_loop_iter so it's safe to set the
+ // esp_scan_list variable to NULL without disabling interrupts
+ if (MP_STATE_THREAD(mp_pending_exception) != NULL) {
+ esp_scan_list = NULL;
+ mp_handle_pending(true);
+ }
+ ets_loop_iter();
+ }
+ if (list == MP_OBJ_NULL) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("scan failed"));
+ }
+ return list;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_scan_obj, esp_scan);
+
+/// \method isconnected()
+/// Return True if connected to an AP and an IP address has been assigned,
+/// false otherwise.
+STATIC mp_obj_t esp_isconnected(mp_obj_t self_in) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->if_id == STATION_IF) {
+ if (wifi_station_get_connect_status() == STATION_GOT_IP) {
+ return mp_const_true;
+ }
+ } else {
+ if (wifi_softap_get_station_num() > 0) {
+ return mp_const_true;
+ }
+ }
+ return mp_const_false;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_isconnected_obj, esp_isconnected);
+
+STATIC mp_obj_t esp_ifconfig(size_t n_args, const mp_obj_t *args) {
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ struct ip_info info;
+ ip_addr_t dns_addr;
+ wifi_get_ip_info(self->if_id, &info);
+ if (n_args == 1) {
+ // get
+ dns_addr = dns_getserver(0);
+ mp_obj_t tuple[4] = {
+ netutils_format_ipv4_addr((uint8_t *)&info.ip, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&info.netmask, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&info.gw, NETUTILS_BIG),
+ netutils_format_ipv4_addr((uint8_t *)&dns_addr, NETUTILS_BIG),
+ };
+ return mp_obj_new_tuple(4, tuple);
+ } else if (args[1] == MP_OBJ_NEW_QSTR(MP_QSTR_dhcp)) {
+ // use DHCP to configure the IP addresses
+ require_if(args[0], STATION_IF);
+ wifi_station_dhcpc_start();
+ return mp_const_none;
+ } else {
+ // set
+ mp_obj_t *items;
+ bool restart_dhcp_server = false;
+ mp_obj_get_array_fixed_n(args[1], 4, &items);
+ netutils_parse_ipv4_addr(items[0], (void *)&info.ip, NETUTILS_BIG);
+ if (mp_obj_is_integer(items[1])) {
+ // allow numeric netmask, i.e.:
+ // 24 -> 255.255.255.0
+ // 16 -> 255.255.0.0
+ // etc...
+ uint32_t *m = (uint32_t *)&info.netmask;
+ *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
+ } else {
+ netutils_parse_ipv4_addr(items[1], (void *)&info.netmask, NETUTILS_BIG);
+ }
+ netutils_parse_ipv4_addr(items[2], (void *)&info.gw, NETUTILS_BIG);
+ netutils_parse_ipv4_addr(items[3], (void *)&dns_addr, NETUTILS_BIG);
+ // To set a static IP we have to disable DHCP first
+ if (self->if_id == STATION_IF) {
+ wifi_station_dhcpc_stop();
+ } else {
+ restart_dhcp_server = wifi_softap_dhcps_status();
+ wifi_softap_dhcps_stop();
+ }
+ if (!wifi_set_ip_info(self->if_id, &info)) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("wifi_set_ip_info() failed"));
+ }
+ dns_setserver(0, &dns_addr);
+ if (restart_dhcp_server) {
+ wifi_softap_dhcps_start();
+ }
+ return mp_const_none;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_ifconfig_obj, 1, 2, esp_ifconfig);
+
+STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ if (n_args != 1 && kwargs->used != 0) {
+ mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
+ }
+
+ wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ union {
+ struct station_config sta;
+ struct softap_config ap;
+ } cfg;
+
+ if (self->if_id == STATION_IF) {
+ error_check(wifi_station_get_config(&cfg.sta), "can't get STA config");
+ } else {
+ error_check(wifi_softap_get_config(&cfg.ap), "can't get AP config");
+ }
+
+ int req_if = -1;
+
+ if (kwargs->used != 0) {
+
+ for (mp_uint_t i = 0; i < kwargs->alloc; i++) {
+ if (mp_map_slot_is_filled(kwargs, i)) {
+ switch (mp_obj_str_get_qstr(kwargs->table[i].key)) {
+ case MP_QSTR_mac: {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ);
+ if (bufinfo.len != 6) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer length"));
+ }
+ wifi_set_macaddr(self->if_id, bufinfo.buf);
+ break;
+ }
+ case MP_QSTR_ssid:
+ case MP_QSTR_essid: {
+ req_if = SOFTAP_IF;
+ size_t len;
+ const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ len = MIN(len, sizeof(cfg.ap.ssid));
+ memcpy(cfg.ap.ssid, s, len);
+ cfg.ap.ssid_len = len;
+ break;
+ }
+ case MP_QSTR_hidden: {
+ req_if = SOFTAP_IF;
+ cfg.ap.ssid_hidden = mp_obj_is_true(kwargs->table[i].value);
+ break;
+ }
+ case MP_QSTR_security:
+ case MP_QSTR_authmode: {
+ req_if = SOFTAP_IF;
+ cfg.ap.authmode = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case MP_QSTR_key:
+ case MP_QSTR_password: {
+ req_if = SOFTAP_IF;
+ size_t len;
+ const char *s = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ len = MIN(len, sizeof(cfg.ap.password) - 1);
+ memcpy(cfg.ap.password, s, len);
+ cfg.ap.password[len] = 0;
+ break;
+ }
+ case MP_QSTR_channel: {
+ req_if = SOFTAP_IF;
+ cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value);
+ break;
+ }
+ case MP_QSTR_hostname:
+ case MP_QSTR_dhcp_hostname: {
+ // TODO: Deprecated. Use network.hostname(name) instead.
+ size_t len;
+ const char *str = mp_obj_str_get_data(kwargs->table[i].value, &len);
+ if (len >= MICROPY_PY_NETWORK_HOSTNAME_MAX_LEN) {
+ mp_raise_ValueError(NULL);
+ }
+ strcpy(mod_network_hostname, str);
+ break;
+ }
+ case MP_QSTR_protocol: {
+ wifi_set_phy_mode(mp_obj_get_int(kwargs->table[i].value));
+ break;
+ }
+ case MP_QSTR_txpower: {
+ int8_t power = mp_obj_get_float(kwargs->table[i].value) * 4;
+ system_phy_set_max_tpw(power);
+ break;
+ }
+ case MP_QSTR_pm: {
+ wifi_set_sleep_type(mp_obj_get_int(kwargs->table[i].value));
+ break;
+ }
+ default:
+ goto unknown;
+ }
+ }
+ }
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+
+ if (self->if_id == STATION_IF) {
+ error_check(wifi_station_set_config(&cfg.sta), "can't set STA config");
+ } else {
+ error_check(wifi_softap_set_config(&cfg.ap), "can't set AP config");
+ }
+
+ return mp_const_none;
+ }
+
+ // Get config
+
+ if (n_args != 2) {
+ mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
+ }
+
+ mp_obj_t val;
+
+ qstr key = mp_obj_str_get_qstr(args[1]);
+ switch (key) {
+ case MP_QSTR_mac: {
+ uint8_t mac[6];
+ wifi_get_macaddr(self->if_id, mac);
+ return mp_obj_new_bytes(mac, sizeof(mac));
+ }
+ case MP_QSTR_ssid:
+ case MP_QSTR_essid:
+ if (self->if_id == STATION_IF) {
+ val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char *)cfg.sta.ssid));
+ } else {
+ val = mp_obj_new_str((char *)cfg.ap.ssid, cfg.ap.ssid_len);
+ }
+ break;
+ case MP_QSTR_hidden:
+ req_if = SOFTAP_IF;
+ val = mp_obj_new_bool(cfg.ap.ssid_hidden);
+ break;
+ case MP_QSTR_security:
+ case MP_QSTR_authmode:
+ req_if = SOFTAP_IF;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
+ break;
+ case MP_QSTR_channel:
+ req_if = SOFTAP_IF;
+ val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
+ break;
+ case MP_QSTR_hostname:
+ case MP_QSTR_dhcp_hostname: {
+ req_if = STATION_IF;
+ // TODO: Deprecated. Use network.hostname() instead.
+ val = mp_obj_new_str(mod_network_hostname, strlen(mod_network_hostname));
+ break;
+ }
+ case MP_QSTR_protocol: {
+ val = mp_obj_new_int(wifi_get_phy_mode());
+ break;
+ }
+ case MP_QSTR_pm: {
+ val = MP_OBJ_NEW_SMALL_INT(wifi_get_sleep_type());
+ break;
+ }
+ default:
+ goto unknown;
+ }
+
+ // We post-check interface requirements to save on code size
+ if (req_if >= 0) {
+ require_if(args[0], req_if);
+ }
+
+ return val;
+
+unknown:
+ mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp_config_obj, 1, esp_config);
+
+STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&esp_active_obj) },
+ { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&esp_connect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&esp_disconnect_obj) },
+ { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&esp_status_obj) },
+ { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&esp_scan_obj) },
+ { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&esp_isconnected_obj) },
+ { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&esp_config_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&esp_ifconfig_obj) },
+
+ // Constants
+ { MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(NONE_SLEEP_T) },
+ { MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(MODEM_SLEEP_T) },
+ { MP_ROM_QSTR(MP_QSTR_PM_POWERSAVE), MP_ROM_INT(LIGHT_SLEEP_T) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ esp_network_wlan_type,
+ MP_QSTR_WLAN,
+ MP_TYPE_FLAG_NONE,
+ make_new, esp_wlan_make_new,
+ locals_dict, &wlan_if_locals_dict
+ );
+
+STATIC mp_obj_t esp_phy_mode(size_t n_args, const mp_obj_t *args) {
+ if (n_args == 0) {
+ return mp_obj_new_int(wifi_get_phy_mode());
+ } else {
+ wifi_set_phy_mode(mp_obj_get_int(args[0]));
+ return mp_const_none;
+ }
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_network_phy_mode_obj, 0, 1, esp_phy_mode);
diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c
index 117cd1bf6c93..f761ecfd70cf 100644
--- a/ports/esp8266/uart.c
+++ b/ports/esp8266/uart.c
@@ -3,7 +3,7 @@
*
* FileName: uart.c
*
- * Description: Two UART mode configration and interrupt handler.
+ * Description: Two UART mode configuration and interrupt handler.
* Check your hardware connection while use this mode.
*
* Modification history:
@@ -164,7 +164,7 @@ uart_os_config(int uart) {
*******************************************************************************/
static void uart0_rx_intr_handler(void *para) {
- /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
+ /* uart0 and uart1 intr combine together, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
* uart1 and uart0 respectively
*/
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 2119e027ef59..63cba7d7a67c 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -2,15 +2,27 @@
# Parameter Configuration
# =============================================================================
+# Select the board to build for:
+ifdef BOARD_DIR
+# Custom board path - remove trailing slash and get the final component of
+# the path as the board name.
+BOARD ?= $(notdir $(BOARD_DIR:/=))
+else
+# If not given on the command line, then default to TEENSY40.
BOARD ?= TEENSY40
BOARD_DIR ?= boards/$(BOARD)
+endif
+
+ifeq ($(wildcard $(BOARD_DIR)/.),)
+ $(error Invalid BOARD specified: $(BOARD_DIR))
+endif
+
BUILD ?= build-$(BOARD)
PORT ?= /dev/ttyACM0
CROSS_COMPILE ?= arm-none-eabi-
GIT_SUBMODULES += lib/tinyusb lib/nxp_driver
# MicroPython feature configurations
-FROZEN_MANIFEST ?= boards/manifest.py
MICROPY_VFS_LFS2 ?= 1
MICROPY_VFS_FAT ?= 1
@@ -26,11 +38,14 @@ MAKE_FLEXRAM_LD = boards/make-flexram-config.py
include ../../py/mkenv.mk
# Include micropython configuration board makefile
-ifeq ($(wildcard $(BOARD_DIR)/.),)
- $(error Invalid BOARD specified: $(BOARD_DIR))
-endif
include $(BOARD_DIR)/mpconfigboard.mk
+# MicroPython feature configurations
+MICROPY_ROM_TEXT_COMPRESSION ?= 1
+
+# File containing description of content to be frozen into firmware.
+FROZEN_MANIFEST ?= boards/manifest.py
+
# Include py core make definitions
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
@@ -101,13 +116,12 @@ SRC_ETH_C += \
hal/phy/device/phydp83848/fsl_phydp83848.c \
hal/phy/device/phyksz8081/fsl_phyksz8081.c \
hal/phy/device/phylan8720/fsl_phylan8720.c \
+ hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c \
hal/phy/mdio/enet/fsl_enet_mdio.c
endif
# NXP SDK sources
SRC_HAL_IMX_C += \
- $(MCU_DIR)/drivers/fsl_adc.c \
- $(MCU_DIR)/drivers/fsl_cache.c \
$(MCU_DIR)/drivers/fsl_clock.c \
$(MCU_DIR)/drivers/fsl_common.c \
$(MCU_DIR)/drivers/fsl_dmamux.c \
@@ -124,10 +138,15 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_pwm.c \
$(MCU_DIR)/drivers/fsl_sai.c \
$(MCU_DIR)/drivers/fsl_snvs_lp.c \
- $(MCU_DIR)/drivers/fsl_trng.c \
$(MCU_DIR)/drivers/fsl_wdog.c \
- $(MCU_DIR)/system_$(MCU_SERIES).c \
- hal/fsl_flexspi_nor_boot.c \
+ $(MCU_DIR)/system_$(MCU_SERIES)$(MCU_CORE).c \
+
+# Use a specific boot header for 1062 so the Teensy loader doesn't erase the filesystem.
+ifeq ($(MCU_SERIES), MIMXRT1062)
+SRC_HAL_IMX_C += hal/fsl_flexspi_nor_boot.c
+else
+SRC_HAL_IMX_C += $(MCU_DIR)/xip/fsl_flexspi_nor_boot.c
+endif
ifeq ($(MICROPY_HW_SDRAM_AVAIL),1)
SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_semc.c
@@ -137,9 +156,28 @@ ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
endif
-ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064))
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064 MIMXRT1176))
+SRC_HAL_IMX_C += \
+ $(MCU_DIR)/drivers/fsl_qtmr.c \
+ $(MCU_DIR)/drivers/fsl_romapi.c
+endif
+
+ifeq ($(MCU_SERIES), MIMXRT1176)
+INC += -I$(TOP)/$(MCU_DIR)/drivers/cm7
+
SRC_HAL_IMX_C += \
- $(MCU_DIR)/drivers/fsl_qtmr.c
+ $(MCU_DIR)/drivers/cm7/fsl_cache.c \
+ $(MCU_DIR)/drivers/fsl_dcdc.c \
+ $(MCU_DIR)/drivers/fsl_pmu.c \
+ $(MCU_DIR)/drivers/fsl_common_arm.c \
+ $(MCU_DIR)/drivers/fsl_anatop_ai.c \
+ $(MCU_DIR)/drivers/fsl_caam.c \
+ $(MCU_DIR)/drivers/fsl_lpadc.c
+else
+SRC_HAL_IMX_C += \
+ $(MCU_DIR)/drivers/fsl_adc.c \
+ $(MCU_DIR)/drivers/fsl_cache.c \
+ $(MCU_DIR)/drivers/fsl_trng.c
endif
# C source files
@@ -151,7 +189,9 @@ SRC_C += \
drivers/dht/dht.c \
eth.c \
fatfs_port.c \
+ flash.c \
hal/pwm_backport.c \
+ help.c \
led.c \
machine_adc.c \
machine_bitstream.c \
@@ -162,7 +202,6 @@ SRC_C += \
machine_rtc.c \
machine_sdcard.c \
machine_spi.c \
- machine_timer.c \
machine_uart.c \
machine_wdt.c \
main.c \
@@ -171,7 +210,6 @@ SRC_C += \
mimxrt_sdram.c \
modmachine.c \
modmimxrt.c \
- modutime.c \
mphalport.c \
mpnetworkport.c \
network_lan.c \
@@ -193,25 +231,38 @@ SHARED_SRC_C += \
shared/runtime/interrupt_char.c \
shared/runtime/mpirq.c \
shared/runtime/pyexec.c \
+ shared/runtime/softtimer.c \
shared/runtime/stdout_helpers.c \
shared/runtime/sys_stdio_mphal.c \
shared/timeutils/timeutils.c \
-# Add sources for respective board flash type
-ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash qspi_hyper_flash))
- # Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively
- SRC_HAL_C += hal/flexspi_$(subst qspi_,,$(MICROPY_HW_FLASH_TYPE)).c
- #
- # Add custom (board specific) or default configuration
- ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1)
- SRC_HAL_C += $(BOARD_DIR)/$(MICROPY_HW_FLASH_TYPE)_config.c
- else
- SRC_HAL_C += hal/$(MICROPY_HW_FLASH_TYPE)_config.c
- endif
+# Set flash driver name, base address and internal flash flag, based on the flash type.
+ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash))
+ MICROPY_HW_FLASH_BASE = 0x60000000
+ FLEXSPI_FLASH_TYPE = $(MICROPY_HW_FLASH_TYPE)
+else ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_hyper_flash))
+ MICROPY_HW_FLASH_BASE = 0x60000000
+ FLEXSPI_FLASH_TYPE = $(MICROPY_HW_FLASH_TYPE)
+else ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),internal))
+ # The internal flash is an SPI NOR Flash.
+ MICROPY_HW_FLASH_BASE = 0x70000000
+ FLEXSPI_FLASH_TYPE = qspi_nor_flash
+ CFLAGS += -DMICROPY_HW_FLASH_INTERNAL
else
$(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE))
endif
+# Add sources for respective board flash type
+# Add hal/flexspi_nor_flash.c or hal/flashspi_hyper_flash.c respectively
+SRC_HAL_C += hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).c
+#
+# Add custom (board specific) or default configuration
+ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1)
+ SRC_HAL_C += $(BOARD_DIR)/$(FLEXSPI_FLASH_TYPE)_config.c
+else
+ SRC_HAL_C += hal/$(FLEXSPI_FLASH_TYPE)_config.c
+endif
+
# Math library source files
ifeq ($(MICROPY_FLOAT_IMPL),double)
LIBM_SRC_C += $(addprefix lib/libm_dbl/,\
@@ -243,10 +294,10 @@ SUPPORTS_HARDWARE_FP_DOUBLE = 0
# Assembly source files
SRC_SS = \
- $(MCU_DIR)/gcc/startup_$(MCU_SERIES).S \
+ $(MCU_DIR)/gcc/startup_$(MCU_SERIES)$(MCU_CORE).S \
hal/resethandler_MIMXRT10xx.S
-SRC_S += shared/runtime/gchelper_m3.s \
+SRC_S += shared/runtime/gchelper_thumb2.s \
# =============================================================================
# QSTR Sources
@@ -262,6 +313,8 @@ SRC_QSTR += $(SRC_C) $(SHARED_SRC_C) $(GEN_PINS_SRC)
CFLAGS += -g # always include debug info in the ELF
ifeq ($(DEBUG),1)
CFLAGS += -Og
+# Disable text compression in debug builds
+MICROPY_ROM_TEXT_COMPRESSION = 0
else
CFLAGS += -Os -DNDEBUG
endif
@@ -279,11 +332,11 @@ CFLAGS += \
-D__STARTUP_INITIALIZE_RAMFUNCTION \
-DBOARD_$(BOARD) \
-DBOARD_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
- -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX \
+ -DCFG_TUSB_MCU=OPT_MCU_MIMXRT \
-DCLOCK_CONFIG_H='' \
- -DCPU_$(MCU_SERIES) \
+ -DCPU_$(MCU_SERIES)$(MCU_CORE) \
-DCPU_$(MCU_VARIANT) \
- -DCPU_HEADER_H='<$(MCU_SERIES).h>' \
+ -DCPU_HEADER_H='<$(MCU_SERIES)$(MCU_CORE).h>' \
-DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 \
-DI2C_RETRY_TIMES=1000000 \
-DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE) \
@@ -308,18 +361,14 @@ CFLAGS += \
-Wno-error=unused-parameter
# Configure respective board flash type
-ifeq ($(MICROPY_HW_FLASH_TYPE),$(filter $(MICROPY_HW_FLASH_TYPE),qspi_nor_flash qspi_hyper_flash))
- # Add hal/flexspi_nor_flash.h or hal/flexspi_hyper_flash.h respectively
- CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_$(subst qspi_,,$(MICROPY_HW_FLASH_TYPE)).h\"
- #
- # Add custom (board specific) or default configuration
- ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1)
- CFLAGS += -DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_flash_config.h\"
- else
- CFLAGS += -DBOARD_FLASH_CONFIG_HEADER_H=\"hal/flexspi_flash_config.h\"
- endif
+# Add hal/flexspi_nor_flash.h or hal/flexspi_hyper_flash.h respectively
+CFLAGS += -DBOARD_FLASH_OPS_HEADER_H=\"hal/flexspi_$(subst qspi_,,$(FLEXSPI_FLASH_TYPE)).h\"
+#
+# Add custom (board specific) or default configuration
+ifeq ($(MICROPY_HW_BOARD_FLASH_FILES),1)
+ CFLAGS += -DBOARD_FLASH_CONFIG_HEADER_H=\"$(BOARD)_flexspi_flash_config.h\"
else
- $(error Error: Unknown board flash type $(MICROPY_HW_FLASH_TYPE))
+ CFLAGS += -DBOARD_FLASH_CONFIG_HEADER_H=\"hal/flexspi_flash_config.h\"
endif
# Configure floating point support
@@ -345,12 +394,13 @@ endif
# All settings for Ethernet support are controller by the value of MICROPY_PY_LWIP
ifeq ($(MICROPY_PY_LWIP),1)
CFLAGS += \
- -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1 \
- -DMBEDTLS_CONFIG_FILE='"mbedtls/mbedtls_config.h"'
+ -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE=1
endif
CFLAGS += $(CFLAGS_EXTRA)
+MPY_CROSS_FLAGS += -march=armv7m
+
# =============================================================================
# Linker Flags
# =============================================================================
@@ -365,7 +415,7 @@ LDFLAGS += \
# the C preprocessor. Therefore keep LDDEFINES separated from LDFLAGS!
LDDEFINES = \
- -DMICROPY_HW_FLASH_TYPE=$(MICROPY_HW_FLASH_TYPE) \
+ -DMICROPY_HW_FLASH_BASE=$(MICROPY_HW_FLASH_BASE) \
-DMICROPY_HW_FLASH_SIZE=$(MICROPY_HW_FLASH_SIZE)
ifdef MICROPY_HW_FLASH_RESERVED
@@ -439,9 +489,8 @@ $(HEADER_BUILD)/qstrdefs.generated.h: $(BOARD_DIR)/mpconfigboard.h
$(GEN_FLEXRAM_CONFIG_SRC):
$(ECHO) "Create $@"
- $(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES).h \
- -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $(GEN_FLEXRAM_CONFIG_SRC)
-
+ $(Q)$(PYTHON) $(MAKE_FLEXRAM_LD) -d $(TOP)/$(MCU_DIR)/$(MCU_SERIES)$(MCU_CORE).h \
+ -f $(TOP)/$(MCU_DIR)/$(MCU_SERIES)$(MCU_CORE)_features.h -l boards/$(MCU_SERIES).ld -c $(MCU_SERIES) > $(GEN_FLEXRAM_CONFIG_SRC)
# Use a pattern rule here so that make will only call make-pins.py once to make
# both pins_gen.c and pins.h
diff --git a/ports/mimxrt/README.md b/ports/mimxrt/README.md
index c8c5d989b9c8..de3de1e2817f 100644
--- a/ports/mimxrt/README.md
+++ b/ports/mimxrt/README.md
@@ -29,3 +29,47 @@ Known issues:
TODO:
- More peripherals (Counter, I2S, CAN, etc)
- More Python options
+
+## Build Instructions
+
+Before building the firmware for a given board the MicroPython cross-compiler
+must be built; it will be used to pre-compile some of the built-in scripts to
+bytecode. The cross-compiler is built and run on the host machine, using:
+
+ $ make -C mpy-cross
+
+This command should be executed from the root directory of this repository.
+All other commands below should be executed from the ports/mimxrt/ directory.
+
+An ARM compiler is required for the build, along with the associated binary
+utilities. The default compiler is `arm-none-eabi-gcc`, which is available for
+Arch Linux via the package `arm-none-eabi-gcc`, for Ubuntu via instructions
+[here](https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa), or
+see [here](https://launchpad.net/gcc-arm-embedded) for the main GCC ARM
+Embedded page. The compiler can be changed using the `CROSS_COMPILE` variable
+when invoking `make`.
+
+In addition newlib is required which is available for Arch Linux via the
+package `arm-none-eabi-newlib`, for Ubuntu/Debian install package `libnewlib-arm-none-eabi`
+
+Next, the board to build must be selected. Any of the board names of the
+subdirectories in the `boards/` directory is a valid board. The board name
+must be passed as the argument to `BOARD=` when invoking `make`.
+
+All boards require certain submodules to be obtained before they can be built.
+The correct set of submodules can be initialised using (with `SEEED_ARCH_MIX`
+as an example of the selected board):
+
+ $ make BOARD=SEEED_ARCH_MIX submodules
+
+Then to build the board's firmware run:
+
+ $ make BOARD=SEEED_ARCH_MIX
+
+The above command should produce binary images in the `build-SEEED_ARCH_MIX/`
+subdirectory (or the equivalent directory for the board specified).
+
+## Flashing
+
+Deploy the firmware following the instructions here
+https://docs.micropython.org/en/latest/mimxrt/tutorial/intro.html#deploying-the-firmware
diff --git a/ports/mimxrt/board_init.c b/ports/mimxrt/board_init.c
index 12496890ac4a..78001862f05d 100644
--- a/ports/mimxrt/board_init.c
+++ b/ports/mimxrt/board_init.c
@@ -40,10 +40,15 @@
#include CLOCK_CONFIG_H
#include "modmachine.h"
-
const uint8_t dcd_data[] = { 0x00 };
+void usb_phy0_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn);
+
void board_init(void) {
+ // Clean and enable cache
+ SCB_CleanDCache();
+ SCB_EnableDCache();
+ SCB_EnableICache();
// Init clock
BOARD_BootClockRUN();
SystemCoreClockUpdate();
@@ -51,7 +56,7 @@ void board_init(void) {
// Enable IOCON clock
CLOCK_EnableClock(kCLOCK_Iomuxc);
- // ------------- SDRAM ------------ //
+ // SDRAM
#if MICROPY_HW_SDRAM_AVAIL
mimxrt_sdram_init();
#endif
@@ -59,39 +64,12 @@ void board_init(void) {
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
- // ------------- USB0 ------------- //
- // Clock
- CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
- CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U);
-
- #ifdef USBPHY1
- USBPHY_Type *usb_phy = USBPHY1;
- #else
- USBPHY_Type *usb_phy = USBPHY;
- #endif
-
- // Enable PHY support for Low speed device + LS via FS Hub
- usb_phy->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK | USBPHY_CTRL_SET_ENUTMILEVEL3_MASK;
-
- // Enable all power for normal operation
- usb_phy->PWD = 0;
-
- // TX Timing
- uint32_t phytx = usb_phy->TX;
- phytx &= ~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK);
- phytx |= USBPHY_TX_D_CAL(0x0C) | USBPHY_TX_TXCAL45DP(0x06) | USBPHY_TX_TXCAL45DM(0x06);
- usb_phy->TX = phytx;
-
- // USB1
- // CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U);
- // CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U);
+ // USB0
+ usb_phy0_init(0b0111, 0b0110, 0b0110); // Configure nominal values for D_CAL and TXCAL45DP/DN
// ADC
machine_adc_init();
- // PIT
- machine_timer_init_PIT();
-
// SDCard
#if MICROPY_PY_MACHINE_SDCARD
machine_sdcard_init0();
@@ -102,6 +80,49 @@ void board_init(void) {
#endif
// RTC
machine_rtc_start();
+
+ // OCRAM wait states (discarded, but code kept)
+ #if 0
+ MECC1->PIPE_ECC_EN =
+ MECC_PIPE_ECC_EN_READ_DATA_WAIT_EN(1) |
+ MECC_PIPE_ECC_EN_READ_ADDR_PIPE_EN(1) |
+ MECC_PIPE_ECC_EN_WRITE_DATA_PIPE_EN(1) |
+ MECC_PIPE_ECC_EN_WRITE_ADDR_PIPE_EN(1);
+
+ MECC2->PIPE_ECC_EN =
+ MECC_PIPE_ECC_EN_READ_DATA_WAIT_EN(1) |
+ MECC_PIPE_ECC_EN_READ_ADDR_PIPE_EN(1) |
+ MECC_PIPE_ECC_EN_WRITE_DATA_PIPE_EN(1) |
+ MECC_PIPE_ECC_EN_WRITE_ADDR_PIPE_EN(1);
+
+ FLEXRAM->FLEXRAM_CTRL =
+ FLEXRAM_FLEXRAM_CTRL_OCRAM_RDATA_WAIT_EN(1) |
+ FLEXRAM_FLEXRAM_CTRL_OCRAM_RADDR_PIPELINE_EN(1) |
+ FLEXRAM_FLEXRAM_CTRL_OCRAM_WRDATA_PIPELINE_EN(1) |
+ FLEXRAM_FLEXRAM_CTRL_OCRAM_WRADDR_PIPELINE_EN(1);
+ #endif
+}
+
+void usb_phy0_init(uint8_t d_cal, uint8_t txcal45dp, uint8_t txcal45dn) {
+ #ifdef USBPHY1
+ USBPHY_Type *usb_phy = USBPHY1;
+ #else
+ USBPHY_Type *usb_phy = USBPHY;
+ #endif
+
+ CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, BOARD_XTAL0_CLK_HZ);
+ CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, BOARD_XTAL0_CLK_HZ);
+
+ #if defined(MIMXRT117x_SERIES)
+ usb_phy->TRIM_OVERRIDE_EN = USBPHY_TRIM_OVERRIDE_EN_TRIM_DIV_SEL_OVERRIDE(1) |
+ USBPHY_TRIM_OVERRIDE_EN_TRIM_ENV_TAIL_ADJ_VD_OVERRIDE(1) |
+ USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_D_CAL_OVERRIDE(1) |
+ USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DP_OVERRIDE(1) |
+ USBPHY_TRIM_OVERRIDE_EN_TRIM_TX_CAL45DN_OVERRIDE(1); // Enable override for D_CAL and TXCAL45DP/DN
+ #endif
+ usb_phy->PWD = 0U; // Set all bits in PWD register to normal operation
+ usb_phy->TX = ((usb_phy->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) |
+ (USBPHY_TX_D_CAL(d_cal) | USBPHY_TX_TXCAL45DP(txcal45dp) | USBPHY_TX_TXCAL45DM(txcal45dn))); // Configure values for D_CAL and TXCAL45DP/DN
}
void USB_OTG1_IRQHandler(void) {
diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json
new file mode 100644
index 000000000000..c96e9b08fe21
--- /dev/null
+++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/board.json
@@ -0,0 +1,26 @@
+{
+ "deploy": [
+ "deploy_metro_m7.md"
+ ],
+ "docs": "",
+ "features": [
+ "USB-C",
+ "SPI",
+ "I2C",
+ "UART",
+ "RGB LED",
+ "QSPI Flash",
+ "QWIIC",
+ "JLink",
+ "WiFi",
+ "BLE"
+ ],
+ "images": [
+ "Metro_M7.jpg"
+ ],
+ "mcu": "mimxrt",
+ "product": "Adafruit Metro M7",
+ "thumbnail": "",
+ "url": "https://www.adafruit.com/product/4950",
+ "vendor": "Adafruit"
+}
diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/deploy_metro_m7.md b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/deploy_metro_m7.md
new file mode 100644
index 000000000000..bc92016b7175
--- /dev/null
+++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/deploy_metro_m7.md
@@ -0,0 +1,141 @@
+## 1. Deploy the MicroPython firmware to the Metro M7 board.
+
+### 1.1 Deploy the firmware using the serial bootloader.
+
+For initial deployment of the firmware a few preparation steps are required, which
+have to be done once.
+
+1. Get the files ufconv.py and uf2families.json from the micropython/tools directory,
+e.g. at https://github.com/micropython/micropython/tree/master/tools.
+
+2. Get the NXP program sdphost for your operating system, e.g. from
+https://github.com/adafruit/tinyuf2/tree/master/ports/mimxrt10xx/sdphost.
+You can also get them from the NXP web sites.
+
+3. Get the UF2 boot-loader package https://github.com/adafruit/tinyuf2/releases/download/0.9.0/tinyuf2-imxrt1010_evk-0.9.0.zip
+and extract the file tinyuf2-imxrt1010_evk-0.9.0.bin.
+
+Now you have all files at hand that you will need for updating.
+
+1. Get the firmware you want to upload from the MicroPython download page.
+
+2. Set the two BOOTSEL DIP switches to the 1/0 position, which is the opposite position of the normal use mode.
+
+3. Push the reset button.
+
+4. Run the commands:
+
+```
+sudo ./sdphost -u 0x1fc9,0x0145 -- write-file 0x20206400 tinyuf2-imxrt1010_evk-0.9.0.bin
+sudo ./sdphost -u 0x1fc9,0x0145 -- jump-address 0x20207000
+```
+Wait until a drive icon appears on the computer (or mount it explicitly), and then run:
+```
+python3 uf2conv.py --base 0x60000400 -f 0x4fb2d5bd
+```
+You can put all of that in a script. Just add a short wait before the 3rd command to let the drive connect.
+
+5. Once the upload is finished, set the BOOTSEL DIP switches back to the 0/1 position and push reset.
+
+Using sudo is Linux specific. You may not need it at all, if the access rights are set properly,
+and you will not need it for Windows.
+
+### 1.2 Deploy the firmware using a JTAG adapter.
+
+With a JTAG adapter the firmware can be easily installed. Appropriate tools are Segger JFlash Lite and
+the Segger Edu Mini adapter. Just use the firmware.hex file for loading, which will be loaded at the
+proper address.
+
+
+## 2. Deploy the WiFi firmware.
+
+The NINA firmware in the NINA module has to be updated for use with MicroPython. That can be done
+using MicroPython and two small Python scripts.
+
+The firmware binaries are available at
+https://github.com/micropython/micropython-lib/tree/master/micropython/espflash
+or https://github.com/robert-hh/Shared-Stuff. For the Metro M7 board, the
+NINA_FW_v1.5.0_Airlift.bin file is needed.
+
+For firmware upload, the following connections to the WiFi module are required:
+
+- Pin Reset (as above)
+- Pin GPIO0
+- UART RX
+- UART TX
+
+The GPIO pins and UART device id varies between boards. At the Adafruit Metro M7 board,
+the UART is UART(1), and the Pin names for reset and GPIO0 are ESP_RESET and ESP_GPIO0.
+The firmware can be uploaded, using the espflash.py module, a short script
+using espflash.py and mpremote. espflash.py is available at
+https://github.com/micropython/micropython-lib/tree/master/micropython/espflash.
+This place also holds the example script.
+
+```
+import espflash
+from machine import Pin
+from machine import UART
+import sys
+sys.path.append("/flash")
+
+reset = Pin("ESP_RESET", Pin.OUT)
+gpio0 = Pin("ESP_GPIO0", Pin.OUT)
+uart = UART(0, 115200, timeout=350)
+
+md5sum = b"b0b9ab23da820a469e597c41364acb3a"
+path = "/remote/NINA_FW_v1.5.0_Airlift.bin"
+
+esp = espflash.ESPFlash(reset, gpio0, uart)
+# Enter bootloader download mode, at 115200
+esp.bootloader()
+# Can now change to higher/lower baud rate
+esp.set_baudrate(921600)
+# Must call this first before any flash functions.
+esp.flash_attach()
+# Read flash size
+size = esp.flash_read_size()
+# Configure flash parameters.
+esp.flash_config(size)
+# Write firmware image from internal storage.
+esp.flash_write_file(path)
+# Compares file and flash MD5 checksum.
+esp.flash_verify_file(path, md5sum)
+# Resets the ESP32 chip.
+esp.reboot()
+```
+
+The script shows the set-up for the Metro M7 board.
+The md5sum is the one of the WiFi firmware. It may change and
+can be recalculated using e.g. the Linux `md5sum` command. It is used to
+verify the firmware upload. To upload the firmware, place the firmware
+and the above script (let's call it ninaflash.py) into the same directory
+on your PC, and run the command:
+```
+mpremote connect mount . run ninaflash.py
+```
+After a while, the upload will start. A typical start sequence looks like:
+```
+Local directory . is mounted at /remote
+Failed to read response to command 8.
+Failed to read response to command 8.
+Changing baudrate => 921600
+Flash attached
+Flash size 2.0 MBytes
+Flash write size: 1310720 total_blocks: 320 block size: 4096
+Writing sequence number 0/320...
+Writing sequence number 1/320...
+Writing sequence number 2/320...
+Writing sequence number 3/320...
+Writing sequence number 4/320...
+....
+....
+Writing sequence number 317/320...
+Writing sequence number 318/320...
+Writing sequence number 319/320...
+Flash write finished
+Flash verify: File MD5 b'b0b9ab23da820a469e597c41364acb3a'
+Flash verify: Flash MD5 b'b0b9ab23da820a469e597c41364acb3a'
+Firmware verified.
+```
+The initial messages `Failed to read response to command 8.`
+can be ignored.
diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h
new file mode 100644
index 000000000000..ac9cf9705807
--- /dev/null
+++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.h
@@ -0,0 +1,65 @@
+#define MICROPY_HW_BOARD_NAME "Adafruit Metro M7"
+#define MICROPY_HW_MCU_NAME "MIMXRT1011DAE5A"
+
+// i.MX RT1010 EVK has 1 board LED
+#define MICROPY_HW_LED1_PIN (pin_GPIO_03)
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+
+#define MICROPY_HW_NUM_PIN_IRQS (2 * 32)
+
+// Define mapping logical UART # to hardware UART #
+// LPUART1 on USB_DBG -> 0
+// LPUART1 on D0/D1 -> 1
+// LPUART3 on A0/D4 -> 3
+// LPUART4 on D6/D7 -> 2
+
+#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
+#define MICROPY_HW_UART_INDEX { 1, 1, 2, 4 }
+
+#define IOMUX_TABLE_UART \
+ { IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
+ { IOMUXC_GPIO_12_LPUART3_TXD }, { IOMUXC_GPIO_11_LPUART3_RXD }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_AD_06_LPSPI1_SCK }, { IOMUXC_GPIO_AD_05_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_AD_04_LPSPI1_SDO }, { IOMUXC_GPIO_AD_03_LPSPI1_SDI }, \
+ { IOMUXC_GPIO_AD_02_LPSPI1_PCS1 }
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx }
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx }
+
+// Define mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C1 -> 0
+// D0/D1 LPI2C2 -> 1
+// D6/D7 LPI2C2 -> 1 Alternatively possible GPIO_AD_01, GPIO_AD_02
+
+#define MICROPY_HW_I2C_INDEX { 1, 2 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_02_LPI2C1_SCL }, { IOMUXC_GPIO_01_LPI2C1_SDA }, \
+ { IOMUXC_GPIO_10_LPI2C2_SCL }, { IOMUXC_GPIO_09_LPI2C2_SDA },
+
+// Wifi Deinitions
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-metro-m7"
+
+#define MICROPY_HW_WIFI_SPI_ID (0)
+#define MICROPY_HW_WIFI_SPI_BAUDRATE (8000000)
+
+#define MICROPY_HW_NINA_ACK pin_find(MP_OBJ_NEW_QSTR(MP_QSTR_ESP_BUSY))
+#define MICROPY_HW_NINA_CS pin_find(MP_OBJ_NEW_QSTR(MP_QSTR_ESP_CS))
+#define MICROPY_HW_NINA_RESET pin_find(MP_OBJ_NEW_QSTR(MP_QSTR_ESP_RESET))
+
+// BLE definitions
+#define MICROPY_PY_BLUETOOTH_NINAW10 (1)
+
+#define MICROPY_HW_BLE_UART_ID (1)
+#define MICROPY_HW_BLE_UART_BAUDRATE (115200)
+
+#define MICROPY_HW_NINA_RTS pin_find(MP_OBJ_NEW_QSTR(MP_QSTR_MOSI))
+#define MICROPY_HW_NINA_CTS MICROPY_HW_NINA_ACK
diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.mk b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.mk
new file mode 100644
index 000000000000..236db27c87db
--- /dev/null
+++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/mpconfigboard.mk
@@ -0,0 +1,11 @@
+MCU_SERIES = MIMXRT1011
+MCU_VARIANT = MIMXRT1011DAE5A
+
+MICROPY_FLOAT_IMPL = single
+MICROPY_PY_MACHINE_SDCARD = 0
+MICROPY_HW_FLASH_TYPE ?= qspi_nor_flash
+MICROPY_HW_FLASH_SIZE ?= 0x800000 # 8MB
+
+MICROPY_PY_NETWORK_NINAW10 ?= 1
+MICROPY_PY_SSL ?= 1
+MICROPY_SSL_MBEDTLS ?= 1
diff --git a/ports/mimxrt/boards/ADAFRUIT_METRO_M7/pins.csv b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/pins.csv
new file mode 100644
index 000000000000..65fbd68d507f
--- /dev/null
+++ b/ports/mimxrt/boards/ADAFRUIT_METRO_M7/pins.csv
@@ -0,0 +1,31 @@
+D0,GPIO_09
+D1,GPIO_10
+D2,GPIO_13
+D3,GPIO_12
+D4,GPIO_SD_00
+D5,GPIO_SD_01
+D6,GPIO_SD_02
+D7,GPIO_11
+D8,GPIO_08
+D9,GPIO_07
+D10,GPIO_06
+D11,GPIO_05
+D12,GPIO_04
+D13,GPIO_03
+D14,GPIO_01
+D15,GPIO_02
+A0,GPIO_AD_02
+A1,GPIO_AD_01
+A2,GPIO_AD_00
+A3,GPIO_AD_05
+A4,GPIO_AD_10
+A5,GPIO_AD_08
+LED,GPIO_03
+NEOPIXEL,GPIO_00
+ESP_RESET,GPIO_AD_07
+ESP_BUSY,GPIO_AD_11
+ESP_CS,GPIO_AD_14
+ESP_GPIO0,GPIO_SD_05
+SCK,GPIO_AD_06
+MISO,GPIO_AD_03
+MOSI,GPIO_AD_04
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 6c9aaff96ab5..eff9e9c2cd5c 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -20,7 +20,7 @@
#define IOMUX_TABLE_UART \
{ IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
{ 0 }, { 0 }, \
- { 0 }, { 0 }, \
+ { IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \
{ IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
#define MICROPY_HW_SPI_INDEX { 1 }
@@ -54,6 +54,7 @@
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx }
#define I2S_WM8960_RX_MODE (1)
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
diff --git a/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h
index adb97fd24e9f..f37ba824f485 100644
--- a/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1015_EVK/mpconfigboard.h
@@ -59,6 +59,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir, kIOMUXC_GPR_SAI2MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/manifest.py b/ports/mimxrt/boards/MIMXRT1020_EVK/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 762499f6c2f2..390e91814d16 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "i.MX RT1020 EVK"
#define MICROPY_HW_MCU_NAME "MIMXRT1021DAG5A"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1020evk"
+
// i.MX RT1020 EVK has 1 board LED
// Todo: think about replacing the define with searching in the generated pins?
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_05)
@@ -73,6 +75,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir, kIOMUXC_GPR_SAI2MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -158,8 +161,8 @@
#define ENET_PHY_OPS phyksz8081_ops
// Etherner PIN definitions
-#define ENET_RESET_PIN pin_GPIO_AD_B0_04
-#define ENET_INT_PIN pin_GPIO_AD_B1_06
+#define ENET_RESET_PIN &pin_GPIO_AD_B0_04
+#define ENET_INT_PIN &pin_GPIO_AD_B1_06
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_AD_B0_08_ENET_REF_CLK1, 1, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
index e8922e4b7abf..547b88d57de4 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.mk
@@ -10,9 +10,11 @@ MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
JLINK_PATH ?= /media/RT1020-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/manifest.py b/ports/mimxrt/boards/MIMXRT1050_EVK/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index f2a7b0b78b43..134c9637ea57 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "i.MX RT1050 EVKB-A1"
#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL6B"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1050evk"
+
// MIMXRT1050_EVKB has 1 user LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
@@ -62,6 +64,7 @@
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
#define I2S_WM8960_RX_MODE (1)
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -148,8 +151,8 @@
#define ENET_PHY_OPS phyksz8081_ops
// Etherner PIN definitions
-#define ENET_RESET_PIN pin_GPIO_AD_B0_09
-#define ENET_INT_PIN pin_GPIO_AD_B0_10
+#define ENET_RESET_PIN &pin_GPIO_AD_B0_09
+#define ENET_INT_PIN &pin_GPIO_AD_B0_10
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
index 00843350494a..0cf2a348046e 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.mk
@@ -10,5 +10,7 @@ MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
diff --git a/ports/mimxrt/boards/MIMXRT1052_clock_config.c b/ports/mimxrt/boards/MIMXRT1052_clock_config.c
index 93492812977a..fa7450d487a6 100644
--- a/ports/mimxrt/boards/MIMXRT1052_clock_config.c
+++ b/ports/mimxrt/boards/MIMXRT1052_clock_config.c
@@ -465,4 +465,5 @@ void BOARD_BootClockRUN(void) {
IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK;
/* Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK;
+ CLOCK_SetMode(kCLOCK_ModeRun);
}
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/manifest.py b/ports/mimxrt/boards/MIMXRT1060_EVK/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index 5670902d11a5..01ae3ba303c6 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "i.MX RT1060 EVK"
#define MICROPY_HW_MCU_NAME "MIMXRT1062DVJ6A"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1060evk"
+
// MIMXRT1060_EVK has 1 user LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
@@ -62,6 +64,7 @@
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
#define I2S_WM8960_RX_MODE (1)
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -146,8 +149,8 @@
#define ENET_PHY_OPS phyksz8081_ops
// Etherner PIN definitions
-#define ENET_RESET_PIN pin_GPIO_AD_B0_09
-#define ENET_INT_PIN pin_GPIO_AD_B0_10
+#define ENET_RESET_PIN &pin_GPIO_AD_B0_09
+#define ENET_INT_PIN &pin_GPIO_AD_B0_10
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
index 96afe276f706..c2556a27248a 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.mk
@@ -10,9 +10,11 @@ MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
JLINK_PATH ?= /media/RT1060-EVK/
JLINK_COMMANDER_SCRIPT = $(BUILD)/script.jlink
diff --git a/ports/mimxrt/boards/MIMXRT1062_clock_config.c b/ports/mimxrt/boards/MIMXRT1062_clock_config.c
index 05474167bd85..589ffb0b5831 100644
--- a/ports/mimxrt/boards/MIMXRT1062_clock_config.c
+++ b/ports/mimxrt/boards/MIMXRT1062_clock_config.c
@@ -487,4 +487,5 @@ void BOARD_BootClockRUN(void) {
IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK;
/* Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK;
+ CLOCK_SetMode(kCLOCK_ModeRun);
}
diff --git a/ports/mimxrt/boards/MIMXRT1064.ld b/ports/mimxrt/boards/MIMXRT1064.ld
index 1fbc855fa13f..708dac4d515c 100644
--- a/ports/mimxrt/boards/MIMXRT1064.ld
+++ b/ports/mimxrt/boards/MIMXRT1064.ld
@@ -3,15 +3,7 @@
reserved_size = MICROPY_HW_FLASH_RESERVED;
#endif
-#if MICROPY_HW_FLASH_TYPE == qspi_nor_flash
-flash_start = 0x60000000;
-#elif MICROPY_HW_FLASH_TYPE == qspi_hyper_flash
-flash_start = 0x60000000;
-#elif MICROPY_HW_FLASH_TYPE == internal
-flash_start = 0x70000000;
-#else
-#error Unknown MICROPY_HW_FLASH_TYPE
-#endif
+flash_start = MICROPY_HW_FLASH_BASE;
flash_size = MICROPY_HW_FLASH_SIZE;
flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
flash_config_start = flash_start;
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/manifest.py b/ports/mimxrt/boards/MIMXRT1064_EVK/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 0f4eaf246da1..b6752c3e1ba3 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "i.MX RT1064 EVK"
#define MICROPY_HW_MCU_NAME "MIMXRT1064DVL6A"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1064evk"
+
// MIMXRT1064_EVK has 1 user LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin))
@@ -62,6 +64,7 @@
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
#define I2S_WM8960_RX_MODE (1)
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -146,8 +149,8 @@
#define ENET_PHY_OPS phyksz8081_ops
// Etherner PIN definitions
-#define ENET_RESET_PIN pin_GPIO_AD_B0_09
-#define ENET_INT_PIN pin_GPIO_AD_B0_10
+#define ENET_RESET_PIN &pin_GPIO_AD_B0_09
+#define ENET_INT_PIN &pin_GPIO_AD_B0_10
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
index ceb1e9796e01..d3ba752419e0 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.mk
@@ -3,16 +3,18 @@ MCU_VARIANT = MIMXRT1064DVL6A
MICROPY_FLOAT_IMPL = double
MICROPY_PY_MACHINE_SDCARD = 1
-MICROPY_HW_FLASH_TYPE = qspi_hyper_flash
-MICROPY_HW_FLASH_SIZE = 0x4000000 # 64MB
+MICROPY_HW_FLASH_TYPE = internal
+MICROPY_HW_FLASH_SIZE = 0x400000 # 4MB
MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
JLINK_PATH ?= /media/RT1064-EVK/
deploy: $(BUILD)/firmware.bin
diff --git a/ports/mimxrt/boards/MIMXRT1064_clock_config.c b/ports/mimxrt/boards/MIMXRT1064_clock_config.c
index 5e49a2fff80e..56dd75d7fbf6 100644
--- a/ports/mimxrt/boards/MIMXRT1064_clock_config.c
+++ b/ports/mimxrt/boards/MIMXRT1064_clock_config.c
@@ -487,4 +487,5 @@ void BOARD_BootClockRUN(void) {
IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK;
/* Set SystemCoreClock variable. */
SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK;
+ CLOCK_SetMode(kCLOCK_ModeRun);
}
diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/board.json b/ports/mimxrt/boards/MIMXRT1170_EVK/board.json
new file mode 100644
index 000000000000..01e554751b46
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1170_EVK/board.json
@@ -0,0 +1,28 @@
+{
+ "deploy": [
+ "../deploy_mimxrt.md"
+ ],
+ "docs": "",
+ "features": [
+ "Ethernet",
+ "SDRAM",
+ "MicroSD",
+ "MicroUSB",
+ "Microphone",
+ "AudioCodec",
+ "SPDIF",
+ "CAN",
+ "Camera",
+ "SIM Socket",
+ "OpenSDA",
+ "JLink"
+ ],
+ "images": [
+ "IMX-RT1170-EVK-TOP.jpg"
+ ],
+ "mcu": "mimxrt",
+ "product": "MIMXRT1170_EVK",
+ "thumbnail": "",
+ "url": "https://www.nxp.com/design/development-boards/i-mx-evaluation-and-development-boards/i-mx-rt1170-evaluation-kit:MIMXRT1170-EVK",
+ "vendor": "NXP"
+}
diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/manifest.py b/ports/mimxrt/boards/MIMXRT1170_EVK/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1170_EVK/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h
new file mode 100644
index 000000000000..d37050eb5604
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.h
@@ -0,0 +1,257 @@
+#define MICROPY_HW_BOARD_NAME "i.MX RT1170 EVK"
+#define MICROPY_HW_MCU_NAME "MIMXRT1176DVMAA"
+
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-1070evk"
+
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(bool); \
+ mp_handle_pending(true); \
+ } while (0);
+
+// MIMXRT1170_EVK has 2 user LEDs
+#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_04)
+#define MICROPY_HW_LED2_PIN (pin_GPIO_AD_26)
+#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin))
+#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
+
+#define MICROPY_HW_NUM_PIN_IRQS (6 * 32)
+
+// Define mapping hardware UART # to logical UART #
+// LPUART2 on D0/D1 -> 1
+// LPUART3 on D12/D11 -> 2
+// LPUART5 on D10/D13 -> 3
+// LPUART11 on D15/D14 -> 4
+// LPUART12 on D25/D26 -> 5
+// LPUART8 on D33/D34 -> 6
+// LPUART7 on D35/D36 -> 7
+
+#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
+#define MICROPY_HW_UART_INDEX { 1, 2, 3, 5, 11, 12, 8, 7 }
+
+#define IOMUX_TABLE_UART \
+ { IOMUXC_GPIO_AD_24_LPUART1_TXD }, { IOMUXC_GPIO_AD_25_LPUART1_RXD }, \
+ { IOMUXC_GPIO_DISP_B2_10_LPUART2_TXD }, { IOMUXC_GPIO_DISP_B2_11_LPUART2_RXD }, \
+ { IOMUXC_GPIO_AD_30_LPUART3_TXD }, { IOMUXC_GPIO_AD_31_LPUART3_RXD }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_28_LPUART5_TXD }, { IOMUXC_GPIO_AD_29_LPUART5_RXD }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_00_LPUART7_TXD }, { IOMUXC_GPIO_AD_01_LPUART7_RXD }, \
+ { IOMUXC_GPIO_AD_02_LPUART8_TXD }, { IOMUXC_GPIO_AD_03_LPUART8_RXD }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_LPSR_04_LPUART11_TXD }, { IOMUXC_GPIO_LPSR_05_LPUART11_RXD }, \
+ { IOMUXC_GPIO_LPSR_10_LPUART12_TXD }, { IOMUXC_GPIO_LPSR_11_LPUART12_RXD },
+
+// Define the mapping hardware SPI # to logical SPI #
+// SCK/CS/SDO/SDI HW-SPI Logical SPI
+// D13/D10/D11/D12 LPSPI1 -> 0
+// D26/D28/D25/D24 LPSPI6 -> 1
+// D24/ - /D14/D15 LPSPI5 -> 2
+
+#define MICROPY_HW_SPI_INDEX { 1, 6, 5 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_AD_28_LPSPI1_SCK }, { IOMUXC_GPIO_AD_29_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_AD_30_LPSPI1_SOUT }, { IOMUXC_GPIO_AD_31_LPSPI1_SIN }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_LPSR_12_LPSPI5_SCK }, { IOMUXC_GPIO_LPSR_13_LPSPI5_PCS0 }, \
+ { IOMUXC_GPIO_LPSR_04_LPSPI5_SOUT }, { IOMUXC_GPIO_LPSR_05_LPSPI5_SIN }, \
+ { IOMUXC_GPIO_LPSR_10_LPSPI6_SCK }, { IOMUXC_GPIO_LPSR_09_LPSPI6_PCS0 }, \
+ { IOMUXC_GPIO_LPSR_11_LPSPI6_SOUT }, { IOMUXC_GPIO_LPSR_12_LPSPI6_SIN },
+
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
+
+// Define the mapping hardware I2C # to logical I2C #
+// SDA/SCL HW-I2C Logical I2C
+// D14/D15 LPI2C5 -> 0
+// D1/D0 LPI2C3 -> 1
+// A4/A5 LPI2C1 -> 2
+// D26/D25 LPI2C6 -> 3
+// D19/D18 LPI2C2 -> 4
+
+#define MICROPY_HW_I2C_INDEX { 5, 3, 1, 6, 2 }
+
+#define IOMUX_TABLE_I2C \
+ { IOMUXC_GPIO_AD_08_LPI2C1_SCL }, { IOMUXC_GPIO_AD_09_LPI2C1_SDA }, \
+ { IOMUXC_GPIO_AD_18_LPI2C2_SCL }, { IOMUXC_GPIO_AD_19_LPI2C2_SDA }, \
+ { IOMUXC_GPIO_DISP_B2_10_LPI2C3_SCL }, { IOMUXC_GPIO_DISP_B2_11_LPI2C3_SDA }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_LPSR_05_LPI2C5_SCL }, { IOMUXC_GPIO_LPSR_04_LPI2C5_SDA }, \
+ { IOMUXC_GPIO_LPSR_11_LPI2C6_SCL }, { IOMUXC_GPIO_LPSR_10_LPI2C6_SDA },
+
+#define MICROPY_PY_MACHINE_I2S (1)
+#define MICROPY_HW_I2S_NUM (1)
+#define I2S_CLOCK_MUX { 0, kCLOCK_Root_Sai1, kCLOCK_Root_Sai2, kCLOCK_Root_Sai3, kCLOCK_Root_Sai4 }
+#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx, kDmaRequestMuxSai3Rx, kDmaRequestMuxSai4Rx }
+#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx, kDmaRequestMuxSai3Tx, kDmaRequestMuxSai4Tx }
+#define I2S_WM8960_RX_MODE (1)
+#define I2S_AUDIO_PLL_CLOCK (4U)
+#define DMAMUX DMAMUX0
+
+#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
+ { \
+ .hw_id = _hwid, \
+ .fn = _fn, \
+ .mode = _mode, \
+ .name = MP_QSTR_##_pin, \
+ .iomux = {_iomux}, \
+ }
+
+#define I2S_GPIO_MAP \
+ { \
+ I2S_GPIO(1, MCK, TX, GPIO_AD_17, IOMUXC_GPIO_AD_17_SAI1_MCLK), \
+ I2S_GPIO(1, SCK, RX, GPIO_AD_19, IOMUXC_GPIO_AD_19_SAI1_RX_BCLK), \
+ I2S_GPIO(1, WS, RX, GPIO_AD_18, IOMUXC_GPIO_AD_18_SAI1_RX_SYNC), \
+ I2S_GPIO(1, SD, RX, GPIO_AD_20, IOMUXC_GPIO_AD_20_SAI1_RX_DATA00), \
+ I2S_GPIO(1, SCK, TX, GPIO_AD_22, IOMUXC_GPIO_AD_22_SAI1_TX_BCLK), \
+ I2S_GPIO(1, WS, TX, GPIO_AD_23, IOMUXC_GPIO_AD_23_SAI1_TX_SYNC), \
+ I2S_GPIO(1, SD, TX, GPIO_AD_21, IOMUXC_GPIO_AD_21_SAI1_TX_DATA00), \
+ }
+
+// USDHC1
+
+#define USDHC_DUMMY_PIN NULL, 0
+#define MICROPY_USDHC1 \
+ { \
+ .cmd = {GPIO_SD_B1_00_USDHC1_CMD}, \
+ .clk = { GPIO_SD_B1_01_USDHC1_CLK }, \
+ .cd_b = { USDHC_DUMMY_PIN }, \
+ .data0 = { GPIO_SD_B1_02_USDHC1_DATA0 }, \
+ .data1 = { GPIO_SD_B1_03_USDHC1_DATA1 }, \
+ .data2 = { GPIO_SD_B1_04_USDHC1_DATA2 }, \
+ .data3 = { GPIO_SD_B1_05_USDHC1_DATA3 }, \
+ }
+#define USDHC_DATA3_PULL_DOWN_ON_BOARD (1)
+
+// Network definitions
+
+// Transceiver Phy Parameters
+#define ENET_PHY_ADDRESS (2)
+#define ENET_PHY KSZ8081
+#define ENET_PHY_OPS phyksz8081_ops
+
+// 10/100 Ethernet PIN definitions
+#define ENET_RESET_PIN &pin_GPIO_LPSR_12
+#define ENET_INT_PIN &pin_GPIO_AD_12
+
+#define IOMUX_TABLE_ENET \
+ { IOMUXC_GPIO_DISP_B2_06_ENET_RX_DATA00, 0, 0x06u }, \
+ { IOMUXC_GPIO_DISP_B2_07_ENET_RX_DATA01, 0, 0x06u }, \
+ { IOMUXC_GPIO_DISP_B2_08_ENET_RX_EN, 0, 0x06u }, \
+ { IOMUXC_GPIO_DISP_B2_02_ENET_TX_DATA00, 0, 0x02u }, \
+ { IOMUXC_GPIO_DISP_B2_03_ENET_TX_DATA01, 0, 0x02u }, \
+ { IOMUXC_GPIO_DISP_B2_04_ENET_TX_EN, 0, 0x06u }, \
+ { IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK, 1, 0x03u }, \
+ { IOMUXC_GPIO_DISP_B2_09_ENET_RX_ER, 0, 0x06u }, \
+ { IOMUXC_GPIO_AD_33_ENET_MDIO, 0, 0x06u }, \
+ { IOMUXC_GPIO_AD_32_ENET_MDC, 0, 0x06u },
+
+// A second ETH port is present.
+#define ENET_DUAL_PORT (1)
+// 1G Transceiver Phy Parameters
+#define ENET_1_PHY_ADDRESS (1)
+#define ENET_1_PHY RTL8211F
+#define ENET_1_PHY_OPS phyrtl8211f_ops
+
+// 1G Ethernet PIN definitions
+// No INT pin for ENET_1G
+#define ENET_1_RESET_PIN &pin_GPIO_DISP_B2_13
+#define ENET_1_INT_PIN NULL
+
+#define IOMUX_TABLE_ENET_1 \
+ { IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_02_ENET_1G_RX_DATA00, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_03_ENET_1G_RX_DATA01, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_04_ENET_1G_RX_DATA02, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_05_ENET_1G_RX_DATA03, 0, 0x08U }, \
+ { IOMUXC_GPIO_DISP_B1_06_ENET_1G_TX_DATA03, 0, 0x0CU }, \
+ { IOMUXC_GPIO_DISP_B1_07_ENET_1G_TX_DATA02, 0, 0x0CU }, \
+ { IOMUXC_GPIO_DISP_B1_08_ENET_1G_TX_DATA01, 0, 0x0CU }, \
+ { IOMUXC_GPIO_DISP_B1_09_ENET_1G_TX_DATA00, 0, 0x0CU }, \
+ { IOMUXC_GPIO_DISP_B1_10_ENET_1G_TX_EN, 0, 0x0CU }, \
+ { IOMUXC_GPIO_DISP_B1_11_ENET_1G_TX_CLK_IO, 0, 0x0CU }, \
+ { IOMUXC_GPIO_EMC_B2_20_ENET_1G_MDIO, 0, 0x06u }, \
+ { IOMUXC_GPIO_EMC_B2_19_ENET_1G_MDC, 0, 0x06u },
+
+// --- SEMC --- //
+#define MIMXRT_IOMUXC_SEMC_DATA00 IOMUXC_GPIO_EMC_B1_00_SEMC_DATA00
+#define MIMXRT_IOMUXC_SEMC_DATA01 IOMUXC_GPIO_EMC_B1_01_SEMC_DATA01
+#define MIMXRT_IOMUXC_SEMC_DATA02 IOMUXC_GPIO_EMC_B1_02_SEMC_DATA02
+#define MIMXRT_IOMUXC_SEMC_DATA03 IOMUXC_GPIO_EMC_B1_03_SEMC_DATA03
+#define MIMXRT_IOMUXC_SEMC_DATA04 IOMUXC_GPIO_EMC_B1_04_SEMC_DATA04
+#define MIMXRT_IOMUXC_SEMC_DATA05 IOMUXC_GPIO_EMC_B1_05_SEMC_DATA05
+#define MIMXRT_IOMUXC_SEMC_DATA06 IOMUXC_GPIO_EMC_B1_06_SEMC_DATA06
+#define MIMXRT_IOMUXC_SEMC_DATA07 IOMUXC_GPIO_EMC_B1_07_SEMC_DATA07
+#define MIMXRT_IOMUXC_SEMC_DATA08 IOMUXC_GPIO_EMC_B1_30_SEMC_DATA08
+#define MIMXRT_IOMUXC_SEMC_DATA09 IOMUXC_GPIO_EMC_B1_31_SEMC_DATA09
+#define MIMXRT_IOMUXC_SEMC_DATA10 IOMUXC_GPIO_EMC_B1_32_SEMC_DATA10
+#define MIMXRT_IOMUXC_SEMC_DATA11 IOMUXC_GPIO_EMC_B1_33_SEMC_DATA11
+#define MIMXRT_IOMUXC_SEMC_DATA12 IOMUXC_GPIO_EMC_B1_34_SEMC_DATA12
+#define MIMXRT_IOMUXC_SEMC_DATA13 IOMUXC_GPIO_EMC_B1_35_SEMC_DATA13
+#define MIMXRT_IOMUXC_SEMC_DATA14 IOMUXC_GPIO_EMC_B1_36_SEMC_DATA14
+#define MIMXRT_IOMUXC_SEMC_DATA15 IOMUXC_GPIO_EMC_B1_37_SEMC_DATA15
+
+#define MIMXRT_IOMUXC_SEMC_ADDR00 IOMUXC_GPIO_EMC_B1_09_SEMC_ADDR00
+#define MIMXRT_IOMUXC_SEMC_ADDR01 IOMUXC_GPIO_EMC_B1_10_SEMC_ADDR01
+#define MIMXRT_IOMUXC_SEMC_ADDR02 IOMUXC_GPIO_EMC_B1_11_SEMC_ADDR02
+#define MIMXRT_IOMUXC_SEMC_ADDR03 IOMUXC_GPIO_EMC_B1_12_SEMC_ADDR03
+#define MIMXRT_IOMUXC_SEMC_ADDR04 IOMUXC_GPIO_EMC_B1_13_SEMC_ADDR04
+#define MIMXRT_IOMUXC_SEMC_ADDR05 IOMUXC_GPIO_EMC_B1_14_SEMC_ADDR05
+#define MIMXRT_IOMUXC_SEMC_ADDR06 IOMUXC_GPIO_EMC_B1_15_SEMC_ADDR06
+#define MIMXRT_IOMUXC_SEMC_ADDR07 IOMUXC_GPIO_EMC_B1_16_SEMC_ADDR07
+#define MIMXRT_IOMUXC_SEMC_ADDR08 IOMUXC_GPIO_EMC_B1_17_SEMC_ADDR08
+#define MIMXRT_IOMUXC_SEMC_ADDR09 IOMUXC_GPIO_EMC_B1_18_SEMC_ADDR09
+#define MIMXRT_IOMUXC_SEMC_ADDR10 IOMUXC_GPIO_EMC_B1_23_SEMC_ADDR10
+#define MIMXRT_IOMUXC_SEMC_ADDR11 IOMUXC_GPIO_EMC_B1_19_SEMC_ADDR11
+#define MIMXRT_IOMUXC_SEMC_ADDR12 IOMUXC_GPIO_EMC_B1_20_SEMC_ADDR12
+
+#define MIMXRT_IOMUXC_SEMC_BA0 IOMUXC_GPIO_EMC_B1_21_SEMC_BA0
+#define MIMXRT_IOMUXC_SEMC_BA1 IOMUXC_GPIO_EMC_B1_22_SEMC_BA1
+#define MIMXRT_IOMUXC_SEMC_CAS IOMUXC_GPIO_EMC_B1_24_SEMC_CAS
+#define MIMXRT_IOMUXC_SEMC_RAS IOMUXC_GPIO_EMC_B1_25_SEMC_RAS
+#define MIMXRT_IOMUXC_SEMC_CLK IOMUXC_GPIO_EMC_B1_26_SEMC_CLK
+#define MIMXRT_IOMUXC_SEMC_CKE IOMUXC_GPIO_EMC_B1_27_SEMC_CKE
+#define MIMXRT_IOMUXC_SEMC_WE IOMUXC_GPIO_EMC_B1_28_SEMC_WE
+#define MIMXRT_IOMUXC_SEMC_DM00 IOMUXC_GPIO_EMC_B1_08_SEMC_DM00
+#define MIMXRT_IOMUXC_SEMC_DM01 IOMUXC_GPIO_EMC_B1_38_SEMC_DM01
+#define MIMXRT_IOMUXC_SEMC_DQS IOMUXC_GPIO_EMC_B1_39_SEMC_DQS
+
+#define MIMXRT_IOMUXC_SEMC_CS0 IOMUXC_GPIO_EMC_B1_29_SEMC_CS0
+
+#define MIMXRT_IOMUXC_SEMC_DATA16 IOMUXC_GPIO_EMC_B2_00_SEMC_DATA16
+#define MIMXRT_IOMUXC_SEMC_DATA17 IOMUXC_GPIO_EMC_B2_01_SEMC_DATA17
+#define MIMXRT_IOMUXC_SEMC_DATA18 IOMUXC_GPIO_EMC_B2_02_SEMC_DATA18
+#define MIMXRT_IOMUXC_SEMC_DATA19 IOMUXC_GPIO_EMC_B2_03_SEMC_DATA19
+#define MIMXRT_IOMUXC_SEMC_DATA20 IOMUXC_GPIO_EMC_B2_04_SEMC_DATA20
+#define MIMXRT_IOMUXC_SEMC_DATA21 IOMUXC_GPIO_EMC_B2_05_SEMC_DATA21
+#define MIMXRT_IOMUXC_SEMC_DATA22 IOMUXC_GPIO_EMC_B2_06_SEMC_DATA22
+#define MIMXRT_IOMUXC_SEMC_DATA23 IOMUXC_GPIO_EMC_B2_07_SEMC_DATA23
+#define MIMXRT_IOMUXC_SEMC_DM02 IOMUXC_GPIO_EMC_B2_08_SEMC_DM02
+
+#define MIMXRT_IOMUXC_SEMC_DATA24 IOMUXC_GPIO_EMC_B2_09_SEMC_DATA24
+#define MIMXRT_IOMUXC_SEMC_DATA25 IOMUXC_GPIO_EMC_B2_10_SEMC_DATA25
+#define MIMXRT_IOMUXC_SEMC_DATA26 IOMUXC_GPIO_EMC_B2_11_SEMC_DATA26
+#define MIMXRT_IOMUXC_SEMC_DATA27 IOMUXC_GPIO_EMC_B2_12_SEMC_DATA27
+#define MIMXRT_IOMUXC_SEMC_DATA28 IOMUXC_GPIO_EMC_B2_13_SEMC_DATA28
+#define MIMXRT_IOMUXC_SEMC_DATA29 IOMUXC_GPIO_EMC_B2_14_SEMC_DATA29
+#define MIMXRT_IOMUXC_SEMC_DATA30 IOMUXC_GPIO_EMC_B2_15_SEMC_DATA30
+#define MIMXRT_IOMUXC_SEMC_DATA31 IOMUXC_GPIO_EMC_B2_16_SEMC_DATA31
+#define MIMXRT_IOMUXC_SEMC_DM03 IOMUXC_GPIO_EMC_B2_17_SEMC_DM03
+#define MIMXRT_IOMUXC_SEMC_DQS4 IOMUXC_GPIO_EMC_B2_18_SEMC_DQS4
+
+#if MICROPY_PY_MACHINE_I2S
+#define MICROPY_BOARD_ROOT_POINTERS \
+ struct _machine_i2s_obj_t *machine_i2s_obj[MICROPY_HW_I2S_NUM];
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk
new file mode 100644
index 000000000000..25747a52c6be
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1170_EVK/mpconfigboard.mk
@@ -0,0 +1,25 @@
+MCU_SERIES = MIMXRT1176
+MCU_VARIANT = MIMXRT1176DVMAA
+MCU_CORE = _cm7
+
+MICROPY_FLOAT_IMPL = double
+MICROPY_PY_MACHINE_SDCARD = 1
+MICROPY_HW_FLASH_TYPE ?= qspi_nor_flash
+MICROPY_HW_FLASH_SIZE ?= 0x1000000 # 16MB
+MICROPY_HW_FLASH_RESERVED ?= 0x100000 # 1MB CM4 Code address space
+
+MICROPY_HW_SDRAM_AVAIL = 1
+MICROPY_HW_SDRAM_SIZE = 0x4000000 # 64MB
+
+MICROPY_PY_LWIP = 1
+MICROPY_PY_SSL = 1
+MICROPY_SSL_MBEDTLS = 1
+
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
+CFLAGS += -DCPU_MIMXRT1176DVMAA_cm7 \
+ -DMIMXRT117x_SERIES \
+ -DENET_ENHANCEDBUFFERDESCRIPTOR_MODE=1 \
+ -DCPU_HEADER_H='<$(MCU_SERIES)$(MCU_CORE).h>' \
+ -DUSB1_BASE=USB_OTG1_BASE \
+ -DUSB2_BASE=USB_OTG2_BASE
diff --git a/ports/mimxrt/boards/MIMXRT1170_EVK/pins.csv b/ports/mimxrt/boards/MIMXRT1170_EVK/pins.csv
new file mode 100644
index 000000000000..77f87e8ba15c
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1170_EVK/pins.csv
@@ -0,0 +1,59 @@
+D0,GPIO_DISP_B2_11
+D1,GPIO_DISP_B2_10
+D2,GPIO_DISP_B2_12
+D3,GPIO_AD_04
+D4,GPIO_AD_06
+D5,GPIO_AD_05
+D6,GPIO_AD_00
+D7,GPIO_AD_14
+D8,GPIO_AD_07
+D9,GPIO_AD_01
+D10,GPIO_AD_29
+D11,GPIO_AD_30
+D12,GPIO_AD_31
+D13,GPIO_AD_28
+D14,GPIO_LPSR_04
+D15,GPIO_LPSR_05
+D16,GPIO_AD_19
+D17,GPIO_DISP_B2_12
+D18,GPIO_AD_18
+D19,GPIO_AD_20
+D20,GPIO_AD_21
+D21,GPIO_AD_22
+D22,GPIO_AD_23
+D23,GPIO_AD_17
+D24,GPIO_LPSR_12
+D25,GPIO_LPSR_11
+D26,GPIO_LPSR_10
+D27,GPIO_LPSR_09
+D29,GPIO_DISP_B2_11
+D30,GPIO_DISP_B2_10
+D31,GPIO_AD_05
+D32,GPIO_AD_04
+D33,GPIO_AD_03
+D34,GPIO_AD_02
+D35,GPIO_AD_01
+D36,GPIO_AD_00
+A0,GPIO_AD_10
+A1,GPIO_AD_11
+A2,GPIO_AD_12
+A3,GPIO_AD_13
+A4,GPIO_AD_09
+A5,GPIO_AD_08
+RX,GPIO_DISP_B2_11
+TX,GPIO_DISP_B2_10
+SCL,GPIO_LPSR_05
+SDA,GPIO_LPSR_04
+SCK,GPIO_AD_28
+SDI,GPIO_AD_31
+SDO,GPIO_AD_30
+CS,GPIO_AD_29
+LED1,GPIO_AD_04
+LED2,GPIO_AD_26
+MCK,GPIO_AD_17
+SCK_RX,GPIO_AD_19
+WS_RX,GPIO_AD_18
+SD_RX,GPIO_AD_20
+SCK_TX,GPIO_AD_22
+WS_TX,GPIO_AD_23
+SD_TX,GPIO_AD_21
diff --git a/ports/mimxrt/boards/MIMXRT1176.ld b/ports/mimxrt/boards/MIMXRT1176.ld
new file mode 100644
index 000000000000..2408977b9410
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1176.ld
@@ -0,0 +1,59 @@
+/* Memory configuration */
+
+/* Reserved Area
+ * Users can create a reserved area at the end of the flash memory via
+ * 'reserved_size' variable. The size of the reserved area should be a multiple
+ * of the sector size of the flash memory!
+ */
+#if defined MICROPY_HW_FLASH_RESERVED
+reserved_size = MICROPY_HW_FLASH_RESERVED;
+#endif
+
+#if MICROPY_HW_FLASH_TYPE == qspi_nor
+flash_start = 0x30000000;
+#else
+#error Unknown MICROPY_HW_FLASH_TYPE
+#endif
+flash_size = MICROPY_HW_FLASH_SIZE;
+flash_end = DEFINED(reserved_size) ? ((flash_start) + (flash_size - reserved_size)) : ((flash_start) + (flash_size));
+flash_config_start = flash_start + 0x400; /* TODO: check why config_start is on 0x400 instead of 0x0 offset */
+flash_config_size = 0x00000C00;
+ivt_start = flash_start + 0x00001000;
+ivt_size = 0x00001000;
+interrupts_start = flash_start + 0x00002000;
+interrupts_size = 0x00000400;
+text_start = flash_start + 0x00002400;
+vfs_start = flash_start + 0x00200000;
+
+#if defined MULTI_CORE
+m_core1_image_start = vfs_start - 0x00040000;
+m_core1_image_size = 0x00040000;
+#endif
+
+text_size = ((vfs_start) - (text_start));
+vfs_size = ((flash_end) - (vfs_start));
+itcm_start = 0x00000000;
+itcm_size = 0x00020000;
+dtcm_start = 0x20000000;
+dtcm_size = 0x00020000;
+ocrm_start = 0x20240000;
+ocrm_size = 0x00100000;
+
+#ifdef MICROPY_HW_SDRAM_AVAIL
+sdram_start = 0x80000000;
+sdram_size = MICROPY_HW_SDRAM_SIZE;
+#endif
+
+/* 32kiB stack. */
+__stack_size__ = 0x8000;
+_estack = __StackTop;
+_sstack = __StackLimit;
+
+#ifdef MICROPY_HW_SDRAM_AVAIL
+_gc_heap_start = ORIGIN(m_sdram);
+_gc_heap_end = ORIGIN(m_sdram) + LENGTH(m_sdram);
+#else
+/* Use second OCRAM bank for GC heap. */
+_gc_heap_start = ORIGIN(m_ocrm);
+_gc_heap_end = ORIGIN(m_ocrm) + LENGTH(m_ocrm);
+#endif
diff --git a/ports/mimxrt/boards/MIMXRT1176_af.csv b/ports/mimxrt/boards/MIMXRT1176_af.csv
new file mode 100644
index 000000000000..fe31f502e4ed
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1176_af.csv
@@ -0,0 +1,173 @@
+Pad,ALT0,ALT1,ALT2,ALT3,ALT4,ALT5,ALT6,ALT7,ALT8,ALT9,ALT10,ADC,ACMP,Default
+GPIO_SD_B1_00,USDHC1_CMD,,XBAR1_INOUT20,GPT4_CAPTURE1,,GPIO4_IO03,FLEXSPI2_A_SS0_B,,KPP_ROW07,,GPIO10_IO03,,,
+GPIO_SD_B1_01,USDHC1_CLK,,XBAR1_INOUT21,GPT4_CAPTURE2,,GPIO4_IO04,FLEXSPI2_A_SCLK,,KPP_COL07,,GPIO10_IO04,,,
+GPIO_SD_B1_02,USDHC1_DATA0,,XBAR1_INOUT22,GPT4_COMPARE1,,GPIO4_IO05,FLEXSPI2_A_DATA00,,KPP_ROW06,FLEXSPI1_A_SS1_B,GPIO10_IO05,,,
+GPIO_SD_B1_03,USDHC1_DATA1,,XBAR1_INOUT23,GPT4_COMPARE2,,GPIO4_IO06,FLEXSPI2_A_DATA01,,KPP_COL06,FLEXSPI1_B_SS1_B,GPIO10_IO06,,,
+GPIO_SD_B1_04,USDHC1_DATA2,,XBAR1_INOUT24,GPT4_COMPARE3,,GPIO4_IO07,FLEXSPI2_A_DATA02,,FLEXSPI1_B_SS0_B,ENET_QOS_1588_EVENT2_AUX_IN,GPIO10_IO07,,,
+GPIO_SD_B1_05,USDHC1_DATA3,,XBAR1_INOUT25,GPT4_CLK,,GPIO4_IO08,FLEXSPI2_A_DATA03,,FLEXSPI1_B_DQS,ENET_QOS_1588_EVENT3_AUX_IN,GPIO10_IO08,,,
+GPIO_SD_B2_00,USDHC2_DATA3,FLEXSPI1_B_DATA03,ENET_1G_RX_EN,LPUART9_TXD,LPSPI4_SCK,GPIO4_IO09,,,,,GPIO10_IO09,,,
+GPIO_SD_B2_01,USDHC2_DATA2,FLEXSPI1_B_DATA02,ENET_1G_RX_CLK,LPUART9_RXD,LPSPI4_PCS0,GPIO4_IO10,,,,,GPIO10_IO10,,,
+GPIO_SD_B2_02,USDHC2_DATA1,FLEXSPI1_B_DATA01,ENET_1G_RX_DATA00,LPUART9_CTS_B,LPSPI4_SOUT,GPIO4_IO11,,,,,GPIO10_IO11,,,
+GPIO_SD_B2_03,USDHC2_DATA0,FLEXSPI1_B_DATA00,ENET_1G_RX_DATA01,LPUART9_RTS_B,LPSPI4_SIN,GPIO4_IO12,,,,,GPIO10_IO12,,,
+GPIO_SD_B2_04,USDHC2_CLK,FLEXSPI1_B_SCLK,ENET_1G_RX_DATA02,FLEXSPI1_A_SS1_B,LPSPI4_PCS1,GPIO4_IO13,,,,,GPIO10_IO13,,,
+GPIO_SD_B2_05,USDHC2_CMD,FLEXSPI1_A_DQS,ENET_1G_RX_DATA03,FLEXSPI1_B_SS0_B,LPSPI4_PCS2,GPIO4_IO14,,,,,GPIO10_IO14,,,
+GPIO_SD_B2_06,USDHC2_RESET_B,FLEXSPI1_A_SS0_B,ENET_1G_TX_DATA03,LPSPI4_PCS3,GPT6_CAPTURE1,GPIO4_IO15,,,,,GPIO10_IO15,,,
+GPIO_SD_B2_07,USDHC2_STROBE,FLEXSPI1_A_SCLK,ENET_1G_TX_DATA02,LPUART3_CTS_B,GPT6_CAPTURE2,GPIO4_IO16,LPSPI2_SCK,,ENET_TX_ER,ENET_QOS_REF_CLK,GPIO10_IO16,,,
+GPIO_SD_B2_08,USDHC2_DATA4,FLEXSPI1_A_DATA00,ENET_1G_TX_DATA01,LPUART3_RTS_B,GPT6_COMPARE1,GPIO4_IO17,LPSPI2_PCS0,,,,GPIO10_IO17,,,
+GPIO_SD_B2_09,USDHC2_DATA5,FLEXSPI1_A_DATA01,ENET_1G_TX_DATA00,LPUART5_CTS_B,GPT6_COMPARE2,GPIO4_IO18,LPSPI2_SOUT,,,,GPIO10_IO18,,,
+GPIO_SD_B2_10,USDHC2_DATA6,FLEXSPI1_A_DATA02,ENET_1G_TX_EN,LPUART5_RTS_B,GPT6_COMPARE3,GPIO4_IO19,LPSPI2_SIN,,,,GPIO10_IO19,,,
+GPIO_SD_B2_11,USDHC2_DATA7,FLEXSPI1_A_DATA03,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,GPT6_CLK,GPIO4_IO20,LPSPI2_PCS1,,,,GPIO10_IO20,,,
+GPIO_EMC_B1_00,SEMC_DATA00,FLEXPWM4_PWM0_A,,,,GPIO1_IO00,,,FLEXIO1_D00,,GPIO7_IO00,,,
+GPIO_EMC_B1_01,SEMC_DATA01,FLEXPWM4_PWM0_B,,,,GPIO1_IO01,,,FLEXIO1_D01,,GPIO7_IO01,,,
+GPIO_EMC_B1_02,SEMC_DATA02,FLEXPWM4_PWM1_A,,,,GPIO1_IO02,,,FLEXIO1_D02,,GPIO7_IO02,,,
+GPIO_EMC_B1_03,SEMC_DATA03,FLEXPWM4_PWM1_B,,,,GPIO1_IO03,,,FLEXIO1_D03,,GPIO7_IO03,,,
+GPIO_EMC_B1_04,SEMC_DATA04,FLEXPWM4_PWM2_A,,,,GPIO1_IO04,,,FLEXIO1_D04,,GPIO7_IO04,,,
+GPIO_EMC_B1_05,SEMC_DATA05,FLEXPWM4_PWM2_B,,,,GPIO1_IO05,,,FLEXIO1_D05,,GPIO7_IO05,,,
+GPIO_EMC_B1_06,SEMC_DATA06,FLEXPWM2_PWM0_A,,,,GPIO1_IO06,,,FLEXIO1_D06,,GPIO7_IO06,,,
+GPIO_EMC_B1_07,SEMC_DATA07,FLEXPWM2_PWM0_B,,,,GPIO1_IO07,,,FLEXIO1_D07,,GPIO7_IO07,,,
+GPIO_EMC_B1_08,SEMC_DM00,FLEXPWM2_PWM1_A,,,,GPIO1_IO08,,,FLEXIO1_D08,,GPIO7_IO08,,,
+GPIO_EMC_B1_09,SEMC_ADDR00,FLEXPWM2_PWM1_B,GPT5_CAPTURE1,,,GPIO1_IO09,,,FLEXIO1_D09,,GPIO7_IO09,,,
+GPIO_EMC_B1_10,SEMC_ADDR01,FLEXPWM2_PWM2_A,GPT5_CAPTURE2,,,GPIO1_IO10,,,FLEXIO1_D10,,GPIO7_IO10,,,
+GPIO_EMC_B1_11,SEMC_ADDR02,FLEXPWM2_PWM2_B,GPT5_COMPARE1,,,GPIO1_IO11,,,FLEXIO1_D11,,GPIO7_IO11,,,
+GPIO_EMC_B1_12,SEMC_ADDR03,XBAR1_INOUT04,GPT5_COMPARE2,,,GPIO1_IO12,,,FLEXIO1_D12,,GPIO7_IO12,,,
+GPIO_EMC_B1_13,SEMC_ADDR04,XBAR1_INOUT05,GPT5_COMPARE3,,,GPIO1_IO13,,,FLEXIO1_D13,,GPIO7_IO13,,,
+GPIO_EMC_B1_14,SEMC_ADDR05,XBAR1_INOUT06,GPT5_CLK,,,GPIO1_IO14,,,FLEXIO1_D14,,GPIO7_IO14,,,
+GPIO_EMC_B1_15,SEMC_ADDR06,XBAR1_INOUT07,,,,GPIO1_IO15,,,FLEXIO1_D15,,GPIO7_IO15,,,
+GPIO_EMC_B1_16,SEMC_ADDR07,XBAR1_INOUT08,,,,GPIO1_IO16,,,FLEXIO1_D16,,GPIO7_IO16,,,
+GPIO_EMC_B1_17,SEMC_ADDR08,FLEXPWM4_PWM3_A,TMR1_TIMER0,,,GPIO1_IO17,,,FLEXIO1_D17,,GPIO7_IO17,,,
+GPIO_EMC_B1_18,SEMC_ADDR09,FLEXPWM4_PWM3_B,TMR2_TIMER0,,,GPIO1_IO18,,,FLEXIO1_D18,,GPIO7_IO18,,,
+GPIO_EMC_B1_19,SEMC_ADDR11,FLEXPWM2_PWM3_A,TMR3_TIMER0,,,GPIO1_IO19,,,FLEXIO1_D19,,GPIO7_IO19,,,
+GPIO_EMC_B1_20,SEMC_ADDR12,FLEXPWM2_PWM3_B,TMR4_TIMER0,,,GPIO1_IO20,,,FLEXIO1_D20,,GPIO7_IO20,,,
+GPIO_EMC_B1_21,SEMC_BA0,FLEXPWM3_PWM3_A,,,,GPIO1_IO21,,,FLEXIO1_D21,,GPIO7_IO21,,,
+GPIO_EMC_B1_22,SEMC_BA1,FLEXPWM3_PWM3_B,,,,GPIO1_IO22,,,FLEXIO1_D22,,GPIO7_IO22,,,
+GPIO_EMC_B1_23,SEMC_ADDR10,FLEXPWM1_PWM0_A,,,,GPIO1_IO23,,,FLEXIO1_D23,,GPIO7_IO23,,,
+GPIO_EMC_B1_24,SEMC_CAS,FLEXPWM1_PWM0_B,,,,GPIO1_IO24,,,FLEXIO1_D24,,GPIO7_IO24,,,
+GPIO_EMC_B1_25,SEMC_RAS,FLEXPWM1_PWM1_A,,,,GPIO1_IO25,,,FLEXIO1_D25,,GPIO7_IO25,,,
+GPIO_EMC_B1_26,SEMC_CLK,FLEXPWM1_PWM1_B,,,,GPIO1_IO26,,,FLEXIO1_D26,,GPIO7_IO26,,,
+GPIO_EMC_B1_27,SEMC_CKE,FLEXPWM1_PWM2_A,,,,GPIO1_IO27,,,FLEXIO1_D27,,GPIO7_IO27,,,
+GPIO_EMC_B1_28,SEMC_WE,FLEXPWM1_PWM2_B,,,,GPIO1_IO28,,,FLEXIO1_D28,,GPIO7_IO28,,,
+GPIO_EMC_B1_29,SEMC_CS0,FLEXPWM3_PWM0_A,,,,GPIO1_IO29,,,FLEXIO1_D29,,GPIO7_IO29,,,
+GPIO_EMC_B1_30,SEMC_DATA08,FLEXPWM3_PWM0_B,,,,GPIO1_IO30,,,FLEXIO1_D30,,GPIO7_IO30,,,
+GPIO_EMC_B1_31,SEMC_DATA09,FLEXPWM3_PWM1_A,,,,GPIO1_IO31,,,FLEXIO1_D31,,GPIO7_IO31,,,
+GPIO_EMC_B1_32,SEMC_DATA10,FLEXPWM3_PWM1_B,,,,GPIO2_IO00,,,,,GPIO8_IO00,,,
+GPIO_EMC_B1_33,SEMC_DATA11,FLEXPWM3_PWM2_A,,,,GPIO2_IO01,,,,,GPIO8_IO01,,,
+GPIO_EMC_B1_34,SEMC_DATA12,FLEXPWM3_PWM2_B,,,,GPIO2_IO02,,,,,GPIO8_IO02,,,
+GPIO_EMC_B1_35,SEMC_DATA13,XBAR1_INOUT09,,,,GPIO2_IO03,,,,,GPIO8_IO03,,,
+GPIO_EMC_B1_36,SEMC_DATA14,XBAR1_INOUT10,,,,GPIO2_IO04,,,,,GPIO8_IO04,,,
+GPIO_EMC_B1_37,SEMC_DATA15,XBAR1_INOUT11,,,,GPIO2_IO05,,,,,GPIO8_IO05,,,
+GPIO_EMC_B1_38,SEMC_DM01,FLEXPWM1_PWM3_A,TMR1_TIMER1,,,GPIO2_IO06,,,,,GPIO8_IO06,,,
+GPIO_EMC_B1_39,SEMC_DQS,FLEXPWM1_PWM3_B,TMR2_TIMER1,,,GPIO2_IO07,,,,,GPIO8_IO07,,,
+GPIO_EMC_B1_40,SEMC_RDY,XBAR1_INOUT12,MQS_RIGHT,LPUART6_TXD,,GPIO2_IO08,,ENET_1G_MDC,,CCM_CLKO1,GPIO8_IO08,,,
+GPIO_EMC_B1_41,SEMC_CSX00,XBAR1_INOUT13,MQS_LEFT,LPUART6_RXD,FLEXSPI2_B_DATA07,GPIO2_IO09,,ENET_1G_MDIO,,CCM_CLKO2,GPIO8_IO09,,,
+GPIO_EMC_B2_00,SEMC_DATA16,CCM_ENET_REF_CLK_25M,TMR3_TIMER1,LPUART6_CTS_B,FLEXSPI2_B_DATA06,GPIO2_IO10,XBAR1_INOUT20,ENET_QOS_1588_EVENT1_OUT,LPSPI1_SCK,LPI2C2_SCL,GPIO8_IO10,,,
+GPIO_EMC_B2_01,SEMC_DATA17,USDHC2_CD_B,TMR4_TIMER1,LPUART6_RTS_B,FLEXSPI2_B_DATA05,GPIO2_IO11,XBAR1_INOUT21,ENET_QOS_1588_EVENT1_IN,LPSPI1_PCS0,LPI2C2_SDA,GPIO8_IO11,,,
+GPIO_EMC_B2_02,SEMC_DATA18,USDHC2_WP,,VIDEO_MUX_CSI_DATA23,FLEXSPI2_B_DATA04,GPIO2_IO12,XBAR1_INOUT22,ENET_QOS_1588_EVENT1_AUX_IN,LPSPI1_SOUT,,GPIO8_IO12,,,
+GPIO_EMC_B2_03,SEMC_DATA19,USDHC2_VSELECT,,VIDEO_MUX_CSI_DATA22,FLEXSPI2_B_DATA03,GPIO2_IO13,XBAR1_INOUT23,ENET_1G_TX_DATA03,LPSPI1_SIN,,GPIO8_IO13,,,
+GPIO_EMC_B2_04,SEMC_DATA20,USDHC2_RESET_B,SAI2_MCLK,VIDEO_MUX_CSI_DATA21,FLEXSPI2_B_DATA02,GPIO2_IO14,XBAR1_INOUT24,ENET_1G_TX_DATA02,LPSPI3_SCK,,GPIO8_IO14,,,
+GPIO_EMC_B2_05,SEMC_DATA21,GPT3_CLK,SAI2_RX_SYNC,VIDEO_MUX_CSI_DATA20,FLEXSPI2_B_DATA01,GPIO2_IO15,XBAR1_INOUT25,ENET_1G_RX_CLK,LPSPI3_PCS0,PIT1_TRIGGER0,GPIO8_IO15,,,
+GPIO_EMC_B2_06,SEMC_DATA22,GPT3_CAPTURE1,SAI2_RX_BCLK,VIDEO_MUX_CSI_DATA19,FLEXSPI2_B_DATA00,GPIO2_IO16,XBAR1_INOUT26,ENET_1G_TX_ER,LPSPI3_SOUT,PIT1_TRIGGER1,GPIO8_IO16,,,
+GPIO_EMC_B2_07,SEMC_DATA23,GPT3_CAPTURE2,SAI2_RX_DATA,VIDEO_MUX_CSI_DATA18,FLEXSPI2_B_DQS,GPIO2_IO17,XBAR1_INOUT27,ENET_1G_RX_DATA03,LPSPI3_SIN,PIT1_TRIGGER2,GPIO8_IO17,,,
+GPIO_EMC_B2_08,SEMC_DM02,GPT3_COMPARE1,SAI2_TX_DATA,VIDEO_MUX_CSI_DATA17,FLEXSPI2_B_SS0_B,GPIO2_IO18,XBAR1_INOUT28,ENET_1G_RX_DATA02,LPSPI3_PCS1,PIT1_TRIGGER3,GPIO8_IO18,,,
+GPIO_EMC_B2_09,SEMC_DATA24,GPT3_COMPARE2,SAI2_TX_BCLK,VIDEO_MUX_CSI_DATA16,FLEXSPI2_B_SCLK,GPIO2_IO19,XBAR1_INOUT29,ENET_1G_CRS,LPSPI3_PCS2,TMR1_TIMER0,GPIO8_IO19,,,
+GPIO_EMC_B2_10,SEMC_DATA25,GPT3_COMPARE3,SAI2_TX_SYNC,VIDEO_MUX_CSI_FIELD,FLEXSPI2_A_SCLK,GPIO2_IO20,XBAR1_INOUT30,ENET_1G_COL,LPSPI3_PCS3,TMR1_TIMER1,GPIO8_IO20,,,
+GPIO_EMC_B2_11,SEMC_DATA26,SPDIF_IN,ENET_1G_TX_DATA00,SAI3_RX_SYNC,FLEXSPI2_A_SS0_B,GPIO2_IO21,XBAR1_INOUT31,,EMVSIM1_IO,TMR1_TIMER2,GPIO8_IO21,,,
+GPIO_EMC_B2_12,SEMC_DATA27,SPDIF_OUT,ENET_1G_TX_DATA01,SAI3_RX_BCLK,FLEXSPI2_A_DQS,GPIO2_IO22,XBAR1_INOUT32,,EMVSIM1_CLK,TMR1_TIMER3,GPIO8_IO22,,,
+GPIO_EMC_B2_13,SEMC_DATA28,,ENET_1G_TX_EN,SAI3_RX_DATA,FLEXSPI2_A_DATA00,GPIO2_IO23,XBAR1_INOUT33,,EMVSIM1_RST,TMR2_TIMER0,GPIO8_IO23,,,
+GPIO_EMC_B2_14,SEMC_DATA29,,ENET_1G_TX_CLK_IO,SAI3_TX_DATA,FLEXSPI2_A_DATA01,GPIO2_IO24,XBAR1_INOUT34,SFA_ipp_do_atx_clk_under_test,EMVSIM1_SVEN,TMR2_TIMER1,GPIO8_IO24,,,
+GPIO_EMC_B2_15,SEMC_DATA30,,ENET_1G_RX_DATA00,SAI3_TX_BCLK,FLEXSPI2_A_DATA02,GPIO2_IO25,XBAR1_INOUT35,,EMVSIM1_PD,TMR2_TIMER2,GPIO8_IO25,,,
+GPIO_EMC_B2_16,SEMC_DATA31,XBAR1_INOUT14,ENET_1G_RX_DATA01,SAI3_TX_SYNC,FLEXSPI2_A_DATA03,GPIO2_IO26,,,EMVSIM1_POWER_FAIL,TMR2_TIMER3,GPIO8_IO26,,,
+GPIO_EMC_B2_17,SEMC_DM03,XBAR1_INOUT15,ENET_1G_RX_EN,SAI3_MCLK,FLEXSPI2_A_DATA04,GPIO2_IO27,,,WDOG1_ANY,TMR3_TIMER0,GPIO8_IO27,,,
+GPIO_EMC_B2_18,SEMC_DQS4,XBAR1_INOUT16,ENET_1G_RX_ER,EWM_OUT_B,FLEXSPI2_A_DATA05,GPIO2_IO28,FLEXSPI1_A_DQS,,WDOG1_B,TMR3_TIMER1,GPIO8_IO28,,,
+GPIO_EMC_B2_19,SEMC_CLKX00,ENET_MDC,ENET_1G_MDC,ENET_1G_REF_CLK,FLEXSPI2_A_DATA06,GPIO2_IO29,,,ENET_QOS_MDC,TMR3_TIMER2,GPIO8_IO29,,,
+GPIO_EMC_B2_20,SEMC_CLKX01,ENET_MDIO,ENET_1G_MDIO,ENET_QOS_REF_CLK,FLEXSPI2_A_DATA07,GPIO2_IO30,,,ENET_QOS_MDIO,TMR3_TIMER3,GPIO8_IO30,,,
+GPIO_SNVS_00,SNVS_TAMPER0,,,,,GPIO13_IO03,,,,,,,,
+GPIO_SNVS_01,SNVS_TAMPER1,,,,,GPIO13_IO04,,,,,,,,
+GPIO_SNVS_02,SNVS_TAMPER2,,,,,GPIO13_IO05,,,,,,,,
+GPIO_SNVS_03,SNVS_TAMPER3,,,,,GPIO13_IO06,,,,,,,,
+GPIO_SNVS_04,SNVS_TAMPER4,,,,,GPIO13_IO07,,,,,,,,
+GPIO_SNVS_05,SNVS_TAMPER5,,,,,GPIO13_IO08,,,,,,,,
+GPIO_SNVS_06,SNVS_TAMPER6,,,,,GPIO13_IO09,,,,,,,,
+GPIO_SNVS_07,SNVS_TAMPER7,,,,,GPIO13_IO10,,,,,,,,
+GPIO_SNVS_08,SNVS_TAMPER8,,,,,GPIO13_IO11,,,,,,,,
+GPIO_SNVS_09,SNVS_TAMPER9,,,,,GPIO13_IO12,,,,,,,,
+GPIO_LPSR_00,FLEXCAN3_TX,MIC_CLK,MQS_RIGHT,ARM_CM4_EVENTO,,GPIO6_IO00,LPUART12_TXD,SAI4_MCLK,,,GPIO12_IO00,,,
+GPIO_LPSR_01,FLEXCAN3_RX,MIC_BITSTREAM0,MQS_LEFT,ARM_CM4_EVENTI,,GPIO6_IO01,LPUART12_RXD,,,,GPIO12_IO01,,,
+GPIO_LPSR_02,SRC_BOOT_MODE00,LPSPI5_SCK,SAI4_TX_DATA,MQS_RIGHT,,GPIO6_IO02,,,,,GPIO12_IO02,,,
+GPIO_LPSR_03,SRC_BOOT_MODE01,LPSPI5_PCS0,SAI4_TX_SYNC,MQS_LEFT,,GPIO6_IO03,,,,,GPIO12_IO03,,,
+GPIO_LPSR_04,LPI2C5_SDA,LPSPI5_SOUT,SAI4_TX_BCLK,LPUART12_RTS_B,,GPIO6_IO04,LPUART11_TXD,,,,GPIO12_IO04,,,
+GPIO_LPSR_05,LPI2C5_SCL,LPSPI5_SIN,SAI4_MCLK,LPUART12_CTS_B,,GPIO6_IO05,LPUART11_RXD,NMI_GLUE_NMI,,,GPIO12_IO05,,,
+GPIO_LPSR_06,LPI2C6_SDA,,SAI4_RX_DATA,LPUART12_TXD,LPSPI6_PCS3,GPIO6_IO06,FLEXCAN3_TX,PIT2_TRIGGER3,LPSPI5_PCS1,,GPIO12_IO06,,,
+GPIO_LPSR_07,LPI2C6_SCL,,SAI4_RX_BCLK,LPUART12_RXD,LPSPI6_PCS2,GPIO6_IO07,FLEXCAN3_RX,PIT2_TRIGGER2,LPSPI5_PCS2,,GPIO12_IO07,,,
+GPIO_LPSR_08,LPUART11_TXD,FLEXCAN3_TX,SAI4_RX_SYNC,MIC_CLK,LPSPI6_PCS1,GPIO6_IO08,LPI2C5_SDA,PIT2_TRIGGER1,LPSPI5_PCS3,,GPIO12_IO08,,,
+GPIO_LPSR_09,LPUART11_RXD,FLEXCAN3_RX,PIT2_TRIGGER0,MIC_BITSTREAM0,LPSPI6_PCS0,GPIO6_IO09,LPI2C5_SCL,SAI4_TX_DATA,,,GPIO12_IO09,,,
+GPIO_LPSR_10,JTAG_MUX_TRSTB,LPUART11_CTS_B,LPI2C6_SDA,MIC_BITSTREAM1,LPSPI6_SCK,GPIO6_IO10,LPI2C5_SCLS,SAI4_TX_SYNC,LPUART12_TXD,,GPIO12_IO10,,,
+GPIO_LPSR_11,JTAG_MUX_TDO,LPUART11_RTS_B,LPI2C6_SCL,MIC_BITSTREAM2,LPSPI6_SOUT,GPIO6_IO11,LPI2C5_SDAS,ARM_TRACE_SWO,LPUART12_RXD,,GPIO12_IO11,,,
+GPIO_LPSR_12,JTAG_MUX_TDI,PIT2_TRIGGER0,,MIC_BITSTREAM3,LPSPI6_SIN,GPIO6_IO12,LPI2C5_HREQ,SAI4_TX_BCLK,LPSPI5_SCK,,GPIO12_IO12,,,
+GPIO_LPSR_13,JTAG_MUX_MOD,MIC_BITSTREAM1,PIT2_TRIGGER1,,,GPIO6_IO13,,SAI4_RX_DATA,LPSPI5_PCS0,,GPIO12_IO13,,,
+GPIO_LPSR_14,JTAG_MUX_TCK,MIC_BITSTREAM2,PIT2_TRIGGER2,,,GPIO6_IO14,,SAI4_RX_BCLK,LPSPI5_SOUT,,GPIO12_IO14,,,
+GPIO_LPSR_15,JTAG_MUX_TMS,MIC_BITSTREAM3,PIT2_TRIGGER3,,,GPIO6_IO15,,SAI4_RX_SYNC,LPSPI5_SIN,,GPIO12_IO15,,,
+WAKEUP_DIG,,,,,,GPIO13_IO00,,NMI_GLUE_NMI,,,,,,
+GPIO_DISP_B1_00,VIDEO_MUX_LCDIF_CLK,ENET_1G_RX_EN,,TMR1_TIMER0,XBAR1_INOUT26,GPIO4_IO21,,,ENET_QOS_RX_EN,,GPIO10_IO21,,,
+GPIO_DISP_B1_01,VIDEO_MUX_LCDIF_ENABLE,ENET_1G_RX_CLK,ENET_1G_RX_ER,TMR1_TIMER1,XBAR1_INOUT27,GPIO4_IO22,,,ENET_QOS_RX_CLK,ENET_QOS_RX_ER,GPIO10_IO22,,,
+GPIO_DISP_B1_02,VIDEO_MUX_LCDIF_HSYNC,ENET_1G_RX_DATA00,LPI2C3_SCL,TMR1_TIMER2,XBAR1_INOUT28,GPIO4_IO23,,,ENET_QOS_RX_DATA00,LPUART1_TXD,GPIO10_IO23,,,
+GPIO_DISP_B1_03,VIDEO_MUX_LCDIF_VSYNC,ENET_1G_RX_DATA01,LPI2C3_SDA,TMR2_TIMER0,XBAR1_INOUT29,GPIO4_IO24,,,ENET_QOS_RX_DATA01,LPUART1_RXD,GPIO10_IO24,,,
+GPIO_DISP_B1_04,VIDEO_MUX_LCDIF_DATA00,ENET_1G_RX_DATA02,LPUART4_RXD,TMR2_TIMER1,XBAR1_INOUT30,GPIO4_IO25,,,ENET_QOS_RX_DATA02,LPSPI3_SCK,GPIO10_IO25,,,
+GPIO_DISP_B1_05,VIDEO_MUX_LCDIF_DATA01,ENET_1G_RX_DATA03,LPUART4_CTS_B,TMR2_TIMER2,XBAR1_INOUT31,GPIO4_IO26,,,ENET_QOS_RX_DATA03,LPSPI3_SIN,GPIO10_IO26,,,
+GPIO_DISP_B1_06,VIDEO_MUX_LCDIF_DATA02,ENET_1G_TX_DATA03,LPUART4_TXD,TMR3_TIMER0,XBAR1_INOUT32,GPIO4_IO27,SRC_BT_CFG00,,ENET_QOS_TX_DATA03,LPSPI3_SOUT,GPIO10_IO27,,,
+GPIO_DISP_B1_07,VIDEO_MUX_LCDIF_DATA03,ENET_1G_TX_DATA02,LPUART4_RTS_B,TMR3_TIMER1,XBAR1_INOUT33,GPIO4_IO28,SRC_BT_CFG01,,ENET_QOS_TX_DATA02,LPSPI3_PCS0,GPIO10_IO28,,,
+GPIO_DISP_B1_08,VIDEO_MUX_LCDIF_DATA04,ENET_1G_TX_DATA01,USDHC1_CD_B,TMR3_TIMER2,XBAR1_INOUT34,GPIO4_IO29,SRC_BT_CFG02,,ENET_QOS_TX_DATA01,LPSPI3_PCS1,GPIO10_IO29,,,
+GPIO_DISP_B1_09,VIDEO_MUX_LCDIF_DATA05,ENET_1G_TX_DATA00,USDHC1_WP,TMR4_TIMER0,XBAR1_INOUT35,GPIO4_IO30,SRC_BT_CFG03,,ENET_QOS_TX_DATA00,LPSPI3_PCS2,GPIO10_IO30,,,
+GPIO_DISP_B1_10,VIDEO_MUX_LCDIF_DATA06,ENET_1G_TX_EN,USDHC1_RESET_B,TMR4_TIMER1,XBAR1_INOUT36,GPIO4_IO31,SRC_BT_CFG04,,ENET_QOS_TX_EN,LPSPI3_PCS3,GPIO10_IO31,,,
+GPIO_DISP_B1_11,VIDEO_MUX_LCDIF_DATA07,ENET_1G_TX_CLK_IO,ENET_1G_REF_CLK,TMR4_TIMER2,XBAR1_INOUT37,GPIO5_IO00,SRC_BT_CFG05,,ENET_QOS_TX_CLK,ENET_QOS_REF_CLK,GPIO11_IO00,,,
+GPIO_DISP_B2_00,VIDEO_MUX_LCDIF_DATA08,WDOG1_B,MQS_RIGHT,ENET_1G_TX_ER,SAI1_TX_DATA03,GPIO5_IO01,SRC_BT_CFG06,,ENET_QOS_TX_ER,,GPIO11_IO01,,,
+GPIO_DISP_B2_01,VIDEO_MUX_LCDIF_DATA09,USDHC1_VSELECT,MQS_LEFT,WDOG2_B,SAI1_TX_DATA02,GPIO5_IO02,SRC_BT_CFG07,,EWM_OUT_B,CCM_ENET_REF_CLK_25M,GPIO11_IO02,,,
+GPIO_DISP_B2_02,VIDEO_MUX_LCDIF_DATA10,ENET_TX_DATA00,PIT1_TRIGGER3,ARM_TRACE00,SAI1_TX_DATA01,GPIO5_IO03,SRC_BT_CFG08,,ENET_QOS_TX_DATA00,,GPIO11_IO03,,,
+GPIO_DISP_B2_03,VIDEO_MUX_LCDIF_DATA11,ENET_TX_DATA01,PIT1_TRIGGER2,ARM_TRACE01,SAI1_MCLK,GPIO5_IO04,SRC_BT_CFG09,,ENET_QOS_TX_DATA01,,GPIO11_IO04,,,
+GPIO_DISP_B2_04,VIDEO_MUX_LCDIF_DATA12,ENET_TX_EN,PIT1_TRIGGER1,ARM_TRACE02,SAI1_RX_SYNC,GPIO5_IO05,SRC_BT_CFG10,,ENET_QOS_TX_EN,,GPIO11_IO05,,,
+GPIO_DISP_B2_05,VIDEO_MUX_LCDIF_DATA13,ENET_TX_CLK,ENET_REF_CLK,ARM_TRACE03,SAI1_RX_BCLK,GPIO5_IO06,SRC_BT_CFG11,,ENET_QOS_TX_CLK,,GPIO11_IO06,,,
+GPIO_DISP_B2_06,VIDEO_MUX_LCDIF_DATA14,ENET_RX_DATA00,LPUART7_TXD,ARM_TRACE_CLK,SAI1_RX_DATA00,GPIO5_IO07,,,ENET_QOS_RX_DATA00,,GPIO11_IO07,,,
+GPIO_DISP_B2_07,VIDEO_MUX_LCDIF_DATA15,ENET_RX_DATA01,LPUART7_RXD,ARM_TRACE_SWO,SAI1_TX_DATA00,GPIO5_IO08,,,ENET_QOS_RX_DATA01,,GPIO11_IO08,,,
+GPIO_DISP_B2_08,VIDEO_MUX_LCDIF_DATA16,ENET_RX_EN,LPUART8_TXD,ARM_CM7_EVENTO,SAI1_TX_BCLK,GPIO5_IO09,,,ENET_QOS_RX_EN,LPUART1_TXD,GPIO11_IO09,,,
+GPIO_DISP_B2_09,VIDEO_MUX_LCDIF_DATA17,ENET_RX_ER,LPUART8_RXD,ARM_CM7_EVENTI,SAI1_TX_SYNC,GPIO5_IO10,,,ENET_QOS_RX_ER,LPUART1_RXD,GPIO11_IO10,,,
+GPIO_DISP_B2_10,VIDEO_MUX_LCDIF_DATA18,EMVSIM2_IO,LPUART2_TXD,WDOG2_RESET_B_DEB,XBAR1_INOUT38,GPIO5_IO11,LPI2C3_SCL,,ENET_QOS_RX_ER,SPDIF_IN,GPIO11_IO11,,,
+GPIO_DISP_B2_11,VIDEO_MUX_LCDIF_DATA19,EMVSIM2_CLK,LPUART2_RXD,WDOG1_RESET_B_DEB,XBAR1_INOUT39,GPIO5_IO12,LPI2C3_SDA,,ENET_QOS_CRS,SPDIF_OUT,GPIO11_IO12,,,
+GPIO_DISP_B2_12,VIDEO_MUX_LCDIF_DATA20,EMVSIM2_RST,FLEXCAN1_TX,LPUART2_CTS_B,XBAR1_INOUT40,GPIO5_IO13,LPI2C4_SCL,,ENET_QOS_COL,LPSPI4_SCK,GPIO11_IO13,,,
+GPIO_DISP_B2_13,VIDEO_MUX_LCDIF_DATA21,EMVSIM2_SVEN,FLEXCAN1_RX,LPUART2_RTS_B,ENET_REF_CLK,GPIO5_IO14,LPI2C4_SDA,,ENET_QOS_1588_EVENT0_OUT,LPSPI4_SIN,GPIO11_IO14,,,
+GPIO_DISP_B2_14,VIDEO_MUX_LCDIF_DATA22,EMVSIM2_PD,WDOG2_B,VIDEO_MUX_EXT_DCIC1,ENET_1G_REF_CLK,GPIO5_IO15,FLEXCAN1_TX,,ENET_QOS_1588_EVENT0_IN,LPSPI4_SOUT,GPIO11_IO15,,,
+GPIO_DISP_B2_15,VIDEO_MUX_LCDIF_DATA23,EMVSIM2_POWER_FAIL,WDOG1_B,VIDEO_MUX_EXT_DCIC2,PIT1_TRIGGER0,GPIO5_IO16,FLEXCAN1_RX,,ENET_QOS_1588_EVENT0_AUX_IN,LPSPI4_PCS0,GPIO11_IO16,,,
+GPIO_AD_00,EMVSIM1_IO,FLEXCAN2_TX,ENET_1G_1588_EVENT1_IN,GPT2_CAPTURE1,FLEXPWM1_PWM0_A,GPIO2_IO31,LPUART7_TXD,,FLEXIO2_D00,FLEXSPI2_B_SS1_B,GPIO8_IO31,,ACMP1_IN1,
+GPIO_AD_01,EMVSIM1_CLK,FLEXCAN2_RX,ENET_1G_1588_EVENT1_OUT,GPT2_CAPTURE2,FLEXPWM1_PWM0_B,GPIO3_IO00,LPUART7_RXD,,FLEXIO2_D01,FLEXSPI2_A_SS1_B,GPIO9_IO00,,ACMP1_IN2,
+GPIO_AD_02,EMVSIM1_RST,LPUART7_CTS_B,ENET_1G_1588_EVENT2_IN,GPT2_COMPARE1,FLEXPWM1_PWM1_A,GPIO3_IO01,LPUART8_TXD,,FLEXIO2_D02,VIDEO_MUX_EXT_DCIC1,GPIO9_IO01,,ACMP1_IN3,
+GPIO_AD_03,EMVSIM1_SVEN,LPUART7_RTS_B,ENET_1G_1588_EVENT2_OUT,GPT2_COMPARE2,FLEXPWM1_PWM1_B,GPIO3_IO02,LPUART8_RXD,,FLEXIO2_D03,VIDEO_MUX_EXT_DCIC2,GPIO9_IO02,,ACMP1_IN4,
+GPIO_AD_04,EMVSIM1_PD,LPUART8_CTS_B,ENET_1G_1588_EVENT3_IN,GPT2_COMPARE3,FLEXPWM1_PWM2_A,GPIO3_IO03,WDOG1_B,,FLEXIO2_D04,TMR4_TIMER0,GPIO9_IO03,,ACMP2_IN1,
+GPIO_AD_05,EMVSIM1_POWER_FAIL,LPUART8_RTS_B,ENET_1G_1588_EVENT3_OUT,GPT2_CLK,FLEXPWM1_PWM2_B,GPIO3_IO04,WDOG2_B,,FLEXIO2_D05,TMR4_TIMER1,GPIO9_IO04,,ACMP2_IN2,
+GPIO_AD_06,USB_OTG2_OC,FLEXCAN1_TX,EMVSIM2_IO,GPT3_CAPTURE1,VIDEO_MUX_CSI_DATA15,GPIO3_IO05,ENET_1588_EVENT1_IN,,FLEXIO2_D06,TMR4_TIMER2,GPIO9_IO05,ADC1_CH0A,,
+GPIO_AD_07,USB_OTG2_PWR,FLEXCAN1_RX,EMVSIM2_CLK,GPT3_CAPTURE2,VIDEO_MUX_CSI_DATA14,GPIO3_IO06,ENET_1588_EVENT1_OUT,,FLEXIO2_D07,TMR4_TIMER3,GPIO9_IO06,ADC1_CH0B,,
+GPIO_AD_08,USBPHY2_OTG_ID,LPI2C1_SCL,EMVSIM2_RST,GPT3_COMPARE1,VIDEO_MUX_CSI_DATA13,GPIO3_IO07,ENET_1588_EVENT2_IN,,FLEXIO2_D08,,GPIO9_IO07,ADC1_CH1A,,
+GPIO_AD_09,USBPHY1_OTG_ID,LPI2C1_SDA,EMVSIM2_SVEN,GPT3_COMPARE2,VIDEO_MUX_CSI_DATA12,GPIO3_IO08,ENET_1588_EVENT2_OUT,,FLEXIO2_D09,,GPIO9_IO08,ADC1_CH1B,,
+GPIO_AD_10,USB_OTG1_PWR,LPI2C1_SCLS,EMVSIM2_PD,GPT3_COMPARE3,VIDEO_MUX_CSI_DATA11,GPIO3_IO09,ENET_1588_EVENT3_IN,,FLEXIO2_D10,,GPIO9_IO09,ADC1_CH2A,,
+GPIO_AD_11,USB_OTG1_OC,LPI2C1_SDAS,EMVSIM2_POWER_FAIL,GPT3_CLK,VIDEO_MUX_CSI_DATA10,GPIO3_IO10,ENET_1588_EVENT3_OUT,,FLEXIO2_D11,,GPIO9_IO10,ADC1_CH2B,,
+GPIO_AD_12,SPDIF_LOCK,LPI2C1_HREQ,GPT1_CAPTURE1,FLEXSPI1_B_DATA03,VIDEO_MUX_CSI_PIXCLK,GPIO3_IO11,ENET_TX_DATA03,,FLEXIO2_D12,EWM_OUT_B,GPIO9_IO11,"ADC1_CH3A,ADC2_CH3A",,
+GPIO_AD_13,SPDIF_SR_CLK,PIT1_TRIGGER0,GPT1_CAPTURE2,FLEXSPI1_B_DATA02,VIDEO_MUX_CSI_MCLK,GPIO3_IO12,ENET_TX_DATA02,,FLEXIO2_D13,REF_CLK_32K,GPIO9_IO12,"ADC1_CH3B,ADC2_CH3B",,
+GPIO_AD_14,SPDIF_EXT_CLK,REF_CLK_24M,GPT1_COMPARE1,FLEXSPI1_B_DATA01,VIDEO_MUX_CSI_VSYNC,GPIO3_IO13,ENET_RX_CLK,,FLEXIO2_D14,CCM_ENET_REF_CLK_25M,GPIO9_IO13,"ADC1_CH4A,ADC2_CH4A",,
+GPIO_AD_15,SPDIF_IN,LPUART10_TXD,GPT1_COMPARE2,FLEXSPI1_B_DATA00,VIDEO_MUX_CSI_HSYNC,GPIO3_IO14,ENET_TX_ER,,FLEXIO2_D15,,GPIO9_IO14,"ADC1_CH4B,ADC2_CH4B",,
+GPIO_AD_16,SPDIF_OUT,LPUART10_RXD,GPT1_COMPARE3,FLEXSPI1_B_SCLK,VIDEO_MUX_CSI_DATA09,GPIO3_IO15,ENET_RX_DATA03,,FLEXIO2_D16,ENET_1G_MDC,GPIO9_IO15,"ADC1_CH5A,ADC2_CH5A",,
+GPIO_AD_17,SAI1_MCLK,ACMP1_OUT,GPT1_CLK,FLEXSPI1_A_DQS,VIDEO_MUX_CSI_DATA08,GPIO3_IO16,ENET_RX_DATA02,,FLEXIO2_D17,ENET_1G_MDIO,GPIO9_IO16,"ADC1_CH5B,ADC2_CH5B",ACMP1_OUT,
+GPIO_AD_18,SAI1_RX_SYNC,ACMP2_OUT,LPSPI1_PCS1,FLEXSPI1_A_SS0_B,VIDEO_MUX_CSI_DATA07,GPIO3_IO17,ENET_CRS,,FLEXIO2_D18,LPI2C2_SCL,GPIO9_IO17,ADC2_CH0A,ACMP2_OUT,
+GPIO_AD_19,SAI1_RX_BCLK,ACMP3_OUT,LPSPI1_PCS2,FLEXSPI1_A_SCLK,VIDEO_MUX_CSI_DATA06,GPIO3_IO18,ENET_COL,,FLEXIO2_D19,LPI2C2_SDA,GPIO9_IO18,ADC2_CH0B,ACMP3_OUT,
+GPIO_AD_20,SAI1_RX_DATA00,ACMP4_OUT,LPSPI1_PCS3,FLEXSPI1_A_DATA00,VIDEO_MUX_CSI_DATA05,GPIO3_IO19,KPP_ROW07,,FLEXIO2_D20,ENET_QOS_1588_EVENT2_OUT,GPIO9_IO19,ADC2_CH1A,ACMP4_OUT,
+GPIO_AD_21,SAI1_TX_DATA00,,LPSPI2_PCS1,FLEXSPI1_A_DATA01,VIDEO_MUX_CSI_DATA04,GPIO3_IO20,KPP_COL07,,FLEXIO2_D21,ENET_QOS_1588_EVENT2_IN,GPIO9_IO20,ADC2_CH1B,,
+GPIO_AD_22,SAI1_TX_BCLK,,LPSPI2_PCS2,FLEXSPI1_A_DATA02,VIDEO_MUX_CSI_DATA03,GPIO3_IO21,KPP_ROW06,,FLEXIO2_D22,ENET_QOS_1588_EVENT3_OUT,GPIO9_IO21,ADC2_CH2A,,
+GPIO_AD_23,SAI1_TX_SYNC,,LPSPI2_PCS3,FLEXSPI1_A_DATA03,VIDEO_MUX_CSI_DATA02,GPIO3_IO22,KPP_COL06,,FLEXIO2_D23,ENET_QOS_1588_EVENT3_IN,GPIO9_IO22,ADC2_CH2B,,
+GPIO_AD_24,LPUART1_TXD,LPSPI2_SCK,VIDEO_MUX_CSI_DATA00,ENET_RX_EN,FLEXPWM2_PWM0_A,GPIO3_IO23,KPP_ROW05,,FLEXIO2_D24,LPI2C4_SCL,GPIO9_IO23,ADC2_CH6A,,
+GPIO_AD_25,LPUART1_RXD,LPSPI2_PCS0,VIDEO_MUX_CSI_DATA01,ENET_RX_ER,FLEXPWM2_PWM0_B,GPIO3_IO24,KPP_COL05,,FLEXIO2_D25,LPI2C4_SDA,GPIO9_IO24,ADC2_CH6B,,
+GPIO_AD_26,LPUART1_CTS_B,LPSPI2_SOUT,SEMC_CSX01,ENET_RX_DATA00,FLEXPWM2_PWM1_A,GPIO3_IO25,KPP_ROW04,,FLEXIO2_D26,ENET_QOS_MDC,GPIO9_IO25,,ACMP2_IN3,
+GPIO_AD_27,LPUART1_RTS_B,LPSPI2_SIN,SEMC_CSX02,ENET_RX_DATA01,FLEXPWM2_PWM1_B,GPIO3_IO26,KPP_COL04,,FLEXIO2_D27,ENET_QOS_MDIO,GPIO9_IO26,,ACMP2_IN4,
+GPIO_AD_28,LPSPI1_SCK,LPUART5_TXD,SEMC_CSX03,ENET_TX_EN,FLEXPWM2_PWM2_A,GPIO3_IO27,KPP_ROW03,,FLEXIO2_D28,VIDEO_MUX_EXT_DCIC1,GPIO9_IO27,,ACMP3_IN1,
+GPIO_AD_29,LPSPI1_PCS0,LPUART5_RXD,ENET_REF_CLK,ENET_TX_CLK,FLEXPWM2_PWM2_B,GPIO3_IO28,KPP_COL03,,FLEXIO2_D29,VIDEO_MUX_EXT_DCIC2,GPIO9_IO28,,ACMP3_IN2,
+GPIO_AD_30,LPSPI1_SOUT,USB_OTG2_OC,FLEXCAN2_TX,ENET_TX_DATA00,LPUART3_TXD,GPIO3_IO29,KPP_ROW02,,FLEXIO2_D30,WDOG2_RESET_B_DEB,GPIO9_IO29,,ACMP3_IN3,
+GPIO_AD_31,LPSPI1_SIN,USB_OTG2_PWR,FLEXCAN2_RX,ENET_TX_DATA01,LPUART3_RXD,GPIO3_IO30,KPP_COL02,,FLEXIO2_D31,WDOG1_RESET_B_DEB,GPIO9_IO30,,ACMP3_IN4,
+GPIO_AD_32,LPI2C1_SCL,USBPHY2_OTG_ID,PGMC_PMIC_RDY,ENET_MDC,USDHC1_CD_B,GPIO3_IO31,KPP_ROW01,,LPUART10_TXD,ENET_1G_MDC,GPIO9_IO31,,ACMP4_IN1,
+GPIO_AD_33,LPI2C1_SDA,USBPHY1_OTG_ID,XBAR1_INOUT17,ENET_MDIO,USDHC1_WP,GPIO4_IO00,KPP_COL01,,LPUART10_RXD,ENET_1G_MDIO,GPIO10_IO00,,ACMP4_IN2,
+GPIO_AD_34,ENET_1G_1588_EVENT0_IN,USB_OTG1_PWR,XBAR1_INOUT18,ENET_1588_EVENT0_IN,USDHC1_VSELECT,GPIO4_IO01,KPP_ROW00,,LPUART10_CTS_B,WDOG1_ANY,GPIO10_IO01,,ACMP4_IN3,
+GPIO_AD_35,ENET_1G_1588_EVENT0_OUT,USB_OTG1_OC,XBAR1_INOUT19,ENET_1588_EVENT0_OUT,USDHC1_RESET_B,GPIO4_IO02,KPP_COL00,,LPUART10_RTS_B,FLEXSPI1_B_SS1_B,GPIO10_IO02,,ACMP4_IN4,
diff --git a/ports/mimxrt/boards/MIMXRT1176_clock_config.c b/ports/mimxrt/boards/MIMXRT1176_clock_config.c
new file mode 100644
index 000000000000..ae02e30fa83b
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1176_clock_config.c
@@ -0,0 +1,693 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * How to setup clock using clock driver functions:
+ *
+ * 1. Call CLOCK_InitXXXPLL() to configure corresponding PLL clock.
+ *
+ * 2. Call CLOCK_InitXXXpfd() to configure corresponding PLL pfd clock.
+ *
+ * 3. Call CLOCK_SetRootClock() to configure corresponding module clock source and divider.
+ *
+ */
+
+#include CLOCK_CONFIG_H
+#include "fsl_iomuxc.h"
+#include "fsl_dcdc.h"
+#include "fsl_pmu.h"
+#include "fsl_clock.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* System clock frequency. */
+extern uint32_t SystemCoreClock;
+
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+void BOARD_InitBootClocks(void) {
+ BOARD_BootClockRUN();
+}
+
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
+/* This function should not run from SDRAM since it will change SEMC configuration. */
+AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
+void UpdateSemcClock(void) {
+ /* Enable self-refresh mode and update semc clock root to 200MHz. */
+ SEMC->IPCMD = 0xA55A000D;
+ while ((SEMC->INTR & 0x3) == 0) {
+ ;
+ }
+ SEMC->INTR = 0x3;
+ SEMC->DCCR = 0x0B;
+ /*
+ * Currently we are using SEMC parameter which fit both 166MHz and 200MHz, only
+ * need to change the SEMC clock root here. If customer is using their own DCD and
+ * want to switch from 166MHz to 200MHz, extra SEMC configuration might need to be
+ * adjusted here to fine tune the SDRAM performance
+ */
+ CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
+}
+#endif
+#endif
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+
+#ifndef SKIP_POWER_ADJUSTMENT
+#if __CORTEX_M == 7
+#define BYPASS_LDO_LPSR 1
+#define SKIP_LDO_ADJUSTMENT 1
+#elif __CORTEX_M == 4
+#define SKIP_DCDC_ADJUSTMENT 1
+#define SKIP_FBB_ENABLE 1
+#endif
+#endif
+
+const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN = {
+ .postDivider = kCLOCK_PllPostDiv2, /* Post divider, 0 - DIV by 2, 1 - DIV by 4, 2 - DIV by 8, 3 - DIV by 1 */
+ .loopDivider = 166, /* PLL Loop divider, Fout = Fin * ( loopDivider / ( 2 * postDivider ) ) */
+};
+
+const clock_sys_pll1_config_t sysPll1Config_BOARD_BootClockRUN = {
+ .pllDiv2En = true,
+};
+
+const clock_sys_pll2_config_t sysPll2Config_BOARD_BootClockRUN = {
+ .mfd = 268435455, /* Denominator of spread spectrum */
+ .ss = NULL, /* Spread spectrum parameter */
+ .ssEnable = false, /* Enable spread spectrum or not */
+};
+
+const clock_video_pll_config_t videoPllConfig_BOARD_BootClockRUN = {
+ .loopDivider = 41, /* PLL Loop divider, valid range for DIV_SELECT divider value: 27 ~ 54. */
+ .postDivider = 0, /* Divider after PLL, should only be 1, 2, 4, 8, 16, 32 */
+ .numerator = 1, /* 30 bit numerator of fractional loop divider, Fout = Fin * ( loopDivider + numerator / denominator ) */
+ .denominator = 960000, /* 30 bit denominator of fractional loop divider, Fout = Fin * ( loopDivider + numerator / denominator ) */
+ .ss = NULL, /* Spread spectrum parameter */
+ .ssEnable = false, /* Enable spread spectrum or not */
+};
+
+/*******************************************************************************
+ * Code for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+void BOARD_BootClockRUN(void) {
+ clock_root_config_t rootCfg = {0};
+
+ #if !defined(SKIP_DCDC_ADJUSTMENT) || (!SKIP_DCDC_ADJUSTMENT)
+ if ((OCOTP->FUSEN[16].FUSE == 0x57AC5969U) && ((OCOTP->FUSEN[17].FUSE & 0xFFU) == 0x0BU)) {
+ DCDC_SetVDD1P0BuckModeTargetVoltage(DCDC, kDCDC_1P0BuckTarget1P15V);
+ } else {
+ /* Set 1.125V for production samples to align with data sheet requirement */
+ DCDC_SetVDD1P0BuckModeTargetVoltage(DCDC, kDCDC_1P0BuckTarget1P125V);
+ }
+ #endif
+
+ #if !defined(SKIP_FBB_ENABLE) || (!SKIP_FBB_ENABLE)
+ /* Check if FBB need to be enabled in OverDrive(OD) mode */
+ if (((OCOTP->FUSEN[7].FUSE & 0x10U) >> 4U) != 1) {
+ PMU_EnableBodyBias(ANADIG_PMU, kPMU_FBB_CM7, true);
+ } else {
+ PMU_EnableBodyBias(ANADIG_PMU, kPMU_FBB_CM7, false);
+ }
+ #endif
+
+ #if defined(BYPASS_LDO_LPSR) && BYPASS_LDO_LPSR
+ PMU_StaticEnableLpsrAnaLdoBypassMode(ANADIG_LDO_SNVS, true);
+ PMU_StaticEnableLpsrDigLdoBypassMode(ANADIG_LDO_SNVS, true);
+ #endif
+
+ #if !defined(SKIP_LDO_ADJUSTMENT) || (!SKIP_LDO_ADJUSTMENT)
+ pmu_static_lpsr_ana_ldo_config_t lpsrAnaConfig;
+ pmu_static_lpsr_dig_config_t lpsrDigConfig;
+
+ if ((ANADIG_LDO_SNVS->PMU_LDO_LPSR_ANA & ANADIG_LDO_SNVS_PMU_LDO_LPSR_ANA_BYPASS_MODE_EN_MASK) == 0UL) {
+ PMU_StaticGetLpsrAnaLdoDefaultConfig(&lpsrAnaConfig);
+ PMU_StaticLpsrAnaLdoInit(ANADIG_LDO_SNVS, &lpsrAnaConfig);
+ }
+
+ if ((ANADIG_LDO_SNVS->PMU_LDO_LPSR_DIG & ANADIG_LDO_SNVS_PMU_LDO_LPSR_DIG_BYPASS_MODE_MASK) == 0UL) {
+ PMU_StaticGetLpsrDigLdoDefaultConfig(&lpsrDigConfig);
+ lpsrDigConfig.targetVoltage = kPMU_LpsrDigTargetStableVoltage1P117V;
+ PMU_StaticLpsrDigLdoInit(ANADIG_LDO_SNVS, &lpsrDigConfig);
+ }
+ #endif
+
+ /* PLL LDO shall be enabled first before enable PLLs */
+
+ /* Config CLK_1M */
+ CLOCK_OSC_Set1MHzOutputBehavior(kCLOCK_1MHzOutEnableFreeRunning1Mhz);
+
+ /* Init OSC RC 16M */
+ ANADIG_OSC->OSC_16M_CTRL |= ANADIG_OSC_OSC_16M_CTRL_EN_IRC4M16M_MASK;
+
+ /* Init OSC RC 400M */
+ CLOCK_OSC_EnableOscRc400M();
+ CLOCK_OSC_GateOscRc400M(true);
+
+ /* Init OSC RC 48M */
+ CLOCK_OSC_EnableOsc48M(true);
+ CLOCK_OSC_EnableOsc48MDiv2(true);
+
+ /* Config OSC 24M */
+ ANADIG_OSC->OSC_24M_CTRL |= ANADIG_OSC_OSC_24M_CTRL_OSC_EN(1) | ANADIG_OSC_OSC_24M_CTRL_BYPASS_EN(0) | ANADIG_OSC_OSC_24M_CTRL_BYPASS_CLK(0) | ANADIG_OSC_OSC_24M_CTRL_LP_EN(1) | ANADIG_OSC_OSC_24M_CTRL_OSC_24M_GATE(0);
+ /* Wait for 24M OSC to be stable. */
+ while (ANADIG_OSC_OSC_24M_CTRL_OSC_24M_STABLE_MASK !=
+ (ANADIG_OSC->OSC_24M_CTRL & ANADIG_OSC_OSC_24M_CTRL_OSC_24M_STABLE_MASK)) {
+ }
+
+ /* Switch both core, M7 Systick and Bus_Lpsr to OscRC48MDiv2 first */
+ rootCfg.mux = kCLOCK_M7_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ #if __CORTEX_M == 7
+ CLOCK_SetRootClock(kCLOCK_Root_M7, &rootCfg);
+ CLOCK_SetRootClock(kCLOCK_Root_M7_Systick, &rootCfg);
+ #endif
+ #if __CORTEX_M == 4
+ CLOCK_SetRootClock(kCLOCK_Root_M4, &rootCfg);
+ CLOCK_SetRootClock(kCLOCK_Root_Bus_Lpsr, &rootCfg);
+ #endif
+
+ /*
+ * if DCD is used, please make sure the clock source of SEMC is not changed in the following PLL/PFD configuration code.
+ */
+ /* Init Arm Pll. */
+ CLOCK_InitArmPll(&armPllConfig_BOARD_BootClockRUN);
+
+ /* Bypass Sys Pll1. */
+ // CLOCK_SetPllBypass(kCLOCK_PllSys1, true);
+
+ /* Init Sys Pll1 and enable PllSys1_Div2 output */
+ CLOCK_InitSysPll1(&sysPll1Config_BOARD_BootClockRUN);
+
+
+ /* Init Sys Pll2. */
+ CLOCK_InitSysPll2(&sysPll2Config_BOARD_BootClockRUN);
+
+ /* Init System Pll2 pfd0. */
+ CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd0, 27);
+
+ /* Init System Pll2 pfd1. */
+ CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd1, 16);
+
+ /* Init System Pll2 pfd2. */
+ CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd2, 24);
+
+ /* Init System Pll2 pfd3. */
+ CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 32);
+
+ /* Init Sys Pll3. */
+ CLOCK_InitSysPll3();
+
+ /* Init System Pll3 pfd0. */
+ CLOCK_InitPfd(kCLOCK_PllSys3, kCLOCK_Pfd0, 13);
+
+ /* Init System Pll3 pfd1. */
+ CLOCK_InitPfd(kCLOCK_PllSys3, kCLOCK_Pfd1, 17);
+
+ /* Init System Pll3 pfd2. */
+ CLOCK_InitPfd(kCLOCK_PllSys3, kCLOCK_Pfd2, 32);
+
+ /* Init System Pll3 pfd3. */
+ CLOCK_InitPfd(kCLOCK_PllSys3, kCLOCK_Pfd3, 22);
+
+ /* Bypass Audio Pll. */
+ CLOCK_SetPllBypass(kCLOCK_PllAudio, true);
+
+ /* DeInit Audio Pll. */
+ CLOCK_DeinitAudioPll();
+
+ /* Init Video Pll. */
+ CLOCK_InitVideoPll(&videoPllConfig_BOARD_BootClockRUN);
+
+ /* Module clock root configurations. */
+ /* Configure M7 using ARM_PLL_CLK */
+ #if __CORTEX_M == 7
+ rootCfg.mux = kCLOCK_M7_ClockRoot_MuxArmPllOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_M7, &rootCfg);
+ #endif
+
+ /* Configure M4 using SYS_PLL3_PFD3_CLK */
+ #if __CORTEX_M == 4
+ rootCfg.mux = kCLOCK_M4_ClockRoot_MuxSysPll3Pfd3;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_M4, &rootCfg);
+ #endif
+
+ /* Configure BUS using SYS_PLL3_CLK */
+ rootCfg.mux = kCLOCK_BUS_ClockRoot_MuxSysPll3Out;
+ rootCfg.div = 3;
+ CLOCK_SetRootClock(kCLOCK_Root_Bus, &rootCfg);
+
+ /* Configure BUS_LPSR using SYS_PLL3_CLK */
+ /* BUS_LPSR must not be more than 120MHz */
+ rootCfg.mux = kCLOCK_BUS_LPSR_ClockRoot_MuxSysPll3Out;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Bus_Lpsr, &rootCfg);
+
+ /* Configure SEMC using SYS_PLL2_PFD1_CLK */
+ #ifndef SKIP_SEMC_INIT
+ rootCfg.mux = kCLOCK_SEMC_ClockRoot_MuxSysPll2Pfd1;
+ rootCfg.div = 3;
+ CLOCK_SetRootClock(kCLOCK_Root_Semc, &rootCfg);
+ #endif
+
+ #if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+ #if defined(XIP_BOOT_HEADER_DCD_ENABLE) && (XIP_BOOT_HEADER_DCD_ENABLE == 1)
+ UpdateSemcClock();
+ #endif
+ #endif
+
+ /* Configure CSSYS using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CSSYS_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Cssys, &rootCfg);
+
+ /* Configure CSTRACE using SYS_PLL2_CLK */
+ rootCfg.mux = kCLOCK_CSTRACE_ClockRoot_MuxSysPll2Out;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Cstrace, &rootCfg);
+
+ // Strange settings for SYSTICK: 24MHz for M4, 100kHz for M7 ?
+ /* Configure M4_SYSTICK using OSC_RC_48M_DIV2 */
+ #if __CORTEX_M == 4
+ rootCfg.mux = kCLOCK_M4_SYSTICK_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_M4_Systick, &rootCfg);
+ #endif
+
+ /* Configure M7_SYSTICK using OSC_RC_48M_DIV2 */
+ #if __CORTEX_M == 7
+ rootCfg.mux = kCLOCK_M7_SYSTICK_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 240;
+ CLOCK_SetRootClock(kCLOCK_Root_M7_Systick, &rootCfg);
+ #endif
+
+ /* Configure ADC1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ADC1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Adc1, &rootCfg);
+
+ /* Configure ADC2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ADC2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Adc2, &rootCfg);
+
+ /* Configure ACMP using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ACMP_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Acmp, &rootCfg);
+
+ /* Configure FLEXIO1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_FLEXIO1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Flexio1, &rootCfg);
+
+ /* Configure FLEXIO2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_FLEXIO2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Flexio2, &rootCfg);
+
+ /* Configure GPT1 using OSC_24M*/
+ rootCfg.mux = kCLOCK_GPT1_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt1, &rootCfg);
+
+ /* Configure GPT2 using OSC_24M */
+ rootCfg.mux = kCLOCK_GPT2_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt2, &rootCfg);
+
+ /* Configure GPT3 using OSC_24M */
+ rootCfg.mux = kCLOCK_GPT3_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt3, &rootCfg);
+
+ /* Configure GPT4 using OSC_24M */
+ rootCfg.mux = kCLOCK_GPT4_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt4, &rootCfg);
+
+ /* Configure GPT5 using OSC_24M */
+ rootCfg.mux = kCLOCK_GPT5_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt5, &rootCfg);
+
+ /* Configure GPT6 using OSC_24M */
+ rootCfg.mux = kCLOCK_GPT6_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Gpt6, &rootCfg);
+
+ /* Configure FLEXSPI1 using OSC_RC_48M_DIV2 */
+ #if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
+ rootCfg.mux = kCLOCK_FLEXSPI1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Flexspi1, &rootCfg);
+ #endif
+
+ /* Configure FLEXSPI2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_FLEXSPI2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Flexspi2, &rootCfg);
+
+ /* Configure CAN1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CAN1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Can1, &rootCfg);
+
+ /* Configure CAN2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CAN2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Can2, &rootCfg);
+
+ /* Configure CAN3 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CAN3_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Can3, &rootCfg);
+
+ /* Configure LPUART1 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART1_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart1, &rootCfg);
+
+ /* Configure LPUART2 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART2_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart2, &rootCfg);
+
+ /* Configure LPUART3 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART3_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart3, &rootCfg);
+
+ /* Configure LPUART4 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART4_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart4, &rootCfg);
+
+ /* Configure LPUART5 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART5_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart5, &rootCfg);
+
+ /* Configure LPUART6 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART6_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart6, &rootCfg);
+
+ /* Configure LPUART7 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART7_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart7, &rootCfg);
+
+ /* Configure LPUART8 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART8_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart8, &rootCfg);
+
+ /* Configure LPUART9 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART9_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart9, &rootCfg);
+
+ /* Configure LPUART10 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART10_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart10, &rootCfg);
+
+ /* Configure LPUART11 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART11_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart11, &rootCfg);
+
+ /* Configure LPUART12 using SYS_PLL3_PFD3_CLK */
+ rootCfg.mux = kCLOCK_LPUART12_ClockRoot_MuxSysPll2Pfd3;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpuart12, &rootCfg);
+
+
+ /* Configure LPI2C1 using SYS_PLL3_DIV2 (240MHz) */
+ rootCfg.mux = kCLOCK_LPI2C1_ClockRoot_MuxSysPll3Div2;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c1, &rootCfg);
+
+ /* Configure LPI2C2 using SYS_PLL3_DIV2 (240MHz) */
+ rootCfg.mux = kCLOCK_LPI2C2_ClockRoot_MuxSysPll3Div2;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c2, &rootCfg);
+
+ /* Configure LPI2C3 using SYS_PLL3_DIV2 (240MHz) */
+ rootCfg.mux = kCLOCK_LPI2C3_ClockRoot_MuxSysPll3Div2;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c3, &rootCfg);
+
+ /* Configure LPI2C4 using SYS_PLL3_DIV2 (240MHz) */
+ rootCfg.mux = kCLOCK_LPI2C4_ClockRoot_MuxSysPll3Div2;
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c4, &rootCfg);
+
+ /* Configure LPI2C5 using SYS_PLL3_OUT (480MHz) */
+ rootCfg.mux = kCLOCK_LPI2C5_ClockRoot_MuxSysPll3Out;
+ rootCfg.div = 8;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c5, &rootCfg);
+
+ /* Configure LPI2C6 using SYS_PLL3_OUT (480MHz) */
+ rootCfg.mux = kCLOCK_LPI2C6_ClockRoot_MuxSysPll3Out;
+ rootCfg.div = 8;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpi2c6, &rootCfg);
+
+
+ /* Configure LPSPI1 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI1_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi1, &rootCfg);
+
+ /* Configure LPSPI2 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI2_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi2, &rootCfg);
+
+ /* Configure LPSPI3 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI3_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi3, &rootCfg);
+
+ /* Configure LPSPI4 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI4_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi4, &rootCfg);
+
+ /* Configure LPSPI5 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI5_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi5, &rootCfg);
+
+ /* Configure LPSPI6 using SYS_PLL_3_PDF2 (270MHz) */
+ rootCfg.mux = kCLOCK_LPSPI6_ClockRoot_MuxSysPll3Pfd2;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Lpspi6, &rootCfg);
+
+
+ /* Configure EMV1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_EMV1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Emv1, &rootCfg);
+
+ /* Configure EMV2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_EMV2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Emv2, &rootCfg);
+
+ /* Configure ENET1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg);
+
+ /* Configure ENET2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg);
+
+ /* Configure ENET_QOS using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET_QOS_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet_Qos, &rootCfg);
+
+ /* Configure ENET_25M using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET_25M_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet_25m, &rootCfg);
+
+ /* Configure ENET_TIMER1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET_TIMER1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet_Timer1, &rootCfg);
+
+ /* Configure ENET_TIMER2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET_TIMER2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet_Timer2, &rootCfg);
+
+ /* Configure ENET_TIMER3 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ENET_TIMER3_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet_Timer3, &rootCfg);
+
+ /* Configure USDHC1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_USDHC1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Usdhc1, &rootCfg);
+
+ /* Configure USDHC2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_USDHC2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Usdhc2, &rootCfg);
+
+ /* Configure ASRC using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_ASRC_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Asrc, &rootCfg);
+
+ /* Configure MQS using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_MQS_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Mqs, &rootCfg);
+
+ /* Configure MIC using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_MIC_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Mic, &rootCfg);
+
+ /* Configure SPDIF using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_SPDIF_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Spdif, &rootCfg);
+
+ /* Configure SAI1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_SAI1_ClockRoot_MuxOsc24MOut;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Sai1, &rootCfg);
+
+ /* Configure SAI2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_SAI2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Sai2, &rootCfg);
+
+ /* Configure SAI3 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_SAI3_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Sai3, &rootCfg);
+
+ /* Configure SAI4 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_SAI4_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Sai4, &rootCfg);
+
+ /* Configure GC355 using PLL_VIDEO_CLK */
+ rootCfg.mux = kCLOCK_GC355_ClockRoot_MuxVideoPllOut;
+ rootCfg.div = 2;
+ CLOCK_SetRootClock(kCLOCK_Root_Gc355, &rootCfg);
+
+ /* Configure LCDIF using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_LCDIF_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Lcdif, &rootCfg);
+
+ /* Configure LCDIFV2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_LCDIFV2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Lcdifv2, &rootCfg);
+
+ /* Configure MIPI_REF using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_MIPI_REF_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Mipi_Ref, &rootCfg);
+
+ /* Configure MIPI_ESC using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_MIPI_ESC_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Mipi_Esc, &rootCfg);
+
+ /* Configure CSI2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CSI2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Csi2, &rootCfg);
+
+ /* Configure CSI2_ESC using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CSI2_ESC_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Csi2_Esc, &rootCfg);
+
+ /* Configure CSI2_UI using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CSI2_UI_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Csi2_Ui, &rootCfg);
+
+ /* Configure CSI using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CSI_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Csi, &rootCfg);
+
+ /* Configure CKO1 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CKO1_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Cko1, &rootCfg);
+
+ /* Configure CKO2 using OSC_RC_48M_DIV2 */
+ rootCfg.mux = kCLOCK_CKO2_ClockRoot_MuxOscRc48MDiv2;
+ rootCfg.div = 1;
+ CLOCK_SetRootClock(kCLOCK_Root_Cko2, &rootCfg);
+
+ /* Set SAI1 MCLK1 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk1Sel, 0);
+ /* Set SAI1 MCLK2 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk2Sel, 3);
+ /* Set SAI1 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk3Sel, 0);
+ /* Set SAI2 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI2MClk3Sel, 0);
+ /* Set SAI3 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI3MClk3Sel, 0);
+
+ /* Set MQS configuration. */
+ IOMUXC_MQSConfig(IOMUXC_GPR, kIOMUXC_MqsPwmOverSampleRate32, 0);
+ /* Set ENET Tx clock source. */
+ IOMUXC_GPR->GPR4 &= ~IOMUXC_GPR_GPR4_ENET_TX_CLK_SEL_MASK;
+ /* Set ENET_1G Tx clock source. */
+ IOMUXC_GPR->GPR5 = ((IOMUXC_GPR->GPR5 & ~IOMUXC_GPR_GPR5_ENET1G_TX_CLK_SEL_MASK) | IOMUXC_GPR_GPR5_ENET1G_RGMII_EN_MASK);
+ /* Set GPT1 High frequency reference clock source. */
+ IOMUXC_GPR->GPR22 &= ~IOMUXC_GPR_GPR22_REF_1M_CLK_GPT1_MASK;
+ /* Set GPT2 High frequency reference clock source. */
+ IOMUXC_GPR->GPR23 &= ~IOMUXC_GPR_GPR23_REF_1M_CLK_GPT2_MASK;
+ /* Set GPT3 High frequency reference clock source. */
+ IOMUXC_GPR->GPR24 &= ~IOMUXC_GPR_GPR24_REF_1M_CLK_GPT3_MASK;
+ /* Set GPT4 High frequency reference clock source. */
+ IOMUXC_GPR->GPR25 &= ~IOMUXC_GPR_GPR25_REF_1M_CLK_GPT4_MASK;
+ /* Set GPT5 High frequency reference clock source. */
+ IOMUXC_GPR->GPR26 &= ~IOMUXC_GPR_GPR26_REF_1M_CLK_GPT5_MASK;
+ /* Set GPT6 High frequency reference clock source. */
+ IOMUXC_GPR->GPR27 &= ~IOMUXC_GPR_GPR27_REF_1M_CLK_GPT6_MASK;
+
+ #if __CORTEX_M == 7
+ SystemCoreClock = CLOCK_GetRootClockFreq(kCLOCK_Root_M7);
+ #else
+ SystemCoreClock = CLOCK_GetRootClockFreq(kCLOCK_Root_M4);
+ #endif
+}
diff --git a/ports/mimxrt/boards/MIMXRT1176_clock_config.h b/ports/mimxrt/boards/MIMXRT1176_clock_config.h
new file mode 100644
index 000000000000..df2748a65811
--- /dev/null
+++ b/ports/mimxrt/boards/MIMXRT1176_clock_config.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _CLOCK_CONFIG_H_
+#define _CLOCK_CONFIG_H_
+
+#include "fsl_common.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */
+
+#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */
+
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes default configuration of clocks.
+ *
+ */
+void BOARD_InitBootClocks(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/*******************************************************************************
+ * Definitions for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if __CORTEX_M == 7
+ #define BOARD_BOOTCLOCKRUN_CORE_CLOCK 996000000UL /*!< CM7 Core clock frequency: 996000000Hz */
+#else
+ #define BOARD_BOOTCLOCKRUN_CORE_CLOCK 392727272UL /*!< CM4 Core clock frequency: 392727272Hz */
+#endif
+
+/* Clock outputs (values are in Hz): */
+#define BOARD_BOOTCLOCKRUN_ACMP_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ADC1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ADC2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ARM_PLL_CLK 996000000UL
+#define BOARD_BOOTCLOCKRUN_ASRC_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_AXI_CLK_ROOT 996000000UL
+#define BOARD_BOOTCLOCKRUN_BUS_CLK_ROOT 160000000UL // 160MHz
+#define BOARD_BOOTCLOCKRUN_BUS_LPSR_CLK_ROOT 120000000UL // 120MHz
+#define BOARD_BOOTCLOCKRUN_CAN1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CAN2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CAN3_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CCM_CLKO1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CCM_CLKO2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CLK_1M 1000000UL
+#define BOARD_BOOTCLOCKRUN_CSI2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI2_ESC_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI2_UI_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSI_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSSYS_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_CSTRACE_CLK_ROOT 132000000UL
+#define BOARD_BOOTCLOCKRUN_ELCDIF_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_EMV1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_EMV2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_1G_TX_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_25M_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_QOS_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_TIMER1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_TIMER2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_TIMER3_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_ENET_TX_CLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXIO2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_FLEXSPI2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GC355_CLK_ROOT 492000012UL
+#define BOARD_BOOTCLOCKRUN_GPT1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT1_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT2_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT3_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT3_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT4_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT4_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT5_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT5_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT6_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_GPT6_IPG_CLK_HIGHFREQ 24000000UL
+#define BOARD_BOOTCLOCKRUN_LCDIFV2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_LPI2C1_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPI2C2_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPI2C3_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPI2C4_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPI2C5_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPI2C6_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI1_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI2_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI3_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI4_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI5_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI6_CLK_ROOT 13500000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_LPUART10_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART11_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART12_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART1_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART2_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART3_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART4_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART5_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART6_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART7_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART8_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_LPUART9_CLK_ROOT 74250000UL
+#define BOARD_BOOTCLOCKRUN_M4_CLK_ROOT 392727272UL
+#define BOARD_BOOTCLOCKRUN_M4_SYSTICK_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_M7_CLK_ROOT 996000000UL
+#define BOARD_BOOTCLOCKRUN_M7_SYSTICK_CLK_ROOT 100000UL
+#define BOARD_BOOTCLOCKRUN_MIC_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_MIPI_DSI_TX_CLK_ESC_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_MIPI_ESC_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_MIPI_REF_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_MQS_MCLK 24000000UL
+#define BOARD_BOOTCLOCKRUN_OSC_24M 24000000UL
+#define BOARD_BOOTCLOCKRUN_OSC_32K 32768UL
+#define BOARD_BOOTCLOCKRUN_OSC_RC_16M 16000000UL
+#define BOARD_BOOTCLOCKRUN_OSC_RC_400M 400000000UL
+#define BOARD_BOOTCLOCKRUN_OSC_RC_48M 48000000UL
+#define BOARD_BOOTCLOCKRUN_OSC_RC_48M_DIV2 24000000UL
+#define BOARD_BOOTCLOCKRUN_PLL_AUDIO_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_PLL_AUDIO_SS_MODULATION 0UL
+#define BOARD_BOOTCLOCKRUN_PLL_AUDIO_SS_RANGE 0UL
+#define BOARD_BOOTCLOCKRUN_PLL_VIDEO_CLK 984000025UL
+#define BOARD_BOOTCLOCKRUN_PLL_VIDEO_SS_MODULATION 0UL
+#define BOARD_BOOTCLOCKRUN_PLL_VIDEO_SS_RANGE 0UL
+#define BOARD_BOOTCLOCKRUN_SAI1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK1 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI1_MCLK3 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK1 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI2_MCLK3 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK1 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SAI3_MCLK3 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI4_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI4_MCLK1 24000000UL
+#define BOARD_BOOTCLOCKRUN_SAI4_MCLK2 0UL
+#define BOARD_BOOTCLOCKRUN_SEMC_CLK_ROOT 198000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_SPDIF_EXTCLK_OUT 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL1_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL1_DIV2_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL1_DIV5_CLK 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL1_SS_MODULATION 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL1_SS_RANGE 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_CLK 528000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_PFD0_CLK 352000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_PFD1_CLK 594000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_PFD2_CLK 396000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_PFD3_CLK 297000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_SS_MODULATION 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL2_SS_RANGE 0UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_CLK 480000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_DIV2_CLK 240000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_PFD0_CLK 664615384UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_PFD1_CLK 508235294UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_PFD2_CLK 270000000UL
+#define BOARD_BOOTCLOCKRUN_SYS_PLL3_PFD3_CLK 392727272UL
+#define BOARD_BOOTCLOCKRUN_USDHC1_CLK_ROOT 24000000UL
+#define BOARD_BOOTCLOCKRUN_USDHC2_CLK_ROOT 24000000UL
+
+
+// Configuration for all instances of peripherals are identical
+#define BOARD_BOOTCLOCKRUN_LPI2C_CLK_ROOT 60000000UL // 60MHz
+#define BOARD_BOOTCLOCKRUN_LPSPI_CLK_ROOT 135000000UL // 135MHz
+#define BOARD_BOOTCLOCKRUN_PERCLK_CLK_ROOT 160000000UL // 160MHz
+#define BOARD_BOOTCLOCKRUN_UART_CLK_ROOT 74250000UL // 74.25MHz
+/*******************************************************************************
+ * API for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /* __cplusplus*/
+
+/*!
+ * @brief This function executes configuration of clocks.
+ *
+ */
+void BOARD_BootClockRUN(void);
+
+#if defined(__cplusplus)
+}
+#endif /* __cplusplus*/
+
+#endif /* _CLOCK_CONFIG_H_ */
diff --git a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h
index 8c6d159fb7ae..3d080ff25f1f 100644
--- a/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h
+++ b/ports/mimxrt/boards/OLIMEX_RT1010/mpconfigboard.h
@@ -1,9 +1,9 @@
#define MICROPY_HW_BOARD_NAME "RT1010-Py-DevKIT"
#define MICROPY_HW_MCU_NAME "MIMXRT1011DAE5A"
-#define MICROPY_HW_USB_STR_MANUF "Olimex Ltd."
+#define MICROPY_HW_USB_MANUFACTURER_STRING "Olimex Ltd."
#define MICROPY_HW_USB_VID 0x15ba
#define MICROPY_HW_USB_PID 0x0046
-#define MICROPY_PY_UOS_DUPTERM_BUILTIN_STREAM (0)
+#define MICROPY_PY_OS_DUPTERM_BUILTIN_STREAM (0)
// Olimex RT1010-Py has 1 board LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_11)
@@ -57,6 +57,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir, 0, kIOMUXC_GPR_SAI3MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, 0, kDmaRequestMuxSai3Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, 0, kDmaRequestMuxSai3Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/manifest.py b/ports/mimxrt/boards/SEEED_ARCH_MIX/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
index d366b4535d70..c98cdcb0a749 100644
--- a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Seeed ARCH MIX"
#define MICROPY_HW_MCU_NAME "MIMXRT1052DVL5B"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-arch-mix"
+
// MIMXRT1050_EVKB has 1 user LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_AD_B0_09)
#define MICROPY_HW_LED2_PIN (pin_GPIO_AD_B0_10)
@@ -73,6 +75,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -116,6 +119,8 @@
// Etherner PIN definitions
// No reset and interrupt pin by intention
+#define ENET_RESET_PIN NULL
+#define ENET_INT_PIN NULL
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
index 2312d11311e5..ca27dff55f3a 100644
--- a/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
+++ b/ports/mimxrt/boards/SEEED_ARCH_MIX/mpconfigboard.mk
@@ -10,5 +10,9 @@ MICROPY_HW_SDRAM_AVAIL = 1
MICROPY_HW_SDRAM_SIZE = 0x2000000 # 32MB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
+CFLAGS += -DSPI_RETRY_TIMES=1000000
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
index 877573d03865..07da87db10fc 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
@@ -66,6 +66,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir, kIOMUXC_GPR_SAI2MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
diff --git a/ports/mimxrt/boards/TEENSY41/manifest.py b/ports/mimxrt/boards/TEENSY41/manifest.py
new file mode 100644
index 000000000000..107181c31ca7
--- /dev/null
+++ b/ports/mimxrt/boards/TEENSY41/manifest.py
@@ -0,0 +1,3 @@
+include("../manifest.py")
+
+require("bundle-networking")
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 3c6a05185da4..56740f48ea3d 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "Teensy 4.1"
#define MICROPY_HW_MCU_NAME "MIMXRT1062DVJ6A"
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-teensy41"
+
// Teensy 4.1 has 1 board LED
#define MICROPY_HW_LED1_PIN (pin_GPIO_B0_03)
#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin))
@@ -66,6 +68,7 @@
#define I2S_IOMUXC_GPR_MODE { 0, kIOMUXC_GPR_SAI1MClkOutputDir, kIOMUXC_GPR_SAI2MClkOutputDir }
#define I2S_DMA_REQ_SRC_RX { 0, kDmaRequestMuxSai1Rx, kDmaRequestMuxSai2Rx }
#define I2S_DMA_REQ_SRC_TX { 0, kDmaRequestMuxSai1Tx, kDmaRequestMuxSai2Tx }
+#define I2S_AUDIO_PLL_CLOCK (2U)
#define I2S_GPIO(_hwid, _fn, _mode, _pin, _iomux) \
{ \
@@ -113,8 +116,8 @@
#define ENET_PHY_OPS phydp83825_ops
// Ethernet PIN definitions
-#define ENET_RESET_PIN pin_GPIO_B0_14
-#define ENET_INT_PIN pin_GPIO_B0_15
+#define ENET_RESET_PIN &pin_GPIO_B0_14
+#define ENET_INT_PIN &pin_GPIO_B0_15
#define IOMUX_TABLE_ENET \
{ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, 0, 0xB0E9u }, \
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
index 601a2cfe8606..cf07144668e1 100755
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.mk
@@ -8,8 +8,10 @@ MICROPY_HW_FLASH_SIZE = 0x800000 # 8MB
MICROPY_HW_FLASH_RESERVED ?= 0x1000 # 4KB
MICROPY_PY_LWIP = 1
-MICROPY_PY_USSL = 1
+MICROPY_PY_SSL = 1
MICROPY_SSL_MBEDTLS = 1
+FROZEN_MANIFEST ?= $(BOARD_DIR)/manifest.py
+
deploy: $(BUILD)/firmware.hex
teensy_loader_cli --mcu=imxrt1062 -v -w $<
diff --git a/ports/mimxrt/boards/common.ld b/ports/mimxrt/boards/common.ld
index 3aaa14c83bf2..c2aa369f66b3 100644
--- a/ports/mimxrt/boards/common.ld
+++ b/ports/mimxrt/boards/common.ld
@@ -96,7 +96,7 @@ SECTIONS
.text :
{
. = ALIGN(4);
- *(EXCLUDE_FILE(*fsl_flexspi.o *gc*.o *vm.o *parse.o *runtime*.o *mpirq.o *map.o) .text*) /* .text* sections (code) */
+ *(EXCLUDE_FILE(*fsl_flexspi.o *gc.o *vm.o *parse*.o *runtime*.o *map.o *mpirq.o ) .text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
diff --git a/ports/mimxrt/boards/deploy_teensy.md b/ports/mimxrt/boards/deploy_teensy.md
index 28da092493dd..8f533a91fda7 100644
--- a/ports/mimxrt/boards/deploy_teensy.md
+++ b/ports/mimxrt/boards/deploy_teensy.md
@@ -11,7 +11,7 @@ or for Teensy 4.1:
teensy_loader_cli --mcu=imxrt1062 -v -w TEENSY41-.hex
```
-Instead of imxrt1062 with the --mcu option, you can as well use the board specic names
+Instead of imxrt1062 with the --mcu option, you can as well use the board specific names
TEENSY40, TEENSY41 or TEENSY_MICROMOD. When loading the firmware the PJRC boot loader
will erase the board file system.
diff --git a/ports/mimxrt/boards/make-flexram-config.py b/ports/mimxrt/boards/make-flexram-config.py
index 5d9c1a8c7c02..4a80fb1d2476 100644
--- a/ports/mimxrt/boards/make-flexram-config.py
+++ b/ports/mimxrt/boards/make-flexram-config.py
@@ -53,6 +53,7 @@
"""
ocram_min_size = 0x00010000 # 64 KB
+
# Value parser
def mimxrt_default_parser(defines_file, features_file, ld_script):
with open(ld_script, "r") as input_file:
@@ -169,6 +170,43 @@ def mimxrt_106x_gen_code(extract_dict):
)
+def mimxrt_1176_gen_code(extract_dict):
+ flexram_bank_cfg = "0b"
+ avail_flexram = extract_dict["fsl_ram_bank_size"] * extract_dict["fsl_bank_nbr"]
+ flexram_configurable_ocram = (
+ extract_dict["ocram_size"] % 524288
+ ) # 512kB OCRAM are not part of FlexRAM configurable memory
+
+ if (
+ flexram_configurable_ocram + extract_dict["dtcm_size"] + extract_dict["itcm_size"]
+ ) > avail_flexram:
+ raise ValueError("Configuration exceeds available FlexRAM!")
+
+ for size, pattern in (
+ (flexram_configurable_ocram, "01"),
+ (extract_dict["dtcm_size"], "10"),
+ (extract_dict["itcm_size"], "11"),
+ ):
+ for _ in range(0, size, extract_dict["fsl_ram_bank_size"]):
+ flexram_bank_cfg += pattern
+
+ # Generate GPR Register config
+ print(".equ __iomux_gpr14_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x38))
+ print(".equ __iomux_gpr16_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x40))
+ print(".equ __iomux_gpr17_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x44))
+ print(".equ __iomux_gpr18_adr, 0x{:08X}".format(extract_dict["gpr_base_addr"] + 0x48))
+ print(
+ ".equ __iomux_gpr17_value, 0x{:08X} /* {}k OCRAM (512k OCRAM, {}k from FlexRAM), {}k DTCM, {}k ITCM */".format(
+ int(flexram_bank_cfg, 2) & 0xFFFF,
+ extract_dict["ocram_size"] // 1024,
+ flexram_configurable_ocram // 1024,
+ extract_dict["dtcm_size"] // 1024,
+ extract_dict["itcm_size"] // 1024,
+ )
+ )
+ print(".equ __iomux_gpr18_value, 0x{:08X}".format((int(flexram_bank_cfg, 2) >> 16) & 0xFFFF))
+
+
def main(defines_file, features_file, ld_script, controller):
dispatcher = {
"MIMXRT1011": (mimxrt_default_parser, mimxrt_default_gen_code),
@@ -177,6 +215,7 @@ def main(defines_file, features_file, ld_script, controller):
"MIMXRT1052": (mimxrt_default_parser, mimxrt_default_gen_code),
"MIMXRT1062": (mimxrt_default_parser, mimxrt_106x_gen_code),
"MIMXRT1064": (mimxrt_default_parser, mimxrt_106x_gen_code),
+ "MIMXRT1176": (mimxrt_default_parser, mimxrt_1176_gen_code),
}
extractor, code_generator = dispatcher[controller]
diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index 441676adde62..429d64869670 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -21,6 +21,9 @@
r"IOMUXC_(?PGPIO_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
r"IOMUXC_(?PGPIO_AD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
r"IOMUXC_(?PGPIO_SD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
+ r"IOMUXC_(?PGPIO_EMC_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
+ r"IOMUXC_(?PGPIO_DISP_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
+ r"IOMUXC_(?PGPIO_LPSR_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)",
]
@@ -62,6 +65,7 @@ def is_board_pin(self):
def parse_adc(self, adc_str):
adc_regex = r"ADC(?P\d*)_IN(?P\d*)"
+ lpadc_regex = r"ADC(?P\d*)_CH(?P\d*)" # LPADC for MIMXRT11xx chips
matches = re.finditer(adc_regex, adc_str, re.MULTILINE)
for match in matches:
@@ -69,6 +73,16 @@ def parse_adc(self, adc_str):
AdcFunction(instance=match.group("instance"), channel=match.group("channel"))
)
+ matches = re.finditer(lpadc_regex, adc_str, re.MULTILINE)
+ for match in matches:
+ self.adc_fns.append(
+ AdcFunction(
+ peripheral="LPADC",
+ instance=match.group("instance"),
+ channel=match.group("channel"),
+ )
+ )
+
def parse_af(self, af_idx, af_strs_in):
pass
@@ -104,18 +118,16 @@ def print(self):
self.print_pin_af()
self.print_pin_adc()
- if self.adc_fns:
- print(
- "const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, pin_{0}_adc);\n".format(
- self.name, self.gpio, int(self.pin), len(self.adc_fns)
- )
- )
- else:
- print(
- "const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, NULL);\n".format(
- self.name, self.gpio, int(self.pin), len(self.adc_fns)
- )
+ print(
+ "const machine_pin_obj_t pin_{0} = {1}({0}, {2}, {3}, pin_{0}_af, {4}, {5});\n".format(
+ self.name,
+ "PIN_LPSR" if "LPSR" in self.name else "PIN",
+ self.gpio,
+ int(self.pin),
+ len(self.adc_fns),
+ "pin_{}_adc".format(self.name) if self.adc_fns else "NULL",
)
+ )
else:
raise ValueError("Pin '{}' has no alternative functions".format(self.name))
@@ -126,13 +138,14 @@ def print_header(self, hdr_file):
class AdcFunction(object):
"""Holds the information associated with a pins ADC function."""
- def __init__(self, instance, channel):
+ def __init__(self, instance, channel, peripheral="ADC"):
+ self.peripheral = peripheral
self.instance = instance
self.channel = channel
def print(self):
"""Prints the C representation of this AF."""
- print(f" PIN_ADC(ADC{self.instance}, {self.channel}),")
+ print(f" PIN_ADC({self.peripheral}{self.instance}, {self.channel}),")
class AlternateFunction(object):
@@ -190,11 +203,8 @@ def parse_board_file(self, filename):
if pin and row[0]: # Only add board pins that have a name
self.board_pins.append(NamedPin(row[0], pin.pad, pin.idx))
- def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col):
- af_end_col = af_start_col + MAX_AF
-
+ def parse_af_file(self, filename, iomux_filename):
iomux_pin_config = dict()
-
with open(iomux_filename, "r") as ipt:
input_str = ipt.read()
for regex in regexes:
@@ -213,16 +223,22 @@ def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col):
with open(filename, "r") as csvfile:
rows = csv.reader(csvfile)
header = next(rows)
+ # Extract indexes from header row
+ pad_col = header.index("Pad")
+ adc_col = header.index("ADC")
+ #
for idx, row in enumerate(rows):
pad = row[pad_col]
gpio, pin = row[6].split("_")
pin_number = pin.lstrip("IO")
-
pin = Pin(pad, gpio, pin_number, idx=idx)
+ if any(s in pad for s in ("SNVS", "WAKEUP")):
+ continue
+
# Parse alternate functions
af_idx = 0
- for af_idx, af in enumerate(row[af_start_col:af_end_col]):
+ for af_idx, af in enumerate(row[(pad_col + 1) : adc_col]):
if af and af_supported(af):
pin.add_af(
AlternateFunction(
@@ -235,7 +251,7 @@ def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col):
)
)
- pin.parse_adc(row[ADC_COL])
+ pin.parse_adc(row[adc_col])
self.cpu_pins.append(pin)
@@ -363,7 +379,7 @@ def main():
if args.af_filename:
print("// --af {:s}".format(args.af_filename))
- pins.parse_af_file(args.af_filename, args.iomux_filename, 0, 1)
+ pins.parse_af_file(args.af_filename, args.iomux_filename)
if args.board_filename:
print("// --board {:s}".format(args.board_filename))
diff --git a/ports/mimxrt/boards/manifest.py b/ports/mimxrt/boards/manifest.py
index e4e5a236a357..d7acab38373f 100644
--- a/ports/mimxrt/boards/manifest.py
+++ b/ports/mimxrt/boards/manifest.py
@@ -1,5 +1,5 @@
freeze("$(PORT_DIR)/modules")
-include("$(MPY_DIR)/extmod/uasyncio")
+include("$(MPY_DIR)/extmod/asyncio")
require("onewire")
require("ds18x20")
require("dht")
diff --git a/ports/mimxrt/boards/mimxrt_prefix.c b/ports/mimxrt/boards/mimxrt_prefix.c
index 938efc810456..09c0aa109ebf 100644
--- a/ports/mimxrt/boards/mimxrt_prefix.c
+++ b/ports/mimxrt/boards/mimxrt_prefix.c
@@ -35,3 +35,17 @@
.adc_list = (_adc_list), \
} \
+#define PIN_LPSR(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list) \
+ { \
+ .base = { &machine_pin_type }, \
+ .name = MP_QSTR_##_name, \
+ .gpio = (_gpio), \
+ .pin = (uint32_t)(_pin), \
+ .muxRegister = (uint32_t)&(IOMUXC_LPSR->SW_MUX_CTL_PAD[kIOMUXC_LPSR_SW_MUX_CTL_PAD_##_name]), \
+ .configRegister = (uint32_t)&(IOMUXC_LPSR->SW_PAD_CTL_PAD[kIOMUXC_LPSR_SW_PAD_CTL_PAD_##_name]), \
+ .af_list_len = (uint8_t)(sizeof((_af_list)) / sizeof(machine_pin_af_obj_t)), \
+ .adc_list_len = (_adc_list_len), \
+ .af_list = (_af_list), \
+ .adc_list = (_adc_list), \
+ } \
+
diff --git a/ports/mimxrt/eth.c b/ports/mimxrt/eth.c
index 50e1cbb0fe82..d0df7610cc27 100644
--- a/ports/mimxrt/eth.c
+++ b/ports/mimxrt/eth.c
@@ -31,7 +31,7 @@
#include "py/mperrno.h"
#include "ticks.h"
-#if defined(MICROPY_HW_ETH_MDC)
+#if defined(IOMUX_TABLE_ENET)
#include "pin.h"
#include "shared/netutils/netutils.h"
@@ -43,7 +43,9 @@
#include "hal/phy/mdio/enet/fsl_enet_mdio.h"
#include "hal/phy/device/phyksz8081/fsl_phyksz8081.h"
#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
+#include "hal/phy/device/phydp83848/fsl_phydp83848.h"
#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
+#include "hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h"
#include "eth.h"
#include "lwip/etharp.h"
@@ -53,50 +55,9 @@
#include "ticks.h"
-// Configuration values
-enet_config_t enet_config;
-phy_config_t phyConfig = {0};
-
-// Prepare the buffer configuration.
-
#define ENET_RXBD_NUM (5)
#define ENET_TXBD_NUM (5)
-AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT);
-AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT);
-SDK_ALIGN(uint8_t g_rxDataBuff[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
- ENET_BUFF_ALIGNMENT);
-SDK_ALIGN(uint8_t g_txDataBuff[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
- ENET_BUFF_ALIGNMENT);
-
-// ENET Handles & Buffers
-enet_handle_t g_handle;
-
-static mdio_handle_t mdioHandle = {.ops = &enet_ops};
-static phy_handle_t phyHandle = {.phyAddr = ENET_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &ENET_PHY_OPS};
-
-enet_buffer_config_t buffConfig[] = {{
- ENET_RXBD_NUM,
- ENET_TXBD_NUM,
- SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
- SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
- &g_rxBuffDescrip[0],
- &g_txBuffDescrip[0],
- &g_rxDataBuff[0][0],
- &g_txDataBuff[0][0],
- #if FSL_ENET_DRIVER_VERSION >= 0x020300
- 0,
- 0,
- NULL
- #endif
- }};
-
-static uint8_t hw_addr[6]; // The MAC address field
-eth_t eth_instance;
-
-#define PHY_INIT_TIMEOUT_MS (10000)
-#define PHY_AUTONEGO_TIMEOUT_US (5000000)
-
typedef struct _eth_t {
uint32_t trace_flags;
struct netif netif;
@@ -113,16 +74,108 @@ typedef struct _iomux_table_t {
uint32_t configValue;
} iomux_table_t;
+// ETH0 buffers and handles
+static AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT);
+static AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT);
+static SDK_ALIGN(uint8_t g_rxDataBuff[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+static SDK_ALIGN(uint8_t g_txDataBuff[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+
+// ENET Handles & Buffers
+static enet_handle_t g_handle;
+static mdio_handle_t mdioHandle = {.ops = &enet_ops};
+static phy_handle_t phyHandle;
+eth_t eth_instance0;
+
+static enet_buffer_config_t buffConfig[] = {{
+ ENET_RXBD_NUM,
+ ENET_TXBD_NUM,
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ &g_rxBuffDescrip[0],
+ &g_txBuffDescrip[0],
+ &g_rxDataBuff[0][0],
+ &g_txDataBuff[0][0],
+ #if FSL_ENET_DRIVER_VERSION >= 0x020300
+ true,
+ true,
+ NULL,
+ #endif
+ }};
+
static const iomux_table_t iomux_table_enet[] = {
IOMUX_TABLE_ENET
};
-#define IOTE (iomux_table_enet[i])
+static uint8_t hw_addr[6]; // The MAC address field
+
+#if defined(ENET_DUAL_PORT)
+
+// ETH1 buffers and handles
+static AT_NONCACHEABLE_SECTION_ALIGN(enet_rx_bd_struct_t g_rxBuffDescrip_1[ENET_RXBD_NUM], ENET_BUFF_ALIGNMENT);
+static AT_NONCACHEABLE_SECTION_ALIGN(enet_tx_bd_struct_t g_txBuffDescrip_1[ENET_TXBD_NUM], ENET_BUFF_ALIGNMENT);
+static SDK_ALIGN(uint8_t g_rxDataBuff_1[ENET_RXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+static SDK_ALIGN(uint8_t g_txDataBuff_1[ENET_TXBD_NUM][SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT)],
+ ENET_BUFF_ALIGNMENT);
+
+static enet_handle_t g_handle_1;
+static mdio_handle_t mdioHandle_1 = {.ops = &enet_ops};
+static phy_handle_t phyHandle_1;
+eth_t eth_instance1;
+
+static enet_buffer_config_t buffConfig_1[] = {{
+ ENET_RXBD_NUM,
+ ENET_TXBD_NUM,
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ SDK_SIZEALIGN(ENET_FRAME_MAX_FRAMELEN, ENET_BUFF_ALIGNMENT),
+ &g_rxBuffDescrip_1[0],
+ &g_txBuffDescrip_1[0],
+ &g_rxDataBuff_1[0][0],
+ &g_txDataBuff_1[0][0],
+ #if FSL_ENET_DRIVER_VERSION >= 0x020300
+ true,
+ true,
+ NULL,
+ #endif
+ }};
+
+static const iomux_table_t iomux_table_enet_1[] = {
+ IOMUX_TABLE_ENET_1
+};
+
+static uint8_t hw_addr_1[6]; // The MAC address field
+
+#endif
+
+#if defined(ENET_DUAL_PORT)
+#if defined MIMXRT117x_SERIES
+#define ENET_1 ENET_1G
+#else
+#define ENET_1 ENET2
+#endif
+#else
+#define ENET_1 ENET
+#endif
+
+#define PHY_AUTONEGO_TIMEOUT_US (5000000)
+#define PHY_SETTLE_TIME_US (1000)
+// Settle time must be 500000 for the 1G interface
+#define PHY_SETTLE_TIME_US_1 (500000)
+#define ENET_RESET_LOW_TIME_US (10000)
+#define ENET_RESET_WAIT_TIME_US (30000)
+
+#define IOTE (iomux_table[i])
+
+#ifndef ENET_TX_CLK_OUTPUT
+#define ENET_TX_CLK_OUTPUT true
+#endif
-#define TRACE_ASYNC_EV (0x0001)
-#define TRACE_ETH_TX (0x0002)
-#define TRACE_ETH_RX (0x0004)
-#define TRACE_ETH_FULL (0x0008)
+#define TRACE_ASYNC_EV (0x0001)
+#define TRACE_ETH_TX (0x0002)
+#define TRACE_ETH_RX (0x0004)
+#define TRACE_ETH_FULL (0x0008)
STATIC void eth_trace(eth_t *self, size_t len, const void *data, unsigned int flags) {
if (((flags & NETUTILS_TRACE_IS_TX) && (self->trace_flags & TRACE_ETH_TX))
@@ -186,106 +239,146 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle,
}
}
-// eth_init: Set up GPIO and the transceiver
-void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) {
-
- self->netif.num = mac_idx; // Set the interface number
+// Configure the ethernet clock
+STATIC uint32_t eth_clock_init(int eth_id, bool phy_clock) {
CLOCK_EnableClock(kCLOCK_Iomuxc);
- gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
- (void)gpio_config;
+ #if defined MIMXRT117x_SERIES
- #ifdef ENET_RESET_PIN
- // Configure the Reset Pin
- const machine_pin_obj_t *reset_pin = &ENET_RESET_PIN;
- const machine_pin_af_obj_t *af_obj = pin_find_af(reset_pin, PIN_AF_MODE_ALT5);
+ clock_root_config_t rootCfg = {0};
- IOMUXC_SetPinMux(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0U);
- IOMUXC_SetPinConfig(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister,
- pin_generate_config(PIN_PULL_DISABLED, PIN_MODE_OUT, PIN_DRIVE_5, reset_pin->configRegister));
- GPIO_PinInit(reset_pin->gpio, reset_pin->pin, &gpio_config);
- #endif
+ if (eth_id == MP_HAL_MAC_ETH0) {
+ // Generate 50M root clock.
+ rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; // 500 MHz
+ rootCfg.div = 10;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg);
+ // 50M ENET_REF_CLOCK output to PHY and ENET module.
+ // if required, handle phy_clock direction here
+ IOMUXC_GPR->GPR4 |= 0x3;
+ } else {
+ // Generate 125M root clock.
+ rootCfg.mux = kCLOCK_ENET1_ClockRoot_MuxSysPll1Div2; // 500 MHz
+ rootCfg.div = 4;
+ CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg);
+ IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_RGMII_EN_MASK; /* bit1:iomuxc_gpr_enet_clk_dir
+ bit0:GPR_ENET_TX_CLK_SEL(internal or OSC) */
+ }
+ return CLOCK_GetRootClockFreq(kCLOCK_Root_Bus);
- #ifdef ENET_INT_PIN
- // Configure the Int Pin
- const machine_pin_obj_t *int_pin = &ENET_INT_PIN;
- af_obj = pin_find_af(int_pin, PIN_AF_MODE_ALT5);
+ #else
+
+ const clock_enet_pll_config_t config = {
+ .enableClkOutput = phy_clock, .enableClkOutput25M = false, .loopDivider = 1
+ };
+ CLOCK_InitEnetPll(&config);
+
+ IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Drive ENET_REF_CLK from PAD
+ IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, phy_clock); // Enable output driver
+
+ return CLOCK_GetFreq(kCLOCK_IpgClk);
- IOMUXC_SetPinMux(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0U);
- IOMUXC_SetPinConfig(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister,
- pin_generate_config(PIN_PULL_UP_47K, PIN_MODE_IN, PIN_DRIVE_5, int_pin->configRegister));
- GPIO_PinInit(int_pin->gpio, int_pin->pin, &gpio_config);
#endif
+}
+
+// eth_gpio_init: Configure the GPIO pins
+STATIC void eth_gpio_init(const iomux_table_t iomux_table[], size_t iomux_table_size,
+ const machine_pin_obj_t *reset_pin, const machine_pin_obj_t *int_pin) {
+
+ gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 1, kGPIO_NoIntmode};
+ (void)gpio_config;
+ const machine_pin_af_obj_t *af_obj;
+
+ if (reset_pin != NULL) {
+ // Configure the Reset Pin
+ af_obj = pin_find_af(reset_pin, PIN_AF_MODE_ALT5);
+
+ IOMUXC_SetPinMux(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister, 0U);
+ IOMUXC_SetPinConfig(reset_pin->muxRegister, af_obj->af_mode, 0, 0, reset_pin->configRegister,
+ pin_generate_config(PIN_PULL_DISABLED, PIN_MODE_OUT, PIN_DRIVE_5, reset_pin->configRegister));
+ GPIO_PinInit(reset_pin->gpio, reset_pin->pin, &gpio_config);
+ }
+
+ if (int_pin != NULL) {
+ // Configure the Int Pin
+ af_obj = pin_find_af(int_pin, PIN_AF_MODE_ALT5);
+
+ IOMUXC_SetPinMux(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister, 0U);
+ IOMUXC_SetPinConfig(int_pin->muxRegister, af_obj->af_mode, 0, 0, int_pin->configRegister,
+ pin_generate_config(PIN_PULL_UP_47K, PIN_MODE_IN, PIN_DRIVE_5, int_pin->configRegister));
+ GPIO_PinInit(int_pin->gpio, int_pin->pin, &gpio_config);
+ }
// Configure the Transceiver Pins, Settings except for CLK:
// Slew Rate Field: Fast Slew Rate, Drive Strength, R0/5, Speed max(200MHz)
// Open Drain Disabled, Pull Enabled, Pull 100K Ohm Pull Up
// Hysteresis Disabled
-
- for (int i = 0; i < ARRAY_SIZE(iomux_table_enet); i++) {
+ for (int i = 0; i < iomux_table_size; i++) {
IOMUXC_SetPinMux(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.inputOnfield);
IOMUXC_SetPinConfig(IOTE.muxRegister, IOTE.muxMode, IOTE.inputRegister, IOTE.inputDaisy, IOTE.configRegister, IOTE.configValue);
}
- const clock_enet_pll_config_t config = {
- .enableClkOutput = phy_clock, .enableClkOutput25M = false, .loopDivider = 1
- };
- CLOCK_InitEnetPll(&config);
-
- IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); // Do not use the 25 MHz MII clock
- IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, phy_clock); // Set the clock pad direction
-
- // Reset transceiver
- // pull up the ENET_INT before RESET.
- #ifdef ENET_INT_PIN
- GPIO_WritePinOutput(int_pin->gpio, int_pin->pin, 1);
- #endif
-
- #ifdef ENET_RESET_PIN
- GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 0);
- mp_hal_delay_us(1000);
- GPIO_WritePinOutput(reset_pin->gpio, reset_pin->pin, 1);
- mp_hal_delay_us(1000);
- #endif
+ // Reset the transceiver
+ if (reset_pin != NULL) {
+ GPIO_PinWrite(reset_pin->gpio, reset_pin->pin, 0);
+ mp_hal_delay_us(ENET_RESET_LOW_TIME_US);
+ GPIO_PinWrite(reset_pin->gpio, reset_pin->pin, 1);
+ mp_hal_delay_us(ENET_RESET_WAIT_TIME_US);
+ }
+}
- mp_hal_get_mac(0, hw_addr);
+// eth_phy_init: Initilaize the PHY interface
+STATIC void eth_phy_init(phy_handle_t *phyHandle, phy_config_t *phy_config,
+ phy_speed_t *speed, phy_duplex_t *duplex, uint32_t phy_settle_time) {
- phyHandle.ops = phy_ops;
- phyConfig.phyAddr = phy_addr;
- phyConfig.autoNeg = true;
- mdioHandle.resource.base = ENET;
- mdioHandle.resource.csrClock_Hz = CLOCK_GetFreq(kCLOCK_IpgClk);
-
- // Init the PHY interface & negotiate the speed
bool link = false;
bool autonego = false;
- phy_speed_t speed = kENET_MiiSpeed100M;
- phy_duplex_t duplex = kENET_MiiFullDuplex;
+ phy_config->autoNeg = true;
-
- status_t status = PHY_Init(&phyHandle, &phyConfig);
+ status_t status = PHY_Init(phyHandle, phy_config);
if (status == kStatus_Success) {
- if (phyConfig.autoNeg) {
- uint64_t t = ticks_us64() + PHY_AUTONEGO_TIMEOUT_US;
- // Wait for auto-negotiation success and link up
- do {
- PHY_GetAutoNegotiationStatus(&phyHandle, &autonego);
- PHY_GetLinkStatus(&phyHandle, &link);
- if (autonego && link) {
- break;
- }
- } while (ticks_us64() < t);
- if (!autonego) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Auto-negotiation failed."));
+ uint64_t t = ticks_us64() + PHY_AUTONEGO_TIMEOUT_US;
+ // Wait for auto-negotiation success and link up
+ do {
+ PHY_GetAutoNegotiationStatus(phyHandle, &autonego);
+ PHY_GetLinkStatus(phyHandle, &link);
+ if (autonego && link) {
+ break;
}
- PHY_GetLinkSpeedDuplex(&phyHandle, &speed, &duplex);
- } else {
- PHY_SetLinkSpeedDuplex(&phyHandle, speed, duplex);
+ } while (ticks_us64() < t);
+ if (!autonego) {
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Auto-negotiation failed."));
}
+ PHY_GetLinkSpeedDuplex(phyHandle, speed, duplex);
} else {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed."));
}
+ mp_hal_delay_us(phy_settle_time);
+}
+
+// eth_init: Set up GPIO and the transceiver
+void eth_init_0(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) {
+ // Configuration values
+ enet_config_t enet_config;
+
+ phy_config_t phy_config = {0};
+
+ uint32_t source_clock = eth_clock_init(eth_id, phy_clock);
+
+ eth_gpio_init(iomux_table_enet, ARRAY_SIZE(iomux_table_enet), ENET_RESET_PIN, ENET_INT_PIN);
+
+ mp_hal_get_mac(0, hw_addr);
+
+ // Init the PHY interface & negotiate the speed
+ phyHandle.ops = phy_ops;
+ phy_config.phyAddr = phy_addr;
+ phyHandle.mdioHandle = &mdioHandle;
+ mdioHandle.resource.base = ENET;
+ mdioHandle.resource.csrClock_Hz = source_clock;
+
+ phy_speed_t speed = kENET_MiiSpeed100M;
+ phy_duplex_t duplex = kENET_MiiFullDuplex;
+ eth_phy_init(&phyHandle, &phy_config, &speed, &duplex, PHY_SETTLE_TIME_US);
ENET_Reset(ENET);
ENET_GetDefaultConfig(&enet_config);
@@ -297,14 +390,70 @@ void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy
// Set interrupt
enet_config.interrupt |= ENET_TX_INTERRUPT | ENET_RX_INTERRUPT;
- ENET_Init(ENET, &g_handle, &enet_config, &buffConfig[0], hw_addr, CLOCK_GetFreq(kCLOCK_IpgClk));
+ ENET_Init(ENET, &g_handle, &enet_config, &buffConfig[0], hw_addr, source_clock);
ENET_SetCallback(&g_handle, eth_irq_handler, (void *)self);
NVIC_SetPriority(ENET_IRQn, IRQ_PRI_PENDSV);
ENET_EnableInterrupts(ENET, ENET_RX_INTERRUPT);
ENET_ClearInterruptStatus(ENET, ENET_TX_INTERRUPT | ENET_RX_INTERRUPT | ENET_ERR_INTERRUPT);
+ NVIC_SetPriority(ENET_IRQn, IRQ_PRI_PENDSV);
+ ENET_EnableInterrupts(ENET, ENET_RX_INTERRUPT);
ENET_ActiveRead(ENET);
}
+#if defined(ENET_DUAL_PORT)
+
+// eth_init: Set up GPIO and the transceiver
+void eth_init_1(eth_t *self, int eth_id, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock) {
+ // Configuration values
+ enet_config_t enet_config;
+
+ phy_config_t phy_config = {0};
+
+ uint32_t source_clock = eth_clock_init(eth_id, phy_clock);
+
+ eth_gpio_init(iomux_table_enet_1, ARRAY_SIZE(iomux_table_enet_1), ENET_1_RESET_PIN, ENET_1_INT_PIN);
+
+ #if defined MIMXRT117x_SERIES
+ NVIC_SetPriority(ENET_1G_MAC0_Tx_Rx_1_IRQn, IRQ_PRI_PENDSV);
+ NVIC_SetPriority(ENET_1G_MAC0_Tx_Rx_2_IRQn, IRQ_PRI_PENDSV);
+ NVIC_SetPriority(ENET_1G_IRQn, IRQ_PRI_PENDSV);
+ EnableIRQ(ENET_1G_MAC0_Tx_Rx_1_IRQn);
+ EnableIRQ(ENET_1G_MAC0_Tx_Rx_2_IRQn);
+ phy_speed_t speed = kENET_MiiSpeed1000M;
+ #else
+ NVIC_SetPriority(ENET2_IRQn, IRQ_PRI_PENDSV);
+ phy_speed_t speed = kENET_MiiSpeed100M;
+ #endif
+
+ mp_hal_get_mac(1, hw_addr_1);
+
+ // Init the PHY interface & negotiate the speed
+ phyHandle_1.ops = phy_ops;
+ phy_config.phyAddr = phy_addr;
+ phyHandle_1.mdioHandle = &mdioHandle_1;
+ mdioHandle_1.resource.base = ENET_1;
+ mdioHandle_1.resource.csrClock_Hz = source_clock;
+
+ phy_duplex_t duplex = kENET_MiiFullDuplex;
+ eth_phy_init(&phyHandle_1, &phy_config, &speed, &duplex, PHY_SETTLE_TIME_US_1);
+
+ ENET_Reset(ENET_1);
+ ENET_GetDefaultConfig(&enet_config);
+ enet_config.miiSpeed = (enet_mii_speed_t)speed;
+ enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
+ // Enable checksum generation by the ENET controller
+ enet_config.txAccelerConfig = kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled;
+ // Set interrupt
+ enet_config.interrupt = ENET_TX_INTERRUPT | ENET_RX_INTERRUPT;
+
+ ENET_Init(ENET_1, &g_handle_1, &enet_config, &buffConfig_1[0], hw_addr_1, source_clock);
+ ENET_SetCallback(&g_handle_1, eth_irq_handler, (void *)self);
+ ENET_ClearInterruptStatus(ENET_1, ENET_TX_INTERRUPT | ENET_RX_INTERRUPT | ENET_ERR_INTERRUPT);
+ ENET_EnableInterrupts(ENET_1, ENET_RX_INTERRUPT);
+ ENET_ActiveRead(ENET_1);
+}
+
+#endif
// Initialize the phy interface
STATIC int eth_mac_init(eth_t *self) {
return 0;
@@ -312,6 +461,8 @@ STATIC int eth_mac_init(eth_t *self) {
// Deinit the interface
STATIC void eth_mac_deinit(eth_t *self) {
+ // Just as a reminder: Calling ENET_Deinit() twice causes the board to stall
+ // with a bus error. Reason unclear. So don't do that for now (or ever).
}
void eth_set_trace(eth_t *self, uint32_t value) {
@@ -332,7 +483,7 @@ STATIC err_t eth_send_frame_blocking(ENET_Type *base, enet_handle_t *handle, uin
if (status != kStatus_ENET_TxFrameBusy) {
break;
}
- ticks_delay_us64(100);
+ ticks_delay_us64(base == ENET ? 100 : 20);
}
return status;
}
@@ -340,12 +491,20 @@ STATIC err_t eth_send_frame_blocking(ENET_Type *base, enet_handle_t *handle, uin
STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
// This function should always be called from a context where PendSV-level IRQs are disabled
status_t status;
+ ENET_Type *enet = ENET;
+ enet_handle_t *handle = &g_handle;
+
+ #if defined ENET_DUAL_PORT
+ if (netif->state == ð_instance1) {
+ enet = ENET_1;
+ handle = &g_handle_1;
+ }
+ #endif
- LINK_STATS_INC(link.xmit);
eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);
if (p->next == NULL) {
- status = eth_send_frame_blocking(ENET, &g_handle, p->payload, p->len);
+ status = eth_send_frame_blocking(enet, handle, p->payload, p->len);
} else {
// frame consists of several parts. Copy them together and send them
size_t length = 0;
@@ -356,7 +515,7 @@ STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
length += p->len;
p = p->next;
}
- status = eth_send_frame_blocking(ENET, &g_handle, tx_frame, length);
+ status = eth_send_frame_blocking(enet, handle, tx_frame, length);
}
return status == kStatus_Success ? ERR_OK : ERR_BUF;
}
@@ -378,22 +537,29 @@ STATIC err_t eth_netif_init(struct netif *netif) {
}
STATIC void eth_lwip_init(eth_t *self) {
+ struct netif *n = &self->netif;
ip_addr_t ipconfig[4];
- IP4_ADDR(&ipconfig[0], 192, 168, 0, 2);
+
+ self->netif.hwaddr_len = 6;
+ if (self == ð_instance0) {
+ memcpy(self->netif.hwaddr, hw_addr, 6);
+ IP4_ADDR(&ipconfig[0], 192, 168, 0, 2);
+ #if defined ENET_DUAL_PORT
+ } else {
+ memcpy(self->netif.hwaddr, hw_addr_1, 6);
+ IP4_ADDR(&ipconfig[0], 192, 168, 0, 3);
+ #endif
+ }
IP4_ADDR(&ipconfig[1], 255, 255, 255, 0);
IP4_ADDR(&ipconfig[2], 192, 168, 0, 1);
IP4_ADDR(&ipconfig[3], 8, 8, 8, 8);
- self->netif.hwaddr_len = 6;
- memcpy(self->netif.hwaddr, hw_addr, 6);
-
MICROPY_PY_LWIP_ENTER
- struct netif *n = &self->netif;
n->name[0] = 'e';
- n->name[1] = '0';
+ n->name[1] = (self == ð_instance0 ? '0' : '1');
netif_add(n, &ipconfig[0], &ipconfig[1], &ipconfig[2], self, eth_netif_init, ethernet_input);
- netif_set_hostname(n, "MPY");
+ netif_set_hostname(n, mod_network_hostname);
netif_set_default(n);
netif_set_up(n);
@@ -433,7 +599,11 @@ int eth_link_status(eth_t *self) {
}
} else {
bool link;
+ #if defined ENET_DUAL_PORT
+ PHY_GetLinkStatus(self == ð_instance0 ? &phyHandle : &phyHandle_1, &link);
+ #else
PHY_GetLinkStatus(&phyHandle, &link);
+ #endif
if (link) {
return 1; // link up
} else {
@@ -463,6 +633,10 @@ int eth_stop(eth_t *self) {
}
void eth_low_power_mode(eth_t *self, bool enable) {
+ #if defined ENET_DUAL_PORT
+ ENET_EnableSleepMode(self == ð_instance0 ? ENET : ENET_1, enable);
+ #else
ENET_EnableSleepMode(ENET, enable);
+ #endif
}
-#endif // defined(MICROPY_HW_ETH_MDC)
+#endif // defined(IOMUX_TABLE_ENET)
diff --git a/ports/mimxrt/eth.h b/ports/mimxrt/eth.h
index b225d0049248..afb5d5edf375 100644
--- a/ports/mimxrt/eth.h
+++ b/ports/mimxrt/eth.h
@@ -28,9 +28,14 @@
#define MICROPY_INCLUDED_MIMXRT_ETH_H
typedef struct _eth_t eth_t;
-extern eth_t eth_instance;
+extern eth_t eth_instance0;
+extern eth_t eth_instance1;
+void eth_init_0(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock);
+
+#if defined(ENET_DUAL_PORT)
+void eth_init_1(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock);
+#endif
-void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy_addr, bool phy_clock);
void eth_set_trace(eth_t *self, uint32_t value);
struct netif *eth_netif(eth_t *self);
int eth_link_status(eth_t *self);
@@ -43,6 +48,7 @@ enum {
PHY_DP83825,
PHY_DP83848,
PHY_LAN8720,
+ PHY_RTL8211F,
};
enum {
diff --git a/ports/mimxrt/flash.c b/ports/mimxrt/flash.c
new file mode 100644
index 000000000000..3a18f8f51b93
--- /dev/null
+++ b/ports/mimxrt/flash.c
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Philipp Ebensberger
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "flash.h"
+
+void flash_init(void) {
+ // Upload the custom flash configuration
+ // This should be performed by the boot ROM but for some reason it is not.
+ FLEXSPI_UpdateLUT(BOARD_FLEX_SPI, 0,
+ qspiflash_config.memConfig.lookupTable,
+ ARRAY_SIZE(qspiflash_config.memConfig.lookupTable));
+
+ // Configure FLEXSPI IP FIFO access.
+ BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK);
+ BOARD_FLEX_SPI->MCR0 &= ~(FLEXSPI_MCR0_ATDFEN_MASK);
+ BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ARDFEN(0);
+ BOARD_FLEX_SPI->MCR0 |= FLEXSPI_MCR0_ATDFEN(0);
+}
+
+// flash_erase_block(erase_addr)
+// erases the block starting at addr. Block size according to the flash properties.
+__attribute__((section(".ram_functions"))) status_t flash_erase_block(uint32_t erase_addr) {
+ status_t status = kStatus_Fail;
+
+ SCB_CleanInvalidateDCache();
+ SCB_DisableDCache();
+ __disable_irq();
+
+ status = flexspi_nor_flash_erase_block(BOARD_FLEX_SPI, erase_addr);
+
+ __enable_irq();
+ SCB_EnableDCache();
+
+ return status;
+}
+
+// flash_erase_sector(erase_addr_bytes)
+// erases the sector starting at addr. Sector size according to the flash properties.
+__attribute__((section(".ram_functions"))) status_t flash_erase_sector(uint32_t erase_addr) {
+ status_t status = kStatus_Fail;
+
+ SCB_CleanInvalidateDCache();
+ SCB_DisableDCache();
+ __disable_irq();
+
+ status = flexspi_nor_flash_erase_sector(BOARD_FLEX_SPI, erase_addr);
+
+ __enable_irq();
+ SCB_EnableDCache();
+
+ return status;
+}
+
+// flash_write_block(flash_dest_addr_bytes, data_source, length_bytes)
+// writes length_byte data to the destination address
+// the vfs driver takes care for erasing the sector if required
+__attribute__((section(".ram_functions"))) status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) {
+ status_t status = kStatus_Fail;
+ uint32_t write_length;
+ uint32_t next_addr;
+
+ if (length == 0) {
+ status = kStatus_Success; // Nothing to do
+ } else {
+
+ SCB_CleanInvalidateDCache();
+ SCB_DisableDCache();
+
+ // write data in chunks not crossing a page boundary
+ do {
+ next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary
+ write_length = next_addr - dest_addr; // calculate write length based on destination address and subsequent page boundary.
+ if (write_length > length) { // compare possible write_length against remaining data length
+ write_length = length;
+ }
+
+ __disable_irq();
+ status = flexspi_nor_flash_page_program(BOARD_FLEX_SPI, dest_addr, (uint32_t *)src, write_length);
+ __enable_irq();
+
+ // Update remaining data length
+ length -= write_length;
+
+ // Move source and destination pointer
+ src += write_length;
+ dest_addr += write_length;
+ } while ((length > 0) && (status == kStatus_Success));
+
+ SCB_EnableDCache();
+
+ }
+ return status;
+}
+
+// flash_read_block(flash_src_addr_bytes, data_dest, length_bytes)
+// read length_byte data to the source address
+// It is just a shim to provide the same structure for read_block and write_block.
+__attribute__((section(".ram_functions"))) void flash_read_block(uint32_t src_addr, uint8_t *dest, uint32_t length) {
+ memcpy(dest, (const uint8_t *)(BOARD_FLEX_SPI_ADDR_BASE + src_addr), length);
+}
diff --git a/ports/mimxrt/flash.h b/ports/mimxrt/flash.h
new file mode 100644
index 000000000000..ad010767c8e5
--- /dev/null
+++ b/ports/mimxrt/flash.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Philipp Ebensberger
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_MIMXRT_FLASH_H
+#define MICROPY_INCLUDED_MIMXRT_FLASH_H
+
+#include BOARD_FLASH_OPS_HEADER_H
+
+#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
+#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
+#define BLOCK_SIZE_BYTES (qspiflash_config.blockSize)
+
+#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
+#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
+
+#ifndef MICROPY_HW_FLASH_STORAGE_BYTES
+#define MICROPY_HW_FLASH_STORAGE_BYTES (((uint32_t)&__vfs_end) - ((uint32_t)&__vfs_start))
+#endif
+
+#ifndef MICROPY_HW_FLASH_STORAGE_BASE
+#define MICROPY_HW_FLASH_STORAGE_BASE (((uint32_t)&__vfs_start) - ((uint32_t)&__flash_start))
+#endif
+
+// Linker symbols
+extern uint8_t __vfs_start;
+extern uint8_t __vfs_end;
+extern uint8_t __flash_start;
+
+void flash_init(void);
+status_t flash_erase_sector(uint32_t erase_addr);
+status_t flash_erase_block(uint32_t erase_addr);
+void flash_read_block(uint32_t src_addr, uint8_t *dest, uint32_t length);
+status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length);
+
+#endif // MICROPY_INCLUDED_MIMXRT_FLASH_H
diff --git a/ports/mimxrt/hal/flexspi_flash_config.h b/ports/mimxrt/hal/flexspi_flash_config.h
index 80526880be0b..5320231a1495 100644
--- a/ports/mimxrt/hal/flexspi_flash_config.h
+++ b/ports/mimxrt/hal/flexspi_flash_config.h
@@ -123,7 +123,7 @@ enum
kFlexSpiDeviceType_SerialNAND = 2, // !< Flash devices are Serial NAND
kFlexSpiDeviceType_SerialRAM = 3, // !< Flash devices are Serial RAM/HyperFLASH
kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND
- kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, // !< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs
+ kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, // !< Flash device is MCP device, A1 is Serial NOR, A2 is Serial RAMs
};
// !@brief Flash Pad Definitions
@@ -184,7 +184,7 @@ typedef struct _FlexSPIConfig
// ! details
uint8_t deviceType; // !< [0x044-0x044] Device Type: See Flash Type Definition for more details
uint8_t sflashPadType; // !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal
- uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
+ uint8_t serialClkFreq; // !< [0x046-0x046] Serial Flash Frequency, device specific definitions, See System Boot
// ! Chapter for more details
uint8_t lutCustomSeqEnable; // !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
// ! be done using 1 LUT sequence, currently, only applicable to HyperFLASH
@@ -222,6 +222,7 @@ typedef struct _FlexSPIConfig
#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10
#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 12
+#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 13
#define HYPERFLASH_CMD_LUT_SEQ_IDX_READDATA 0
#define HYPERFLASH_CMD_LUT_SEQ_IDX_WRITEDATA 1
@@ -245,7 +246,7 @@ typedef struct _flexspi_nor_config
uint8_t serialNorType; // !< Serial NOR Flash type: 0/1/2/3
uint8_t needExitNoCmdMode; // !< Need to exit NoCmd mode before other IP command
uint8_t halfClkForNonReadCmd; // !< Half the Serial Clock for non-read command: true/false
- uint8_t needRestoreNoCmdMode; // !< Need to Restore NoCmd mode after IP commmand execution
+ uint8_t needRestoreNoCmdMode; // !< Need to Restore NoCmd mode after IP command execution
uint32_t blockSize; // !< Block size
uint32_t reserve2[11]; // !< Reserved for future use
} flexspi_nor_config_t;
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.c b/ports/mimxrt/hal/flexspi_hyper_flash.c
index c7b41658a498..5e5d87166d85 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.c
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.c
@@ -51,11 +51,11 @@ __attribute__((always_inline)) static inline void clock_disable_clock(clock_ip_n
static void SetFlexSPIDiv(uint32_t div) __attribute__((section(".ram_functions")));
static void SetFlexSPIDiv(uint32_t div) {
- FLEXSPI_Enable(FLEXSPI, false);
+ FLEXSPI_Enable(BOARD_FLEX_SPI, false);
clock_disable_clock(kCLOCK_FlexSpi);
clock_set_div(kCLOCK_FlexspiDiv, div); /* flexspi clock 332M, DDR mode, internal clock 166M. */
clock_enable_clock(kCLOCK_FlexSpi);
- FLEXSPI_Enable(FLEXSPI, true);
+ FLEXSPI_Enable(BOARD_FLEX_SPI, true);
}
status_t flexspi_nor_hyperbus_read(FLEXSPI_Type *base, uint32_t addr, uint32_t *buffer, uint32_t bytes) __attribute__((section(".ram_functions")));
@@ -175,6 +175,11 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
return status;
}
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) {
+ return flexspi_nor_flash_erase_sector(base, address); // HyperFlash does not support block erase!
+}
+
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions")));
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size) {
status_t status;
diff --git a/ports/mimxrt/hal/flexspi_hyper_flash.h b/ports/mimxrt/hal/flexspi_hyper_flash.h
index dbd028fd6f71..a6454a1c9a23 100644
--- a/ports/mimxrt/hal/flexspi_hyper_flash.h
+++ b/ports/mimxrt/hal/flexspi_hyper_flash.h
@@ -26,16 +26,30 @@
#ifndef MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
#define MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_HYPER_FLASH_H
-#include "fsl_flexspi.h"
#include "mpconfigboard.h"
-#include BOARD_FLASH_CONFIG_HEADER_H
+#include "flexspi_flash_config.h"
+#include "fsl_flexspi.h"
+// #include BOARD_FLASH_CONFIG_HEADER_H
+
+#if defined MICROPY_HW_FLASH_INTERNAL
+#define BOARD_FLEX_SPI FLEXSPI2
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI2_AMBA_BASE
+#elif defined MIMXRT117x_SERIES
+#define BOARD_FLEX_SPI FLEXSPI1
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI1_AMBA_BASE
+#else
+#define BOARD_FLEX_SPI FLEXSPI
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI_AMBA_BASE
+#endif
// Defined in boards flash_config.c
extern flexspi_nor_config_t qspiflash_config;
status_t flexspi_nor_hyperflash_cfi(FLEXSPI_Type *base);
+void flexspi_hyper_flash_init(void);
void flexspi_nor_update_lut(void);
status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address);
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
static inline uint32_t flexspi_get_frequency(void) {
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.c b/ports/mimxrt/hal/flexspi_nor_flash.c
index 8c04150d1273..956fb657db6d 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.c
+++ b/ports/mimxrt/hal/flexspi_nor_flash.c
@@ -165,6 +165,37 @@ status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {
return status;
}
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) __attribute__((section(".ram_functions")));
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address) {
+ status_t status;
+ flexspi_transfer_t flashXfer;
+
+ /* Write enable */
+ status = flexspi_nor_write_enable(base, address);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ /* Erase sector */
+ flashXfer.deviceAddress = address;
+ flashXfer.port = kFLEXSPI_PortA1;
+ flashXfer.cmdType = kFLEXSPI_Command;
+ flashXfer.SeqNumber = 1;
+ flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK;
+ status = FLEXSPI_TransferBlocking(base, &flashXfer);
+
+ if (status != kStatus_Success) {
+ return status;
+ }
+
+ status = flexspi_nor_wait_bus_busy(base);
+
+ flexspi_nor_reset(base);
+
+ return status;
+}
+
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) __attribute__((section(".ram_functions")));
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) {
status_t status;
@@ -193,7 +224,7 @@ status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, co
status = flexspi_nor_wait_bus_busy(base);
- flexspi_nor_reset(FLEXSPI);
+ flexspi_nor_reset(BOARD_FLEX_SPI);
return status;
}
diff --git a/ports/mimxrt/hal/flexspi_nor_flash.h b/ports/mimxrt/hal/flexspi_nor_flash.h
index f8c31488a988..6526142af22f 100644
--- a/ports/mimxrt/hal/flexspi_nor_flash.h
+++ b/ports/mimxrt/hal/flexspi_nor_flash.h
@@ -30,33 +30,25 @@
#include "mpconfigboard.h"
#include BOARD_FLASH_CONFIG_HEADER_H
+#if defined MICROPY_HW_FLASH_INTERNAL
+#define BOARD_FLEX_SPI FLEXSPI2
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI2_AMBA_BASE
+#elif defined MIMXRT117x_SERIES
+#define BOARD_FLEX_SPI FLEXSPI1
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI1_AMBA_BASE
+#else
+#define BOARD_FLEX_SPI FLEXSPI
+#define BOARD_FLEX_SPI_ADDR_BASE FlexSPI_AMBA_BASE
+#endif
+
// Defined in boards flash_config.c
extern flexspi_nor_config_t qspiflash_config;
status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId);
+status_t flexspi_nor_init(void);
void flexspi_nor_update_lut(void);
status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
+status_t flexspi_nor_flash_erase_block(FLEXSPI_Type *base, uint32_t address);
status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t address, const uint32_t *src, uint32_t size);
-static inline uint32_t flexspi_get_frequency(void) {
- uint32_t div;
- uint32_t fre;
-
- /* Clock divider:
- 000 divided by 1
- 001 divided by 2
- 010 divided by 3
- 011 divided by 4
- 100 divided by 5
- 101 divided by 6
- 110 divided by 7
- 111 divided by 8
- */
- div = CLOCK_GetDiv(kCLOCK_FlexspiDiv);
- /* Get frequency */
- fre = CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (div + 0x01U);
-
- return fre;
-}
-
#endif // MICROPY_INCLUDED_MIMXRT_HAL_FLEXSPI_NOR_FLASH_H
diff --git a/ports/mimxrt/hal/fsl_flexspi_nor_boot.h b/ports/mimxrt/hal/fsl_flexspi_nor_boot.h
index fbb8a574f3ea..58443119d465 100644
--- a/ports/mimxrt/hal/fsl_flexspi_nor_boot.h
+++ b/ports/mimxrt/hal/fsl_flexspi_nor_boot.h
@@ -97,7 +97,7 @@ typedef struct _boot_data_ {
uint32_t start; /* boot start location */
uint32_t size; /* size */
uint32_t plugin; /* plugin flag - 1 if downloaded application is plugin */
- uint32_t placeholder; /* placehoder to make even 0x10 size */
+ uint32_t placeholder; /* placeholder to make even 0x10 size */
}BOOT_DATA_T;
#if defined(BOARD_FLASH_SIZE)
diff --git a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
index 9d6b4fdf7815..7d51953f5b1a 100644
--- a/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
+++ b/ports/mimxrt/hal/phy/device/phydp83825/fsl_phydp83825.h
@@ -117,7 +117,7 @@ status_t PHY_DP83825_GetLinkStatus(phy_handle_t *handle, bool *status);
* @brief Gets the PHY link speed and duplex.
*
* @brief This function gets the speed and duplex mode of PHY. User can give one of speed
- * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
*
* @param handle PHY device handle.
* @param speed The address of PHY link speed.
diff --git a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h
index 7ccc260f7b03..6680247e4382 100644
--- a/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h
+++ b/ports/mimxrt/hal/phy/device/phydp83848/fsl_phydp83848.h
@@ -117,7 +117,7 @@ status_t PHY_DP83848_GetLinkStatus(phy_handle_t *handle, bool *status);
* @brief Gets the PHY link speed and duplex.
*
* @brief This function gets the speed and duplex mode of PHY. User can give one of speed
- * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
*
* @param handle PHY device handle.
* @param speed The address of PHY link speed.
diff --git a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
index 5b93c5698a6b..49e930df6689 100644
--- a/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
+++ b/ports/mimxrt/hal/phy/device/phyksz8081/fsl_phyksz8081.h
@@ -117,7 +117,7 @@ status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status);
* @brief Gets the PHY link speed and duplex.
*
* @brief This function gets the speed and duplex mode of PHY. User can give one of speed
- * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
*
* @param handle PHY device handle.
* @param speed The address of PHY link speed.
diff --git a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
index 2e8b4e3631ba..dcd5ebbe7984 100644
--- a/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
+++ b/ports/mimxrt/hal/phy/device/phylan8720/fsl_phylan8720.h
@@ -117,7 +117,7 @@ status_t PHY_LAN8720_GetLinkStatus(phy_handle_t *handle, bool *status);
* @brief Gets the PHY link speed and duplex.
*
* @brief This function gets the speed and duplex mode of PHY. User can give one of speed
- * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
*
* @param handle PHY device handle.
* @param speed The address of PHY link speed.
diff --git a/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c b/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c
new file mode 100644
index 000000000000..0c6cf82dae4a
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_phyrtl8211f.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief Defines the PHY RTL8211F vendor defined registers. */
+#define PHY_SPECIFIC_STATUS_REG 0x1AU /*!< The PHY specific status register. */
+#define PHY_PAGE_SELECT_REG 0x1FU /*!< The PHY page select register. */
+
+/*! @brief Defines the PHY RTL8211F ID number. */
+#define PHY_CONTROL_ID1 0x001CU /*!< The PHY ID1 . */
+
+/*! @brief Defines the mask flag in specific status register. */
+#define PHY_SSTATUS_LINKSTATUS_MASK 0x04U /*!< The PHY link status mask. */
+#define PHY_SSTATUS_LINKSPEED_MASK 0x30U /*!< The PHY link speed mask. */
+#define PHY_SSTATUS_LINKDUPLEX_MASK 0x08U /*!< The PHY link duplex mask. */
+#define PHY_SSTATUS_LINKSPEED_SHIFT 4U /*!< The link speed shift */
+
+/*! @brief Defines the PHY RTL8211F extra page and the registers in specified page. */
+#define PHY_PAGE_RGMII_TXRX_DELAY_ADDR 0xD08U /*!< The register page including RGMII TX/RX delay setting. */
+#define PHY_RGMII_TX_DELAY_REG 0x11U /*!< The RGMII TXC delay register. */
+#define PHY_RGMII_RX_DELAY_REG 0x15U /*!< The RGMII RXC delay register. */
+#define PHY_RGMII_TX_DELAY_MASK 0x100U /*!< The RGMII TXC delay mask. */
+#define PHY_RGMII_RX_DELAY_MASK 0x8U /*!< The RGMII RXC delay mask. */
+
+/*! @brief MDIO MMD Devices .*/
+#define PHY_MDIO_MMD_PCS 3U
+#define PHY_MDIO_MMD_AN 7U
+
+/*! @brief MDIO MMD Physical Coding layer device registers .*/
+#define PHY_MDIO_PCS_EEE_CAP 0x14U /* EEE capability */
+
+/*! @brief MDIO MMD AutoNegotiation device registers .*/
+#define PHY_MDIO_AN_EEE_ADV 0x3CU /* EEE advertisement */
+
+/*! @brief MDIO MMD EEE mask flags. (common for adv and cap) */
+#define PHY_MDIO_EEE_100TX 0x2U
+#define PHY_MDIO_EEE_1000T 0x4U
+
+/*! @brief Defines the timeout macro. */
+#define PHY_READID_TIMEOUT_COUNT 1000U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+static status_t PHY_RTL8211F_MMD_SetDevice(phy_handle_t *handle,
+ uint8_t device,
+ uint16_t addr,
+ phy_mmd_access_mode_t mode);
+static inline status_t PHY_RTL8211F_MMD_ReadData(phy_handle_t *handle, uint32_t *data);
+static inline status_t PHY_RTL8211F_MMD_WriteData(phy_handle_t *handle, uint32_t data);
+static status_t PHY_RTL8211F_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint32_t *data);
+static status_t PHY_RTL8211F_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint32_t data);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+const phy_operations_t phyrtl8211f_ops = {.phyInit = PHY_RTL8211F_Init,
+ .phyWrite = PHY_RTL8211F_Write,
+ .phyRead = PHY_RTL8211F_Read,
+ .getAutoNegoStatus = PHY_RTL8211F_GetAutoNegotiationStatus,
+ .getLinkStatus = PHY_RTL8211F_GetLinkStatus,
+ .getLinkSpeedDuplex = PHY_RTL8211F_GetLinkSpeedDuplex,
+ .setLinkSpeedDuplex = PHY_RTL8211F_SetLinkSpeedDuplex,
+ .enableLoopback = PHY_RTL8211F_EnableLoopback};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+status_t PHY_RTL8211F_Init(phy_handle_t *handle, const phy_config_t *config) {
+ uint32_t counter = PHY_READID_TIMEOUT_COUNT;
+ status_t result;
+ uint32_t regValue = 0U;
+
+ /* Init MDIO interface. */
+ MDIO_Init(handle->mdioHandle);
+
+ /* Assign phy address. */
+ handle->phyAddr = config->phyAddr;
+
+ /* Check PHY ID. */
+ do
+ {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ counter--;
+ } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
+
+ if (counter == 0U) {
+ return kStatus_Fail;
+ }
+
+ /* Reset PHY. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* The RGMII specifies output TXC/RXC and TXD/RXD without any clock skew. Need to add skew on clock line
+ to make sure the other side sample right data. This can also be done in PCB traces. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_PAGE_SELECT_REG, PHY_PAGE_RGMII_TXRX_DELAY_ADDR);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ /* Set Tx Delay. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RGMII_TX_DELAY_REG, ®Value);
+ if (result == kStatus_Success) {
+ regValue |= PHY_RGMII_TX_DELAY_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RGMII_TX_DELAY_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ } else {
+ return result;
+ }
+ /* Set Rx Delay. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_RGMII_RX_DELAY_REG, ®Value);
+ if (result == kStatus_Success) {
+ regValue |= PHY_RGMII_RX_DELAY_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_RGMII_RX_DELAY_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ } else {
+ return result;
+ }
+ /* Restore to default page 0 */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_PAGE_SELECT_REG, 0x0);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Energy Efficient Ethernet configuration */
+ if (config->enableEEE) {
+ /* Get capabilities */
+ result = PHY_RTL8211F_MMD_Read(handle, PHY_MDIO_MMD_PCS, PHY_MDIO_PCS_EEE_CAP, ®Value);
+ if (result == kStatus_Success) {
+ /* Enable EEE for 100TX and 1000T */
+ result = PHY_RTL8211F_MMD_Write(handle, PHY_MDIO_MMD_AN, PHY_MDIO_AN_EEE_ADV,
+ regValue & (PHY_MDIO_EEE_1000T | PHY_MDIO_EEE_100TX));
+ }
+ } else {
+ result = PHY_RTL8211F_MMD_Write(handle, PHY_MDIO_MMD_AN, PHY_MDIO_AN_EEE_ADV, 0);
+ }
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ if (config->autoNeg) {
+ /* Set the auto-negotiation. */
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
+ PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK |
+ PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK);
+ if (result == kStatus_Success) {
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_1000BASET_CONTROL_REG,
+ PHY_1000BASET_FULLDUPLEX_MASK);
+ if (result == kStatus_Success) {
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value);
+ if (result == kStatus_Success) {
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ }
+ }
+ } else {
+ /* Disable isolate mode */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value);
+ if (result != kStatus_Success) {
+ return result;
+ }
+ regValue &= PHY_BCTL_ISOLATE_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
+ result = PHY_RTL8211F_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
+ }
+ return result;
+}
+
+status_t PHY_RTL8211F_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
+}
+
+status_t PHY_RTL8211F_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) {
+ return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
+}
+
+status_t PHY_RTL8211F_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ *status = false;
+
+ /* Check auto negotiation complete. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value);
+ if (result == kStatus_Success) {
+ if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) {
+ *status = true;
+ }
+ }
+ return result;
+}
+
+status_t PHY_RTL8211F_GetLinkStatus(phy_handle_t *handle, bool *status) {
+ assert(status);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Read the basic status register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SPECIFIC_STATUS_REG, ®Value);
+ if (result == kStatus_Success) {
+ if ((PHY_SSTATUS_LINKSTATUS_MASK & regValue) != 0U) {
+ /* Link up. */
+ *status = true;
+ } else {
+ /* Link down. */
+ *status = false;
+ }
+ }
+ return result;
+}
+
+status_t PHY_RTL8211F_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) {
+ assert(!((speed == NULL) && (duplex == NULL)));
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Read the status register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SPECIFIC_STATUS_REG, ®Value);
+ if (result == kStatus_Success) {
+ if (speed != NULL) {
+ switch ((regValue & PHY_SSTATUS_LINKSPEED_MASK) >> PHY_SSTATUS_LINKSPEED_SHIFT)
+ {
+ case (uint32_t)kPHY_Speed10M:
+ *speed = kPHY_Speed10M;
+ break;
+ case (uint32_t)kPHY_Speed100M:
+ *speed = kPHY_Speed100M;
+ break;
+ case (uint32_t)kPHY_Speed1000M:
+ *speed = kPHY_Speed1000M;
+ break;
+ default:
+ *speed = kPHY_Speed10M;
+ break;
+ }
+ }
+
+ if (duplex != NULL) {
+ if ((regValue & PHY_SSTATUS_LINKDUPLEX_MASK) != 0U) {
+ *duplex = kPHY_FullDuplex;
+ } else {
+ *duplex = kPHY_HalfDuplex;
+ }
+ }
+ }
+ return result;
+}
+
+status_t PHY_RTL8211F_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) {
+ status_t result;
+ uint32_t regValue;
+
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value);
+ if (result == kStatus_Success) {
+ /* Disable the auto-negotiation and set according to user-defined configuration. */
+ regValue &= ~PHY_BCTL_AUTONEG_MASK;
+ if (speed == kPHY_Speed1000M) {
+ regValue &= PHY_BCTL_SPEED0_MASK;
+ regValue |= PHY_BCTL_SPEED1_MASK;
+ } else if (speed == kPHY_Speed100M) {
+ regValue |= PHY_BCTL_SPEED0_MASK;
+ regValue &= ~PHY_BCTL_SPEED1_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_SPEED0_MASK;
+ regValue &= ~PHY_BCTL_SPEED1_MASK;
+ }
+ if (duplex == kPHY_FullDuplex) {
+ regValue |= PHY_BCTL_DUPLEX_MASK;
+ } else {
+ regValue &= ~PHY_BCTL_DUPLEX_MASK;
+ }
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ }
+ return result;
+}
+
+status_t PHY_RTL8211F_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) {
+ /* This PHY only supports local loopback. */
+ assert(mode == kPHY_LocalLoop);
+
+ status_t result;
+ uint32_t regValue;
+
+ /* Set the loop mode. */
+ if (enable) {
+ if (speed == kPHY_Speed1000M) {
+ regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ } else if (speed == kPHY_Speed100M) {
+ regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ } else {
+ regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
+ }
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
+ } else {
+ /* First read the current status in control register. */
+ result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value);
+ if (result == kStatus_Success) {
+ regValue &= ~PHY_BCTL_LOOP_MASK;
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
+ (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
+ }
+ }
+ return result;
+}
+
+static status_t PHY_RTL8211F_MMD_SetDevice(phy_handle_t *handle,
+ uint8_t device,
+ uint16_t addr,
+ phy_mmd_access_mode_t mode) {
+ status_t result = kStatus_Success;
+
+ /* Set Function mode of address access(b00) and device address. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MMD_ACCESS_CONTROL_REG, device);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Set register address. */
+ result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MMD_ACCESS_DATA_REG, addr);
+ if (result != kStatus_Success) {
+ return result;
+ }
+
+ /* Set Function mode of data access(b01~11) and device address. */
+ result =
+ MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MMD_ACCESS_CONTROL_REG, (uint32_t)mode | (uint32_t)device);
+ return result;
+}
+
+static inline status_t PHY_RTL8211F_MMD_ReadData(phy_handle_t *handle, uint32_t *data) {
+ return MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_MMD_ACCESS_DATA_REG, data);
+}
+
+static inline status_t PHY_RTL8211F_MMD_WriteData(phy_handle_t *handle, uint32_t data) {
+ return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_MMD_ACCESS_DATA_REG, data);
+}
+
+static status_t PHY_RTL8211F_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint32_t *data) {
+ status_t result = kStatus_Success;
+ result = PHY_RTL8211F_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
+ if (result == kStatus_Success) {
+ result = PHY_RTL8211F_MMD_ReadData(handle, data);
+ }
+ return result;
+}
+
+static status_t PHY_RTL8211F_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint32_t data) {
+ status_t result = kStatus_Success;
+
+ result = PHY_RTL8211F_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
+ if (result == kStatus_Success) {
+ result = PHY_RTL8211F_MMD_WriteData(handle, data);
+ }
+ return result;
+}
diff --git a/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h b/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h
new file mode 100644
index 000000000000..0598b2511265
--- /dev/null
+++ b/ports/mimxrt/hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*****************************************************************************
+ * PHY RTL8211F driver change log
+ *****************************************************************************/
+
+/*!
+@page driver_log Driver Change Log
+
+@section phyrtl8211 PHYRTL8211F
+ The current PHYRTL8211F driver version is 2.0.0.
+
+ - 2.0.0
+ - Initial version.
+*/
+
+#ifndef _FSL_PHYRTL8211F_H_
+#define _FSL_PHYRTL8211F_H_
+
+#include "fsl_phy.h"
+
+/*!
+ * @addtogroup phy_driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @brief PHY driver version */
+#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
+
+/*! @brief PHY operations structure. */
+extern const phy_operations_t phyrtl8211f_ops;
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PHY Driver
+ * @{
+ */
+
+/*!
+ * @brief Initializes PHY.
+ *
+ * This function initialize PHY.
+ *
+ * @param handle PHY device handle.
+ * @param config Pointer to structure of phy_config_t.
+ * @retval kStatus_Success PHY initialization succeeds
+ * @retval kStatus_Fail PHY initialization fails
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_Init(phy_handle_t *handle, const phy_config_t *config);
+
+/*!
+ * @brief PHY Write function. This function writes data over the SMI to
+ * the specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param data The data written to the PHY register.
+ * @retval kStatus_Success PHY write success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data);
+
+/*!
+ * @brief PHY Read function. This interface reads data over the SMI from the
+ * specified PHY register. This function is called by all PHY interfaces.
+ *
+ * @param handle PHY device handle.
+ * @param phyReg The PHY register.
+ * @param dataPtr The address to store the data read from the PHY register.
+ * @retval kStatus_Success PHY read success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr);
+
+/*!
+ * @brief Gets the PHY auto-negotiation status.
+ *
+ * @param handle PHY device handle.
+ * @param status The auto-negotiation status of the PHY.
+ * - true the auto-negotiation is over.
+ * - false the auto-negotiation is on-going or not started.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link status.
+ *
+ * @param handle PHY device handle.
+ * @param status The link up or down status of the PHY.
+ * - true the link is up.
+ * - false the link is down.
+ * @retval kStatus_Success PHY gets link status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_GetLinkStatus(phy_handle_t *handle, bool *status);
+
+/*!
+ * @brief Gets the PHY link speed and duplex.
+ *
+ * @brief This function gets the speed and duplex mode of PHY. User can give one of speed
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
+ *
+ * @param handle PHY device handle.
+ * @param speed The address of PHY link speed.
+ * @param duplex The link duplex of PHY.
+ * @retval kStatus_Success PHY gets link speed and duplex success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex);
+
+/*!
+ * @brief Sets the PHY link speed and duplex.
+ *
+ * @param handle PHY device handle.
+ * @param speed Specified PHY link speed.
+ * @param duplex Specified PHY link duplex.
+ * @retval kStatus_Success PHY gets status success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex);
+
+/*!
+ * @brief Enables/disables PHY loopback.
+ *
+ * @param handle PHY device handle.
+ * @param mode The loopback mode to be enabled, please see "phy_loop_t".
+ * All loopback modes should not be set together, when one loopback mode is set
+ * another should be disabled.
+ * @param speed PHY speed for loopback mode.
+ * @param enable True to enable, false to disable.
+ * @retval kStatus_Success PHY loopback success
+ * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
+ */
+status_t PHY_RTL8211F_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable);
+
+/* @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /* _FSL_PHY_H_ */
diff --git a/ports/mimxrt/hal/phy/fsl_phy.h b/ports/mimxrt/hal/phy/fsl_phy.h
index 6a022d4eaed1..53edd9d0b650 100644
--- a/ports/mimxrt/hal/phy/fsl_phy.h
+++ b/ports/mimxrt/hal/phy/fsl_phy.h
@@ -207,7 +207,7 @@ static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status) {
* @brief Gets the PHY link speed and duplex.
*
* @brief This function gets the speed and duplex mode of PHY. User can give one of speed
- * and duplex address paramter and set the other as NULL if only wants to get one of them.
+ * and duplex address parameter and set the other as NULL if only wants to get one of them.
*
* @param handle PHY device handle.
* @param speed The address of PHY link speed.
diff --git a/ports/mimxrt/hal/qspi_nor_flash_config.c b/ports/mimxrt/hal/qspi_nor_flash_config.c
index 469a584b877a..a6bbd624ed53 100644
--- a/ports/mimxrt/hal/qspi_nor_flash_config.c
+++ b/ports/mimxrt/hal/qspi_nor_flash_config.c
@@ -129,11 +129,17 @@ const flexspi_nor_config_t qspiflash_config = {
FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+
+ // 13 Erase Block (32k) -> 13
+ FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x52, RADDR_SDR, FLEXSPI_1PAD, 24),
+ FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
+ FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), // Filler
},
},
.pageSize = 256u,
.sectorSize = 4u * 1024u,
- .blockSize = 64u * 1024u,
+ .blockSize = 32u * 1024u,
.isUniformBlockSize = false,
// .ipcmdSerialClkFreq = kFlexSpiSerialClk_30MHz,
};
diff --git a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S
index 8fe061103388..fe933c6d6002 100644
--- a/ports/mimxrt/hal/resethandler_MIMXRT10xx.S
+++ b/ports/mimxrt/hal/resethandler_MIMXRT10xx.S
@@ -37,6 +37,13 @@ Reset_Handler:
str r1,[r0] /* store FLEXRAM configuration value to IOMUXC_GPR17 */
dsb
isb
+#if defined MIMXRT117x_SERIES
+ ldr r0, =__iomux_gpr18_adr /* load IOMUXC_GPR18 register address to R0 */
+ ldr r1, =__iomux_gpr18_value /* move FlexRAM configuration value to R1 */
+ str r1,[r0] /* store FLEXRAM configuration value to IOMUXC_GPR18 */
+ dsb
+ isb
+#endif
ldr r0, =__iomux_gpr16_adr /* load IOMUXC_GPR16 register address to R0 */
ldr r1,[r0] /* load IOMUXC_GPR16 register value to R1 */
orr r1, r1, #4 /* set corresponding FLEXRAM_BANK_CFG_SEL bit */
@@ -53,7 +60,7 @@ Reset_Handler:
* linker script.
* __etext: End of code section, i.e., begin of data sections to copy from.
* __data_start__/__data_end__: RAM address range that data should be
- * __noncachedata_start__/__noncachedata_end__ : none cachable region
+ * __noncachedata_start__/__noncachedata_end__ : non-cacheable region
* __ram_function_start__/__ram_function_end__ : ramfunction region
* copied to. Both must be aligned to 4 bytes boundary. */
@@ -73,7 +80,7 @@ Reset_Handler:
str r0, [r2, r3]
bgt .LC0
.LC1:
-#else /* code size implemenation */
+#else /* code size implementation */
.LC0:
cmp r2, r3
ittt lt
@@ -96,7 +103,7 @@ Reset_Handler:
str r0, [r2, r3]
bgt .LC_ramfunc_copy_start
.LC_ramfunc_copy_end:
-#else /* code size implemenation */
+#else /* code size implementation */
.LC_ramfunc_copy_start:
cmp r2, r3
ittt lt
@@ -120,7 +127,7 @@ Reset_Handler:
str r0, [r2, r3]
bgt .LC2
.LC3:
-#else /* code size implemenation */
+#else /* code size implementation */
.LC2:
cmp r2, r3
ittt lt
diff --git a/ports/mimxrt/help.c b/ports/mimxrt/help.c
new file mode 100644
index 000000000000..10627aff7fdc
--- /dev/null
+++ b/ports/mimxrt/help.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 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
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/builtin.h"
+
+const char mimxrt_help_text[] =
+ "Welcome to MicroPython!\n"
+ "\n"
+ "For online docs please visit http://docs.micropython.org/\n"
+ "\n"
+ "For access to the hardware use the 'machine' module. \n"
+ "\n"
+ "Quick overview of some objects:\n"
+ " machine.Pin(pin) -- get a pin, eg machine.Pin(0)\n"
+ " machine.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n"
+ " methods: init(..), value([v]), high(), low())\n"
+ "\n"
+ " Pins are numbered board specific, either 0-n, or 'D0'-'Dn', or 'A0' - 'An',\n"
+ " according to the boards's pinout sheet.\n"
+ " Pin IO modes are: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN\n"
+ " Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
+ " machine.ADC(pin) -- make an analog object from a pin\n"
+ " methods: read_u16()\n"
+ " machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8, board-specific)\n"
+ " methods: init(), write(buf), any()\n"
+ " buf=read(n), readinto(buf), buf=readline()\n"
+ " The RX and TX pins are fixed and board-specific.\n"
+ " machine.SoftI2C() -- create a Soft I2C object\n"
+ " machine.I2C(id) -- create a HW I2C object\n"
+ " methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n"
+ " readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n"
+ " SoftI2C allows to use any pin for sda and scl, HW I2C id's and pins are fixed\n"
+ " machine.SoftSPI(baudrate=1000000) -- create a Soft SPI object\n"
+ " machine.SPI(id, baudrate=1000000) -- create a HW SPI object\n"
+ " methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n"
+ " SoftSPI allows to use any pin for SPI, HW SPI id's and pins are fixed\n"
+ " machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n"
+ " eg: machine.Timer(freq=1, callback=lambda t:print(t))\n"
+ " machine.RTC() -- create a Real Time Clock object\n"
+ " methods: init(), datetime([dateime_tuple]), now()\n"
+ " machine.PWM(pin, freq, duty_u16[, kw_opts]) -- create a PWM object\n"
+ " methods: init(), duty_u16([value]), duty_ns([value]), freq([value])\n"
+ "\n"
+ "Useful control commands:\n"
+ " CTRL-C -- interrupt a running program\n"
+ " CTRL-D -- on a blank line, do a soft reset of the board\n"
+ " CTRL-E -- on a blank line, enter paste mode\n"
+ "\n"
+ "For further help on a specific object, type help(obj)\n"
+ "For a list of available modules, type help('modules')\n"
+;
diff --git a/ports/mimxrt/led.c b/ports/mimxrt/led.c
index cb9f9854646e..216affa227ec 100644
--- a/ports/mimxrt/led.c
+++ b/ports/mimxrt/led.c
@@ -31,16 +31,23 @@
#include "py/mphal.h"
#include "led.h"
-#if NUM_LEDS
-
-const machine_led_obj_t machine_led_obj[NUM_LEDS] = {
- {
- .base = {&machine_led_type},
- .led_id = 1U,
- .led_pin = &MICROPY_HW_LED1_PIN,
- }
+#if defined(MICROPY_HW_LED1_PIN)
+
+const machine_led_obj_t machine_led_obj[] = {
+ { .base = {&machine_led_type}, .led_id = 1U, .led_pin = &MICROPY_HW_LED1_PIN, },
+ #if defined(MICROPY_HW_LED2_PIN)
+ { .base = {&machine_led_type}, .led_id = 2U, .led_pin = &MICROPY_HW_LED2_PIN, },
+ #if defined(MICROPY_HW_LED3_PIN)
+ { .base = {&machine_led_type}, .led_id = 3U, .led_pin = &MICROPY_HW_LED3_PIN, },
+ #if defined(MICROPY_HW_LED4_PIN)
+ { .base = {&machine_led_type}, .led_id = 4U, .led_pin = &MICROPY_HW_LED4_PIN, },
+ #endif
+ #endif
+ #endif
};
+#define NUM_LEDS MP_ARRAY_SIZE(machine_led_obj)
+
void led_init(void) {
// Turn off LEDs and initialize
for (mp_int_t led = 0; led < NUM_LEDS; led++) {
@@ -94,9 +101,4 @@ void led_debug(int value, int delay) {
mp_hal_delay_ms(delay);
}
-#else
-
-void led_init(void) {
-}
-
#endif
diff --git a/ports/mimxrt/led.h b/ports/mimxrt/led.h
index a0628e90eddc..7807c4a9037e 100644
--- a/ports/mimxrt/led.h
+++ b/ports/mimxrt/led.h
@@ -29,14 +29,20 @@
#include "pin.h"
-#if defined(MICROPY_HW_LED1_PIN)
-#define NUM_LEDS (1)
-#else
-#define NUM_LEDS (0)
-#endif
-
typedef enum {
- MACHINE_BOARD_LED = 1,
+ #if defined(MICROPY_HW_LED1_PIN)
+ MACHINE_BOARD_LED1 = 1,
+ #if defined(MICROPY_HW_LED2_PIN)
+ MACHINE_BOARD_LED2 = 2,
+ #if defined(MICROPY_HW_LED3_PIN)
+ MACHINE_BOARD_LED3 = 3,
+ #if defined(MICROPY_HW_LED4_PIN)
+ MACHINE_BOARD_LED4 = 4,
+ #endif
+ #endif
+ #endif
+ #endif
+ MICROPY_HW_LED_MAX
} machine_led_t;
typedef struct _machine_led_obj_t {
@@ -51,6 +57,6 @@ void led_toggle(machine_led_t led);
void led_debug(int value, int delay);
extern const mp_obj_type_t machine_led_type;
-extern const machine_led_obj_t machine_led_obj[NUM_LEDS];
+extern const machine_led_obj_t machine_led_obj[];
#endif // MICROPY_INCLUDED_MIMXRT_LED_H
diff --git a/ports/mimxrt/machine_adc.c b/ports/mimxrt/machine_adc.c
index d63157d36efb..36e5fafc984b 100644
--- a/ports/mimxrt/machine_adc.c
+++ b/ports/mimxrt/machine_adc.c
@@ -29,7 +29,12 @@
#include "py/runtime.h"
#include "py/mphal.h"
+#if defined(MIMXRT117x_SERIES)
+#include "fsl_lpadc.h"
+#else
#include "fsl_adc.h"
+#endif
+
#include "fsl_gpio.h"
#include "fsl_iomuxc.h"
@@ -72,12 +77,14 @@ STATIC mp_obj_t adc_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
ADC_Type *adc_instance = pin->adc_list[0].instance; // NOTE: we only use the first ADC assignment - multiple assignments are not supported for now
uint8_t channel = pin->adc_list[0].channel;
+ #if 0 // done in adc_read_u16
// Configure ADC peripheral channel
adc_channel_config_t channel_config = {
.channelNumber = (uint32_t)channel,
.enableInterruptOnConversionCompleted = false,
};
ADC_SetChannelConfig(adc_instance, 0UL, &channel_config); // NOTE: we always choose channel group '0' since we only perform software triggered conversion
+ #endif
// Create ADC Instance
machine_adc_obj_t *o = mp_obj_malloc(machine_adc_obj_t, &machine_adc_type);
@@ -90,6 +97,43 @@ STATIC mp_obj_t adc_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
}
// read_u16()
+#if defined(MIMXRT117x_SERIES)
+STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
+ machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ lpadc_conv_command_config_t adc_config;
+ lpadc_conv_trigger_config_t trigger_config;
+
+ // Set ADC configuration
+ LPADC_GetDefaultConvCommandConfig(&adc_config);
+ adc_config.channelNumber = self->channel;
+ adc_config.sampleScaleMode = kLPADC_SamplePartScale;
+ LPADC_SetConvCommandConfig(self->adc, 1, &adc_config);
+
+ // Set Trigger mode
+ LPADC_GetDefaultConvTriggerConfig(&trigger_config);
+ trigger_config.targetCommandId = 1;
+ LPADC_SetConvTriggerConfig(self->adc, 0U, &trigger_config);
+
+ // Measure input voltage
+ LPADC_DoSoftwareTrigger(self->adc, 1U);
+ lpadc_conv_result_t result_struct;
+ while (!LPADC_GetConvResult(self->adc, &result_struct)) {
+ }
+
+ return MP_OBJ_NEW_SMALL_INT(result_struct.convValue * 2);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);
+
+void machine_adc_init(void) {
+ lpadc_config_t adc_config; // Set ADC configuration
+ LPADC_GetDefaultConfig(&adc_config);
+ adc_config.enableAnalogPreliminary = true;
+ adc_config.referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
+ LPADC_Init(LPADC1, &adc_config);
+}
+
+#else
+
STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -111,21 +155,6 @@ STATIC mp_obj_t machine_adc_read_u16(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);
-STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
-
-MP_DEFINE_CONST_OBJ_TYPE(
- machine_adc_type,
- MP_QSTR_ADC,
- MP_TYPE_FLAG_NONE,
- make_new, adc_obj_make_new,
- print, adc_obj_print,
- locals_dict, &adc_locals_dict
- );
-
void machine_adc_init(void) {
for (int i = 1; i < sizeof(adc_bases) / sizeof(ADC_Type *); ++i) {
ADC_Type *adc_instance = adc_bases[i];
@@ -143,3 +172,19 @@ void machine_adc_init(void) {
}
}
}
+#endif
+
+STATIC const mp_rom_map_elem_t adc_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
+
+MP_DEFINE_CONST_OBJ_TYPE(
+ machine_adc_type,
+ MP_QSTR_ADC,
+ MP_TYPE_FLAG_NONE,
+ make_new, adc_obj_make_new,
+ print, adc_obj_print,
+ locals_dict, &adc_locals_dict
+ );
diff --git a/ports/mimxrt/machine_i2c.c b/ports/mimxrt/machine_i2c.c
index f00ba6b1ba76..c0a3dee98a40 100644
--- a/ports/mimxrt/machine_i2c.c
+++ b/ports/mimxrt/machine_i2c.c
@@ -30,6 +30,7 @@
#include "extmod/machine_i2c.h"
#include "modmachine.h"
#include CLOCK_CONFIG_H
+#include "pin.h"
#include "fsl_iomuxc.h"
#include "fsl_lpi2c.h"
@@ -37,13 +38,6 @@
#define DEFAULT_I2C_FREQ (400000)
#define DEFAULT_I2C_DRIVE (6)
-// Select USB1 PLL (480 MHz) as master lpi2c clock source
-#define LPI2C_CLOCK_SOURCE_SELECT (0U)
-// Clock divider for master lpi2c clock source
-#define LPI2C_CLOCK_SOURCE_DIVIDER (1U)
-// Get frequency of lpi2c clock = 30 MHz
-#define LPI2C_CLOCK_FREQUENCY ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (LPI2C_CLOCK_SOURCE_DIVIDER + 1U))
-
typedef struct _machine_i2c_obj_t {
mp_obj_base_t base;
LPI2C_Type *i2c_inst;
diff --git a/ports/mimxrt/machine_i2s.c b/ports/mimxrt/machine_i2s.c
index 1733140fb57e..7711219441be 100644
--- a/ports/mimxrt/machine_i2s.c
+++ b/ports/mimxrt/machine_i2s.c
@@ -60,9 +60,9 @@
// - non-blocking mode is enabled when a callback is set with the irq() method
// - the DMA callback is used to implement the asynchronous background operations
//
-// Mode3: Uasyncio
+// Mode3: Asyncio
// - implements the stream protocol
-// - uasyncio mode is enabled when the ioctl() function is called
+// - asyncio mode is enabled when the ioctl() function is called
// - the state of the internal ring buffer is used to detect that I2S samples can be read or written
//
// The samples contained in the app buffer supplied for the readinto() and write() methods have the following convention:
@@ -99,7 +99,6 @@
#define NUM_I2S_USER_FORMATS (4)
#define I2S_RX_FRAME_SIZE_IN_BYTES (8)
-#define AUDIO_PLL_CLOCK (2U)
#define SAI_CHANNEL_0 (0)
#define SAI_NUM_AUDIO_CHANNELS (2U)
@@ -123,7 +122,7 @@ typedef enum {
typedef enum {
BLOCKING,
NON_BLOCKING,
- UASYNCIO
+ ASYNCIO
} io_mode_t;
typedef enum {
@@ -208,42 +207,69 @@ STATIC const int8_t i2s_frame_map[NUM_I2S_USER_FORMATS][I2S_RX_FRAME_SIZE_IN_BYT
// PLL output frequency = 24MHz * (.loopDivider + .numerator/.denominator)
// Configuration 1: for sampling frequencies [Hz]: 8000, 12000, 16000, 24000, 32000, 48000
-// Clock frequency = 786,432,480 Hz
+// Clock frequency = 786,432,000 Hz = 48000 * 64 * 256
STATIC const clock_audio_pll_config_t audioPllConfig_8000_48000 = {
.loopDivider = 32, // PLL loop divider. Valid range for DIV_SELECT divider value: 27~54
.postDivider = 1, // Divider after the PLL, should only be 1, 2, 4, 8, 16
- .numerator = 76802, // 30 bit numerator of fractional loop divider
+ .numerator = 76800, // 30 bit numerator of fractional loop divider
.denominator = 100000, // 30 bit denominator of fractional loop divider
+ #if !defined(MIMXRT117x_SERIES)
.src = kCLOCK_PllClkSrc24M // Pll clock source
+ #endif
};
// Configuration 2: for sampling frequencies [Hz]: 11025, 22050, 44100
-// Clock frequency = 722,534,880
+// Clock frequency = 722,534,400 = 44100 * 64 * 256
STATIC const clock_audio_pll_config_t audioPllConfig_11025_44100 = {
.loopDivider = 30, // PLL loop divider. Valid range for DIV_SELECT divider value: 27~54
.postDivider = 1, // Divider after the PLL, should only be 1, 2, 4, 8, 16
- .numerator = 10562, // 30 bit numerator of fractional loop divider
+ .numerator = 10560, // 30 bit numerator of fractional loop divider
.denominator = 100000, // 30 bit denominator of fractional loop divider
+ #if !defined(MIMXRT117x_SERIES)
.src = kCLOCK_PllClkSrc24M // Pll clock source
+ #endif
};
+#if defined(MIMXRT117x_SERIES)
+// for 1176 the pre_div value is used for post_div of the Audio PLL,
+// which is 2**n: 0->1, 1->2, 2->4, 3->8, 4->16, 5->32
+// The divider is 8 bit and must be given as n (not n-1)
+// So the total division factor is given by (2**p) * d
STATIC const i2s_clock_config_t clock_config_map[] = {
- {kSAI_SampleRate8KHz, &audioPllConfig_8000_48000, 5, 63},
- {kSAI_SampleRate11025Hz, &audioPllConfig_11025_44100, 3, 63},
- {kSAI_SampleRate12KHz, &audioPllConfig_8000_48000, 3, 63},
- {kSAI_SampleRate16KHz, &audioPllConfig_8000_48000, 2, 63},
- {kSAI_SampleRate22050Hz, &audioPllConfig_11025_44100, 1, 63},
- {kSAI_SampleRate24KHz, &audioPllConfig_8000_48000, 1, 63},
- {kSAI_SampleRate32KHz, &audioPllConfig_8000_48000, 1, 47},
- {kSAI_SampleRate44100Hz, &audioPllConfig_11025_44100, 0, 63},
- {kSAI_SampleRate48KHz, &audioPllConfig_8000_48000, 0, 63}
+ {kSAI_SampleRate8KHz, &audioPllConfig_8000_48000, 1, 192}, // 384
+ {kSAI_SampleRate11025Hz, &audioPllConfig_11025_44100, 1, 128}, // 256
+ {kSAI_SampleRate12KHz, &audioPllConfig_8000_48000, 1, 128}, // 256
+ {kSAI_SampleRate16KHz, &audioPllConfig_8000_48000, 0, 192}, // 192
+ {kSAI_SampleRate22050Hz, &audioPllConfig_11025_44100, 0, 128}, // 128
+ {kSAI_SampleRate24KHz, &audioPllConfig_8000_48000, 0, 128}, // 128
+ {kSAI_SampleRate32KHz, &audioPllConfig_8000_48000, 0, 96}, // 96
+ {kSAI_SampleRate44100Hz, &audioPllConfig_11025_44100, 0, 64}, // 64
+ {kSAI_SampleRate48KHz, &audioPllConfig_8000_48000, 0, 64} // 64
+};
+
+STATIC const clock_root_t i2s_clock_mux[] = I2S_CLOCK_MUX;
+#else
+// for 10xx the total division factor is given by (p + 1) * (d + 1)
+STATIC const i2s_clock_config_t clock_config_map[] = {
+ {kSAI_SampleRate8KHz, &audioPllConfig_8000_48000, 5, 63}, // 384
+ {kSAI_SampleRate11025Hz, &audioPllConfig_11025_44100, 3, 63}, // 256
+ {kSAI_SampleRate12KHz, &audioPllConfig_8000_48000, 3, 63}, // 256
+ {kSAI_SampleRate16KHz, &audioPllConfig_8000_48000, 2, 63}, // 192
+ {kSAI_SampleRate22050Hz, &audioPllConfig_11025_44100, 1, 63}, // 128
+ {kSAI_SampleRate24KHz, &audioPllConfig_8000_48000, 1, 63}, // 128
+ {kSAI_SampleRate32KHz, &audioPllConfig_8000_48000, 1, 47}, // 96
+ {kSAI_SampleRate44100Hz, &audioPllConfig_11025_44100, 0, 63}, // 64
+ {kSAI_SampleRate48KHz, &audioPllConfig_8000_48000, 0, 63} // 64
};
-STATIC const I2S_Type *i2s_base_ptr[] = I2S_BASE_PTRS;
STATIC const clock_mux_t i2s_clock_mux[] = I2S_CLOCK_MUX;
STATIC const clock_div_t i2s_clock_pre_div[] = I2S_CLOCK_PRE_DIV;
STATIC const clock_div_t i2s_clock_div[] = I2S_CLOCK_DIV;
STATIC const iomuxc_gpr_mode_t i2s_iomuxc_gpr_mode[] = I2S_IOMUXC_GPR_MODE;
+#endif
+
+STATIC const I2S_Type *i2s_base_ptr[] = I2S_BASE_PTRS;
+
STATIC const dma_request_source_t i2s_dma_req_src_tx[] = I2S_DMA_REQ_SRC_TX;
STATIC const dma_request_source_t i2s_dma_req_src_rx[] = I2S_DMA_REQ_SRC_RX;
STATIC const gpio_map_t i2s_gpio_map[] = I2S_GPIO_MAP;
@@ -415,7 +441,7 @@ STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info
// copy audio samples from the ring buffer to the app buffer
// loop, copying samples until the app buffer is filled
- // For uasyncio mode, the loop will make an early exit if the ring buffer becomes empty
+ // For asyncio mode, the loop will make an early exit if the ring buffer becomes empty
// Example:
// a MicroPython I2S object is configured for 16-bit mono (2 bytes per audio sample).
// For every frame coming from the ring buffer (8 bytes), 2 bytes are "cherry picked" and
@@ -441,7 +467,7 @@ STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info
;
}
num_bytes_copied_to_appbuf++;
- } else if (self->io_mode == UASYNCIO) {
+ } else if (self->io_mode == ASYNCIO) {
if (ringbuf_pop(&self->ring_buffer, app_p + r_to_a_mapping) == false) {
// ring buffer is empty, exit
goto exit;
@@ -458,7 +484,7 @@ STATIC uint32_t fill_appbuf_from_ringbuf(machine_i2s_obj_t *self, mp_buffer_info
while (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
;
}
- } else if (self->io_mode == UASYNCIO) {
+ } else if (self->io_mode == ASYNCIO) {
if (ringbuf_pop(&self->ring_buffer, &discard_byte) == false) {
// ring buffer is empty, exit
goto exit;
@@ -521,7 +547,7 @@ STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t
// copy audio samples from the app buffer to the ring buffer
// loop, reading samples until the app buffer is emptied
- // for uasyncio mode, the loop will make an early exit if the ring buffer becomes full
+ // for asyncio mode, the loop will make an early exit if the ring buffer becomes full
uint32_t a_index = 0;
@@ -532,7 +558,7 @@ STATIC uint32_t copy_appbuf_to_ringbuf(machine_i2s_obj_t *self, mp_buffer_info_t
;
}
a_index++;
- } else if (self->io_mode == UASYNCIO) {
+ } else if (self->io_mode == ASYNCIO) {
if (ringbuf_push(&self->ring_buffer, ((uint8_t *)appbuf->buf)[a_index]) == false) {
// ring buffer is full, exit
break;
@@ -674,10 +700,24 @@ STATIC void edma_i2s_callback(edma_handle_t *handle, void *userData, bool transf
STATIC bool i2s_init(machine_i2s_obj_t *self) {
+ #if defined(MIMXRT117x_SERIES)
+ clock_audio_pll_config_t pll_config = *get_pll_config(self->rate);
+ pll_config.postDivider = get_clock_pre_divider(self->rate);
+ CLOCK_InitAudioPll(&pll_config);
+ CLOCK_SetRootClockMux(i2s_clock_mux[self->i2s_id], I2S_AUDIO_PLL_CLOCK);
+ CLOCK_SetRootClockDiv(i2s_clock_mux[self->i2s_id], get_clock_divider(self->rate));
+ uint32_t clock_freq = CLOCK_GetFreq(kCLOCK_AudioPllOut) / get_clock_divider(self->rate);
+
+ #else
+
CLOCK_InitAudioPll(get_pll_config(self->rate));
- CLOCK_SetMux(i2s_clock_mux[self->i2s_id], AUDIO_PLL_CLOCK);
+ CLOCK_SetMux(i2s_clock_mux[self->i2s_id], I2S_AUDIO_PLL_CLOCK);
CLOCK_SetDiv(i2s_clock_pre_div[self->i2s_id], get_clock_pre_divider(self->rate));
CLOCK_SetDiv(i2s_clock_div[self->i2s_id], get_clock_divider(self->rate));
+ uint32_t clock_freq =
+ (CLOCK_GetFreq(kCLOCK_AudioPllClk) / (get_clock_divider(self->rate) + 1U) /
+ (get_clock_pre_divider(self->rate) + 1U));
+ #endif
if (!set_iomux(self->sck, SCK, self->i2s_id)) {
return false;
@@ -695,7 +735,24 @@ STATIC bool i2s_init(machine_i2s_obj_t *self) {
if (!set_iomux(self->mck, MCK, self->i2s_id)) {
return false;
}
+ #if defined(MIMXRT117x_SERIES)
+ switch (self->i2s_id) {
+ case 1:
+ IOMUXC_GPR->GPR0 |= IOMUXC_GPR_GPR0_SAI1_MCLK_DIR_MASK;
+ break;
+ case 2:
+ IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI2_MCLK_DIR_MASK;
+ break;
+ case 3:
+ IOMUXC_GPR->GPR2 |= IOMUXC_GPR_GPR2_SAI3_MCLK_DIR_MASK;
+ break;
+ case 4:
+ IOMUXC_GPR->GPR2 |= IOMUXC_GPR_GPR2_SAI4_MCLK_DIR_MASK;
+ break;
+ }
+ #else
IOMUXC_EnableMode(IOMUXC_GPR, i2s_iomuxc_gpr_mode[self->i2s_id], true);
+ #endif
}
self->dma_channel = allocate_dma_channel();
@@ -743,10 +800,6 @@ STATIC bool i2s_init(machine_i2s_obj_t *self) {
return false; // should never happen
}
- uint32_t clock_freq =
- (CLOCK_GetFreq(kCLOCK_AudioPllClk) / (get_clock_divider(self->rate) + 1U) /
- (get_clock_pre_divider(self->rate) + 1U));
-
SAI_TxSetBitClockRate(self->i2s_inst, clock_freq, self->rate, get_dma_bits(self->mode, self->bits),
SAI_NUM_AUDIO_CHANNELS);
SAI_RxSetBitClockRate(self->i2s_inst, clock_freq, self->rate, get_dma_bits(self->mode, self->bits),
@@ -773,7 +826,7 @@ STATIC bool i2s_init(machine_i2s_obj_t *self) {
memset(self->edmaTcd, 0, sizeof(edma_tcd_t));
- // continuous DMA operation is acheived using the scatter/gather feature, with one TCD linked back to itself
+ // continuous DMA operation is achieved using the scatter/gather feature, with one TCD linked back to itself
EDMA_TcdSetTransferConfig(self->edmaTcd, &transferConfig, self->edmaTcd);
EDMA_TcdEnableInterrupts(self->edmaTcd, kEDMA_MajorInterruptEnable | kEDMA_HalfInterruptEnable);
EDMA_InstallTCD(DMA0, self->dma_channel, self->edmaTcd);
@@ -1132,7 +1185,7 @@ STATIC mp_uint_t machine_i2s_stream_read(mp_obj_t self_in, void *buf_in, mp_uint
self->non_blocking_descriptor.index = 0;
self->non_blocking_descriptor.copy_in_progress = true;
return size;
- } else { // blocking or uasyncio mode
+ } else { // blocking or asyncio mode
mp_buffer_info_t appbuf;
appbuf.buf = (void *)buf_in;
appbuf.len = size;
@@ -1159,7 +1212,7 @@ STATIC mp_uint_t machine_i2s_stream_write(mp_obj_t self_in, const void *buf_in,
self->non_blocking_descriptor.index = 0;
self->non_blocking_descriptor.copy_in_progress = true;
return size;
- } else { // blocking or uasyncio mode
+ } else { // blocking or asyncio mode
mp_buffer_info_t appbuf;
appbuf.buf = (void *)buf_in;
appbuf.len = size;
@@ -1172,7 +1225,7 @@ STATIC mp_uint_t machine_i2s_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
machine_i2s_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;
uintptr_t flags = arg;
- self->io_mode = UASYNCIO; // a call to ioctl() is an indication that uasyncio is being used
+ self->io_mode = ASYNCIO; // a call to ioctl() is an indication that asyncio is being used
if (request == MP_STREAM_POLL) {
ret = 0;
diff --git a/ports/mimxrt/machine_led.c b/ports/mimxrt/machine_led.c
index 8dd74b32ba76..a927c570a253 100644
--- a/ports/mimxrt/machine_led.c
+++ b/ports/mimxrt/machine_led.c
@@ -28,7 +28,7 @@
#include "py/mphal.h"
#include "led.h"
-#if NUM_LEDS
+#if defined(MICROPY_HW_LED1_PIN)
STATIC void led_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
@@ -43,8 +43,8 @@ STATIC mp_obj_t led_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_
mp_int_t led_id = mp_obj_get_int(args[0]);
// Check led id is in range
- if (!(1 <= led_id && led_id <= NUM_LEDS)) {
- mp_raise_msg_varg(&mp_type_ValueError, "LED(%d) doesn't exist", led_id);
+ if (!(1 <= led_id && led_id < MICROPY_HW_LED_MAX)) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("LED(%d) doesn't exist"), led_id);
}
// Return reference to static object
diff --git a/ports/mimxrt/machine_pin.c b/ports/mimxrt/machine_pin.c
index 836bd8524b72..f005e38d697d 100644
--- a/ports/mimxrt/machine_pin.c
+++ b/ports/mimxrt/machine_pin.c
@@ -149,6 +149,16 @@ void GPIO5_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[5], 5, 16);
}
+#if defined(MIMXRT117x_SERIES)
+void GPIO6_Combined_0_15_IRQHandler(void) {
+ call_handler(gpiobases[6], 6, 0);
+}
+
+void GPIO6_Combined_16_31_IRQHandler(void) {
+ call_handler(gpiobases[6], 6, 16);
+}
+#endif
+
// Deinit all pin IRQ handlers.
void machine_pin_irq_deinit(void) {
for (int i = 0; i < ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_objects)); ++i) {
@@ -164,15 +174,17 @@ void machine_pin_irq_deinit(void) {
// Simplified mode setting used by the extmod modules
void machine_pin_set_mode(const machine_pin_obj_t *self, uint8_t mode) {
gpio_pin_config_t pin_config = {kGPIO_DigitalInput, 1, kGPIO_NoIntmode};
+ uint32_t pad_config;
pin_config.direction = (mode == PIN_MODE_IN ? kGPIO_DigitalInput : kGPIO_DigitalOutput);
- GPIO_PinInit(self->gpio, self->pin, &pin_config);
if (mode == PIN_MODE_OPEN_DRAIN) {
- uint32_t pad_config = *(uint32_t *)self->configRegister;
- pad_config |= IOMUXC_SW_PAD_CTL_PAD_ODE(0b1) | IOMUXC_SW_PAD_CTL_PAD_DSE(0b110);
- IOMUXC_SetPinMux(self->muxRegister, PIN_AF_MODE_ALT5, 0, 0, self->configRegister, 1U); // Software Input On Field: Input Path is determined by functionality
- IOMUXC_SetPinConfig(self->muxRegister, PIN_AF_MODE_ALT5, 0, 0, self->configRegister, pad_config);
+ pad_config = pin_generate_config(PIN_PULL_UP_22K, mode, PIN_DRIVE_3, self->configRegister);
+ } else {
+ pad_config = pin_generate_config(PIN_PULL_DISABLED, mode, PIN_DRIVE_3, self->configRegister);
}
+ IOMUXC_SetPinConfig(self->muxRegister, PIN_AF_MODE_ALT5, 0, 0, self->configRegister, pad_config);
+ IOMUXC_SetPinMux(self->muxRegister, PIN_AF_MODE_ALT5, 0, 0, self->configRegister, 1U);
+ GPIO_PinInit(self->gpio, self->pin, &pin_config);
}
STATIC mp_obj_t machine_pin_obj_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
@@ -285,6 +297,14 @@ STATIC mp_obj_t machine_pin_on(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_on_obj, machine_pin_on);
+// pin.toggle()
+STATIC mp_obj_t machine_pin_toggle(mp_obj_t self_in) {
+ machine_pin_obj_t *self = self_in;
+ mp_hal_pin_toggle(self);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle);
+
// pin.value([value])
STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
return machine_pin_obj_call(args[0], (n_args - 1), 0, args + 1);
@@ -366,6 +386,7 @@ STATIC const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_on_obj) },
{ MP_ROM_QSTR(MP_QSTR_low), MP_ROM_PTR(&machine_pin_off_obj) },
{ MP_ROM_QSTR(MP_QSTR_high), MP_ROM_PTR(&machine_pin_on_obj) },
+ { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pin_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) },
diff --git a/ports/mimxrt/machine_pwm.c b/ports/mimxrt/machine_pwm.c
index d5bb029e689e..a50b67cc8ca2 100644
--- a/ports/mimxrt/machine_pwm.c
+++ b/ports/mimxrt/machine_pwm.c
@@ -39,6 +39,7 @@
#define PWM_CHANNEL1 (1)
#define PWM_CHANNEL2 (2)
+#define VALUE_NOT_SET (-1)
typedef struct _machine_pwm_obj_t {
mp_obj_base_t base;
@@ -51,10 +52,10 @@ typedef struct _machine_pwm_obj_t {
uint8_t channel2;
uint8_t invert;
bool sync;
- uint32_t freq;
+ int32_t freq;
int16_t prescale;
- uint16_t duty_u16;
- uint32_t duty_ns;
+ int32_t duty_u16;
+ int32_t duty_ns;
uint16_t center;
uint32_t deadtime;
bool output_enable_1;
@@ -68,7 +69,7 @@ static char *ERRMSG_FREQ = "PWM frequency too low";
static char *ERRMSG_INIT = "PWM set-up failed";
static char *ERRMSG_VALUE = "value larger than period";
-STATIC void machine_pwm_start(machine_pwm_obj_t *self);
+STATIC void mp_machine_pwm_start(machine_pwm_obj_t *self);
STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
@@ -79,31 +80,31 @@ STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_p
} else {
mp_printf(print, "channel=%c", channel_char[self->channel1]);
}
- if (self->duty_ns != 0) {
- mp_printf(print, " duty_ns=%u", self->duty_ns);
+ if (self->duty_ns != VALUE_NOT_SET) {
+ mp_printf(print, " duty_ns=%d", self->duty_ns);
} else {
- mp_printf(print, " duty_u16=%u", self->duty_u16);
+ mp_printf(print, " duty_u16=%d", self->duty_u16);
}
- mp_printf(print, " freq=%u center=%u, deadtime=%u, sync=%u>",
+ mp_printf(print, " freq=%d center=%u, deadtime=%u, sync=%u>",
self->freq, self->center, self->deadtime, self->sync);
#ifdef FSL_FEATURE_SOC_TMR_COUNT
} else {
- mp_printf(print, "module, self->channel1, self->freq);
- if (self->duty_ns != 0) {
- mp_printf(print, "duty_ns=%u>", self->duty_ns);
+ if (self->duty_ns != VALUE_NOT_SET) {
+ mp_printf(print, "duty_ns=%d>", self->duty_ns);
} else {
- mp_printf(print, "duty_u16=%u>", self->duty_u16);
+ mp_printf(print, "duty_u16=%d>", self->duty_u16);
}
#endif
}
}
-// Utility functions for decoding and convertings
+// Utility functions for decoding and converting
//
STATIC uint32_t duty_ns_to_duty_u16(uint32_t freq, uint32_t duty_ns) {
uint64_t duty = (uint64_t)duty_ns * freq * PWM_FULL_SCALE / 1000000000ULL;
- if (duty >= PWM_FULL_SCALE) {
+ if (duty > PWM_FULL_SCALE) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
}
return (uint32_t)duty;
@@ -137,7 +138,7 @@ STATIC uint8_t channel_decode(char channel) {
}
}
-// decode the AF objects module and Port numer. Returns NULL if it is not a FLEXPWM object
+// decode the AF objects module and Port number. Returns NULL if it is not a FLEXPWM object
STATIC const machine_pin_af_obj_t *af_name_decode_flexpwm(const machine_pin_af_obj_t *af_obj,
uint8_t *module, uint8_t *submodule, uint8_t *channel) {
const char *str;
@@ -171,7 +172,7 @@ STATIC uint8_t qtmr_decode(char channel) {
}
}
-// decode the AF objects module and Port numer. Returns NULL if it is not a QTMR object
+// decode the AF objects module and Port number. Returns NULL if it is not a QTMR object
STATIC const machine_pin_af_obj_t *af_name_decode_qtmr(const machine_pin_af_obj_t *af_obj, uint8_t *module, uint8_t *channel) {
const char *str;
size_t len;
@@ -214,7 +215,11 @@ STATIC void configure_flexpwm(machine_pwm_obj_t *self) {
pwm_signal_param_u16_t pwmSignal;
// Initialize PWM module.
+ #if defined(MIMXRT117x_SERIES)
+ uint32_t pwmSourceClockInHz = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus);
+ #else
uint32_t pwmSourceClockInHz = CLOCK_GetFreq(kCLOCK_IpgClk);
+ #endif
int prescale = calc_prescaler(pwmSourceClockInHz, self->freq);
if (prescale < 0) {
@@ -296,10 +301,15 @@ STATIC void configure_flexpwm(machine_pwm_obj_t *self) {
STATIC void configure_qtmr(machine_pwm_obj_t *self) {
qtmr_config_t qtmrConfig;
int prescale;
+ #if defined(MIMXRT117x_SERIES)
+ uint32_t pwmSourceClockInHz = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus);
+ #else
+ uint32_t pwmSourceClockInHz = CLOCK_GetFreq(kCLOCK_IpgClk);
+ #endif
TMR_Type *instance = (TMR_Type *)self->instance;
- prescale = calc_prescaler(CLOCK_GetFreq(kCLOCK_IpgClk), self->freq);
+ prescale = calc_prescaler(pwmSourceClockInHz, self->freq);
if (prescale < 0) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ));
}
@@ -311,7 +321,7 @@ STATIC void configure_qtmr(machine_pwm_obj_t *self) {
}
// Set up the PWM channel
if (QTMR_SetupPwm_u16(instance, self->channel1, self->freq, self->duty_u16,
- self->invert, CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << prescale), self->is_init) == kStatus_Fail) {
+ self->invert, pwmSourceClockInHz / (1 << prescale), self->is_init) == kStatus_Fail) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT));
}
// Start the output
@@ -325,19 +335,24 @@ STATIC void configure_pwm(machine_pwm_obj_t *self) {
static bool set_frequency = true;
// set the frequency only once
if (set_frequency) {
+ #if !defined(MIMXRT117x_SERIES)
CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); // Set IPG PODF to 3, divide by 4
+ #endif
set_frequency = false;
}
- if (self->duty_ns != 0) {
- self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
- }
- if (self->is_flexpwm) {
- configure_flexpwm(self);
- #ifdef FSL_FEATURE_SOC_TMR_COUNT
- } else {
- configure_qtmr(self);
- #endif
+ // Enable the PWM only if both freq and duty value are set
+ if (self->freq != VALUE_NOT_SET && (self->duty_u16 != VALUE_NOT_SET || self->duty_ns != VALUE_NOT_SET)) {
+ if (self->duty_ns != VALUE_NOT_SET) {
+ self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ }
+ if (self->is_flexpwm) {
+ configure_flexpwm(self);
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ } else {
+ configure_qtmr(self);
+ #endif
+ }
}
}
@@ -348,9 +363,9 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
enum { ARG_freq, ARG_duty_u16, ARG_duty_ns, ARG_center, ARG_align,
ARG_invert, ARG_sync, ARG_xor, ARG_deadtime };
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_freq, MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_freq, MP_ARG_INT, {.u_int = VALUE_NOT_SET} },
+ { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = VALUE_NOT_SET} },
+ { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = VALUE_NOT_SET} },
{ MP_QSTR_center, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_align, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
{ MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
@@ -369,24 +384,24 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
}
// Set duty_u16 cycle?
- uint32_t duty = args[ARG_duty_u16].u_int;
- if (duty != 0) {
- if (duty >= PWM_FULL_SCALE) {
+ int32_t duty = args[ARG_duty_u16].u_int;
+ if (duty >= 0) {
+ if (duty > PWM_FULL_SCALE) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
}
self->duty_u16 = duty;
- self->duty_ns = 0;
+ self->duty_ns = VALUE_NOT_SET;
}
// Set duty_ns value?
duty = args[ARG_duty_ns].u_int;
- if (duty != 0) {
+ if (duty >= 0) {
self->duty_ns = duty;
- self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ self->duty_u16 = VALUE_NOT_SET;
}
// Set center value?
int32_t center = args[ARG_center].u_int;
if (center >= 0) {
- if (center >= PWM_FULL_SCALE) {
+ if (center > PWM_FULL_SCALE) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
}
self->center = center;
@@ -421,7 +436,7 @@ STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
configure_pwm(self);
self->is_init = true;
} else {
- machine_pwm_start(self);
+ mp_machine_pwm_start(self);
}
}
@@ -468,6 +483,9 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
break;
}
}
+ if (af_obj2 == NULL) {
+ mp_raise_ValueError(MP_ERROR_TEXT("the second Pin doesn't support PWM"));
+ }
}
if (af_obj1 == NULL) {
submodule1 = 0;
@@ -483,12 +501,12 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
}
#endif
if (af_obj1 == NULL) {
- mp_raise_ValueError(MP_ERROR_TEXT("the requested Pin(s) does not support PWM"));
+ mp_raise_ValueError(MP_ERROR_TEXT("the first Pin doesn't support PWM"));
}
} else {
// is flexpwm, check for instance match
is_flexpwm = true;
- if (pin2 != NULL && af_obj1->instance != af_obj2->instance && submodule1 != submodule2) {
+ if (pin2 != NULL && (af_obj1->instance != af_obj2->instance || submodule1 != submodule2)) {
mp_raise_ValueError(MP_ERROR_TEXT("the pins must be a A/B pair of a submodule"));
}
}
@@ -501,10 +519,10 @@ STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args
self->submodule = submodule1;
self->channel1 = channel1;
self->invert = 0;
- self->freq = 1000;
+ self->freq = VALUE_NOT_SET;
self->prescale = -1;
- self->duty_u16 = 32768;
- self->duty_ns = 0;
+ self->duty_u16 = VALUE_NOT_SET;
+ self->duty_ns = VALUE_NOT_SET;
self->center = 32768;
self->output_enable_1 = is_board_pin(pin1);
self->sync = false;
@@ -547,7 +565,7 @@ void machine_pwm_deinit_all(void) {
for (int i = 1; i < ARRAY_SIZE(pwm_bases); i++) {
PWM_StopTimer(pwm_bases[i], 0x0f); // Stop all submodules
- pwm_bases[i]->OUTEN = 0; // Disable ouput on all submodules, all channels
+ pwm_bases[i]->OUTEN = 0; // Disable output on all submodules, all channels
}
#ifdef FSL_FEATURE_SOC_TMR_COUNT
@@ -560,7 +578,7 @@ void machine_pwm_deinit_all(void) {
#endif
}
-STATIC void machine_pwm_start(machine_pwm_obj_t *self) {
+STATIC void mp_machine_pwm_start(machine_pwm_obj_t *self) {
if (self->is_flexpwm) {
PWM_StartTimer(self->instance, 1 << self->submodule);
#ifdef FSL_FEATURE_SOC_TMR_COUNT
@@ -595,23 +613,23 @@ mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty) {
if (duty >= 0) {
- if (duty >= PWM_FULL_SCALE) {
+ if (duty > PWM_FULL_SCALE) {
mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
}
self->duty_u16 = duty;
- self->duty_ns = 0;
+ self->duty_ns = VALUE_NOT_SET;
configure_pwm(self);
}
}
mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
- return MP_OBJ_NEW_SMALL_INT(1000000000ULL / self->freq * self->duty_u16 / PWM_FULL_SCALE);
+ return MP_OBJ_NEW_SMALL_INT(self->duty_ns);
}
void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty) {
if (duty >= 0) {
self->duty_ns = duty;
- self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ self->duty_u16 = VALUE_NOT_SET;
configure_pwm(self);
}
}
diff --git a/ports/mimxrt/machine_rtc.c b/ports/mimxrt/machine_rtc.c
index da7a437491f7..702c1b903e50 100644
--- a/ports/mimxrt/machine_rtc.c
+++ b/ports/mimxrt/machine_rtc.c
@@ -38,7 +38,6 @@ typedef struct _machine_rtc_obj_t {
// Singleton RTC object.
STATIC const machine_rtc_obj_t machine_rtc_obj = {{&machine_rtc_type}};
-uint32_t us_offset = 0;
// Start the RTC Timer.
void machine_rtc_start(void) {
@@ -83,7 +82,7 @@ STATIC mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args)
mp_obj_new_int(srtc_date.hour),
mp_obj_new_int(srtc_date.minute),
mp_obj_new_int(srtc_date.second),
- mp_obj_new_int((ticks_us64() + us_offset) % 1000000),
+ mp_obj_new_int(0),
};
return mp_obj_new_tuple(8, tuple);
} else {
@@ -104,7 +103,6 @@ STATIC mp_obj_t machine_rtc_datetime_helper(size_t n_args, const mp_obj_t *args)
if (SNVS_LP_SRTC_SetDatetime(SNVS, &srtc_date) != kStatus_Success) {
mp_raise_ValueError(NULL);
}
- us_offset = (1000000 + mp_obj_get_int(items[7]) - ticks_us64() % 1000000) % 1000000;
return mp_const_none;
}
@@ -127,7 +125,7 @@ STATIC mp_obj_t machine_rtc_now(mp_obj_t self_in) {
mp_obj_new_int(srtc_date.hour),
mp_obj_new_int(srtc_date.minute),
mp_obj_new_int(srtc_date.second),
- mp_obj_new_int((ticks_us64() + us_offset) % 1000000),
+ mp_obj_new_int(0),
mp_const_none,
};
return mp_obj_new_tuple(8, tuple);
diff --git a/ports/mimxrt/machine_sdcard.c b/ports/mimxrt/machine_sdcard.c
index 9254faf14a44..496eb9353388 100644
--- a/ports/mimxrt/machine_sdcard.c
+++ b/ports/mimxrt/machine_sdcard.c
@@ -30,7 +30,12 @@
#include "py/mperrno.h"
#include "extmod/vfs.h"
#include "ticks.h"
+
+#if defined(MIMXRT1170x_SERIES)
+#include "cm7/fsl_cache.h"
+#else
#include "fsl_cache.h"
+#endif
#include "sdcard.h"
@@ -62,7 +67,7 @@ STATIC mp_obj_t sdcard_obj_make_new(const mp_obj_type_t *type, size_t n_args, si
mp_int_t sdcard_id = args[SDCARD_INIT_ARG_ID].u_int;
if (!(1 <= sdcard_id && sdcard_id <= MP_ARRAY_SIZE(mimxrt_sdcard_objs))) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SDCard(%d) doesn't exist", sdcard_id));
+ nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SDCard(%d) doesn't exist"), sdcard_id));
}
mimxrt_sdcard_obj_t *self = &mimxrt_sdcard_objs[(sdcard_id - 1)];
diff --git a/ports/mimxrt/machine_spi.c b/ports/mimxrt/machine_spi.c
index a3a6bb414edd..bafe94b970fb 100644
--- a/ports/mimxrt/machine_spi.c
+++ b/ports/mimxrt/machine_spi.c
@@ -45,6 +45,14 @@
#define DEFAULT_SPI_FIRSTBIT (kLPSPI_MsbFirst)
#define DEFAULT_SPI_DRIVE (6)
+#define CLOCK_DIVIDER (1)
+
+#if defined(MIMXRT117x_SERIES)
+#define LPSPI_DMAMUX DMAMUX0
+#else
+#define LPSPI_DMAMUX DMAMUX
+#endif
+
#define MICROPY_HW_SPI_NUM MP_ARRAY_SIZE(spi_index_table)
#define SCK (iomux_table[index])
@@ -232,17 +240,19 @@ STATIC void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj
STATIC void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
- // Wait a short while for the previous transfer to finish, but not forever
- for (volatile int j = 0; (j < 5000) && ((self->spi_inst->SR & kLPSPI_ModuleBusyFlag) != 0); j++) {}
+ if (len > 0) {
+ // Wait a short while for the previous transfer to finish, but not forever
+ for (volatile int j = 0; (j < 5000) && ((self->spi_inst->SR & kLPSPI_ModuleBusyFlag) != 0); j++) {}
- lpspi_transfer_t masterXfer;
- masterXfer.txData = (uint8_t *)src;
- masterXfer.rxData = (uint8_t *)dest;
- masterXfer.dataSize = len;
- masterXfer.configFlags = (self->master_config->whichPcs << LPSPI_MASTER_PCS_SHIFT) | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
+ lpspi_transfer_t masterXfer;
+ masterXfer.txData = (uint8_t *)src;
+ masterXfer.rxData = (uint8_t *)dest;
+ masterXfer.dataSize = len;
+ masterXfer.configFlags = (self->master_config->whichPcs << LPSPI_MASTER_PCS_SHIFT) | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
- if (LPSPI_MasterTransferBlocking(self->spi_inst, &masterXfer) != kStatus_Success) {
- mp_raise_OSError(EIO);
+ if (LPSPI_MasterTransferBlocking(self->spi_inst, &masterXfer) != kStatus_Success) {
+ mp_raise_OSError(EIO);
+ }
}
}
diff --git a/ports/mimxrt/machine_timer.c b/ports/mimxrt/machine_timer.c
deleted file mode 100644
index a237272390ce..000000000000
--- a/ports/mimxrt/machine_timer.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2020-2021 Damien P. George
- * Copyright (c) 2021 Robert Hammelrath
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/runtime.h"
-#include "py/mperrno.h"
-#include "py/mphal.h"
-#include "fsl_pit.h"
-#include "modmachine.h"
-#include CLOCK_CONFIG_H
-
-#define TIMER_MODE_ONE_SHOT (0)
-#define TIMER_MODE_PERIODIC (1)
-#define TIMER_MIN_PERIOD 1
-
-#define alarm_callback PIT_IRQHandler
-#define PIT_IRQ_ID PIT_IRQn
-
-typedef struct _machine_timer_obj_t {
- mp_obj_base_t base;
- int8_t id;
- int8_t channel;
- uint32_t mode;
- uint32_t tick_hz;
- uint32_t delta_us; // for periodic mode
- mp_obj_t callback;
-} machine_timer_obj_t;
-
-static const int8_t channel_no[MICROPY_HW_PIT_NUM_CHANNELS] = {0, 2, 3}; // no channel 1
-static pit_config_t pit_config;
-
-// This is the interrupt handler
-// To tell which channel fired one has to poll the flags
-void alarm_callback(void) {
- for (uint8_t index = 0; index < MICROPY_HW_PIT_NUM_CHANNELS; index++) {
- uint32_t flag;
- machine_timer_obj_t *self = MP_STATE_PORT(timer_table)[index];
- if (self != NULL) {
- flag = PIT_GetStatusFlags(PIT, self->channel);
- if (flag & kPIT_TimerFlag) { // channel fired
- PIT_ClearStatusFlags(PIT, self->channel, kPIT_TimerFlag);
- __DSB();
-
- mp_sched_schedule(self->callback, MP_OBJ_FROM_PTR(self));
-
- if (self->mode == TIMER_MODE_ONE_SHOT) {
- PIT_StopTimer(PIT, self->channel);
- }
- }
- }
- }
-}
-
-STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
- qstr mode = self->mode == TIMER_MODE_ONE_SHOT ? MP_QSTR_ONE_SHOT : MP_QSTR_PERIODIC;
- mp_printf(print, "Timer(channel=%d, mode=%q, period=%d, tick_hz=%d)",
- self->id, mode, self->delta_us / self->tick_hz, self->tick_hz);
-}
-
-STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_mode, ARG_callback, ARG_period, ARG_tick_hz, ARG_freq, };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIMER_MODE_PERIODIC} },
- { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
- { MP_QSTR_tick_hz, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1000} },
- { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
- };
-
- // Parse args
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- self->mode = args[ARG_mode].u_int;
- if (args[ARG_freq].u_obj != mp_const_none) {
- // Frequency specified in Hz
- #if MICROPY_PY_BUILTINS_FLOAT
- self->delta_us = (uint32_t)(MICROPY_FLOAT_CONST(1000000.0) / mp_obj_get_float(args[ARG_freq].u_obj));
- #else
- self->delta_us = 1000000 / mp_obj_get_int(args[ARG_freq].u_obj);
- #endif
- } else {
- // Period specified
- self->tick_hz = args[ARG_tick_hz].u_int;
- self->delta_us = (uint64_t)args[ARG_period].u_int * 1000000 / self->tick_hz;
- }
- if (self->delta_us < TIMER_MIN_PERIOD) {
- self->delta_us = TIMER_MIN_PERIOD;
- }
-
- self->callback = args[ARG_callback].u_obj;
-
- // Set timer period for channel id
- PIT_SetTimerPeriod(PIT, self->channel, USEC_TO_COUNT(self->delta_us, BOARD_BOOTCLOCKRUN_IPG_CLK_ROOT));
-
- // Enable timer interrupts for the channel
- PIT_EnableInterrupts(PIT, self->channel, kPIT_TimerInterruptEnable);
-
- // Enable at the NVIC
- EnableIRQ(PIT_IRQ_ID);
-
- // Start channel 0
- PIT_StartTimer(PIT, self->channel);
-
- return mp_const_none;
-}
-
-STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
- machine_timer_obj_t *self;
-
- // Get timer id in the range of 0..2
- mp_int_t id = 0;
- if (n_args > 0) {
- id = mp_obj_get_int(args[0]);
- --n_args;
- ++args;
- }
- if (id < 0 || id >= MICROPY_HW_PIT_NUM_CHANNELS) {
- mp_raise_ValueError(MP_ERROR_TEXT("Timer does not exist"));
- }
-
- // check, if a timer exists at that channel and stop it first
- if (MP_STATE_PORT(timer_table)[id] != NULL) {
- PIT_StopTimer(PIT, channel_no[id]);
- self = MP_STATE_PORT(timer_table)[id];
- } else {
- self = m_new_obj_with_finaliser(machine_timer_obj_t);
- self->base.type = &machine_timer_type;
- MP_STATE_PORT(timer_table)[id] = self;
- }
-
- // Set initial values
- self->id = id;
- self->channel = channel_no[id];
-
- if (n_args > 0 || n_kw > 0) {
- // Start the timer
- mp_map_t kw_args;
- mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
- machine_timer_init_helper(self, n_args, args, &kw_args);
- }
-
- return MP_OBJ_FROM_PTR(self);
-}
-
-STATIC mp_obj_t machine_timer___del__(mp_obj_t self_in) {
- machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
- PIT_StopTimer(PIT, self->channel);
- MP_STATE_PORT(timer_table)[self->id] = NULL;
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer___del___obj, machine_timer___del__);
-
-STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
- machine_timer_obj_t *self = MP_OBJ_TO_PTR(args[0]);
- PIT_StopTimer(PIT, self->channel);
- return machine_timer_init_helper(self, n_args - 1, args + 1, kw_args);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
-
-STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
- machine_timer_obj_t *self = MP_OBJ_TO_PTR(self_in);
- PIT_StopTimer(PIT, self->channel);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
-
-// Initialize clock an first config
-void machine_timer_init_PIT(void) {
- // PIT timer
- // Enable clock gate for GPIO1
- CLOCK_EnableClock(kCLOCK_Gpio1); // ?
- // Set PERCLK_CLK divider to 1
- CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U);
-
- PIT_GetDefaultConfig(&pit_config);
- PIT_Init(PIT, &pit_config);
-}
-
-STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer___del___obj) },
- { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },
- { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(TIMER_MODE_ONE_SHOT) },
- { MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(TIMER_MODE_PERIODIC) },
-};
-STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
-
-MP_DEFINE_CONST_OBJ_TYPE(
- machine_timer_type,
- MP_QSTR_Timer,
- MP_TYPE_FLAG_NONE,
- make_new, machine_timer_make_new,
- print, machine_timer_print,
- locals_dict, &machine_timer_locals_dict
- );
-
-MP_REGISTER_ROOT_POINTER(struct _machine_timer_obj_t *timer_table[MICROPY_HW_PIT_NUM_CHANNELS]);
diff --git a/ports/mimxrt/machine_uart.c b/ports/mimxrt/machine_uart.c
index a0706c8f4fca..ac9351da8a30 100644
--- a/ports/mimxrt/machine_uart.c
+++ b/ports/mimxrt/machine_uart.c
@@ -33,6 +33,7 @@
#include "fsl_lpuart.h"
#include "fsl_iomuxc.h"
#include CLOCK_CONFIG_H
+#include "pin.h"
#define DEFAULT_UART_BAUDRATE (115200)
#define DEFAULT_BUFFER_SIZE (256)
@@ -221,7 +222,7 @@ STATIC mp_obj_t machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args
self->timeout_char = min_timeout_char;
}
- LPUART_Init(self->lpuart, &self->config, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT); // ??
+ LPUART_Init(self->lpuart, &self->config, BOARD_BOOTCLOCKRUN_UART_CLK_ROOT);
LPUART_TransferCreateHandle(self->lpuart, &self->handle, LPUART_UserCallback, self);
uint8_t *buffer = m_new(uint8_t, rxbuf_len + 1);
LPUART_TransferStartRingBuffer(self->lpuart, &self->handle, buffer, rxbuf_len);
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index 82e07868a1d4..9ac46e4814d5 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -33,6 +33,7 @@
#include "shared/readline/readline.h"
#include "shared/runtime/gchelper.h"
#include "shared/runtime/pyexec.h"
+#include "shared/runtime/softtimer.h"
#include "ticks.h"
#include "tusb.h"
#include "led.h"
@@ -54,12 +55,8 @@ int main(void) {
board_init();
ticks_init();
tusb_init();
- led_init();
pendsv_init();
- mp_stack_set_top(&_estack);
- mp_stack_set_limit(&_estack - &_sstack - 1024);
-
#if MICROPY_PY_LWIP
// lwIP doesn't allow to reinitialise itself by subsequent calls to this function
// because the system timeout list (next_timeout) is only ever reset by BSS clearing.
@@ -68,10 +65,18 @@ int main(void) {
#if LWIP_MDNS_RESPONDER
mdns_resp_init();
#endif
+
systick_enable_dispatch(SYSTICK_DISPATCH_LWIP, mod_network_lwip_poll_wrapper);
#endif
for (;;) {
+ #if defined(MICROPY_HW_LED1)
+ led_init();
+ #endif
+
+ mp_stack_set_top(&_estack);
+ mp_stack_set_limit(&_estack - &_sstack - 1024);
+
gc_init(&_gc_heap_start, &_gc_heap_end);
mp_init();
@@ -83,7 +88,7 @@ int main(void) {
readline_init0();
// Execute _boot.py to set up the filesystem.
- pyexec_frozen_module("_boot.py");
+ pyexec_frozen_module("_boot.py", false);
// Execute user scripts.
int ret = pyexec_file_if_exists("boot.py");
@@ -120,6 +125,7 @@ int main(void) {
mod_network_deinit();
#endif
machine_pwm_deinit_all();
+ soft_timer_deinit();
gc_sweep_all();
mp_deinit();
}
@@ -145,50 +151,3 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
}
}
#endif
-
-const char mimxrt_help_text[] =
- "Welcome to MicroPython!\n"
- "\n"
- "For online help please visit https://micropython.org/help/.\n"
- "\n"
- "For access to the hardware use the 'machine' module. \n"
- "\n"
- "Quick overview of some objects:\n"
- " machine.Pin(pin) -- get a pin, eg machine.Pin(0)\n"
- " machine.Pin(pin, m, [p]) -- get a pin and configure it for IO mode m, pull mode p\n"
- " methods: init(..), value([v]), high(), low())\n"
- "\n"
- " Pins are numbered board specific, either 0-n, or 'D0'-'Dn', or 'A0' - 'An',\n"
- " according to the boards's pinout sheet.\n"
- " Pin IO modes are: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN\n"
- " Pin pull modes are: Pin.PULL_UP, Pin.PULL_UP_47K, Pin.PULL_UP_22K, Pin.PULL_DOWN, Pin.PULL_HOLD\n"
- " machine.ADC(pin) -- make an analog object from a pin\n"
- " methods: read_u16()\n"
- " machine.UART(id, baudrate=115200) -- create an UART object (id=1 - 8, board-specific)\n"
- " methods: init(), write(buf), any()\n"
- " buf=read(n), readinto(buf), buf=readline()\n"
- " The RX and TX pins are fixed and board-specific.\n"
- " machine.SoftI2C() -- create a Soft I2C object\n"
- " machine.I2C(id) -- create a HW I2C object\n"
- " methods: readfrom(addr, buf, stop=True), writeto(addr, buf, stop=True)\n"
- " readfrom_mem(addr, memaddr, arg), writeto_mem(addr, memaddr, arg)\n"
- " SoftI2C allows to use any pin for sda and scl, HW I2C id's and pins are fixed\n"
- " machine.SoftSPI(baudrate=1000000) -- create a Soft SPI object\n"
- " machine.SPI(id, baudrate=1000000) -- create a HW SPI object\n"
- " methods: read(nbytes, write=0x00), write(buf), write_readinto(wr_buf, rd_buf)\n"
- " SoftSPI allows to use any pin for SPI, HW SPI id's and pins are fixed\n"
- " machine.Timer(id, freq, callback) -- create a hardware timer object (id=0,1,2)\n"
- " eg: machine.Timer(freq=1, callback=lambda t:print(t))\n"
- " machine.RTC() -- create a Real Time Clock object\n"
- " methods: init(), datetime([dateime_tuple]), now()\n"
- " machine.PWM(pin, freq, duty_u16[, kw_opts]) -- create a PWM object\n"
- " methods: init(), duty_u16([value]), duty_ns([value]), freq([value])\n"
- "\n"
- "Useful control commands:\n"
- " CTRL-C -- interrupt a running program\n"
- " CTRL-D -- on a blank line, do a soft reset of the board\n"
- " CTRL-E -- on a blank line, enter paste mode\n"
- "\n"
- "For further help on a specific object, type help(obj)\n"
- "For a list of available modules, type help('modules')\n"
-;
diff --git a/ports/mimxrt/mbedtls/mbedtls_config.h b/ports/mimxrt/mbedtls/mbedtls_config.h
index 8e054ed51713..4140bb514555 100644
--- a/ports/mimxrt/mbedtls/mbedtls_config.h
+++ b/ports/mimxrt/mbedtls/mbedtls_config.h
@@ -26,74 +26,10 @@
#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_H
#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H
-// Set mbedtls configuration
-#define MBEDTLS_PLATFORM_MEMORY
-#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
-#define MBEDTLS_DEPRECATED_REMOVED
-#define MBEDTLS_ENTROPY_HARDWARE_ALT
-#define MBEDTLS_AES_ROM_TABLES
-#define MBEDTLS_CIPHER_MODE_CBC
-#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
-#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
-#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
-#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
-#define MBEDTLS_ECP_DP_BP256R1_ENABLED
-#define MBEDTLS_ECP_DP_BP384R1_ENABLED
-#define MBEDTLS_ECP_DP_BP512R1_ENABLED
-#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
-#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
-#define MBEDTLS_NO_PLATFORM_ENTROPY
-#define MBEDTLS_PKCS1_V15
-#define MBEDTLS_SHA256_SMALLER
-#define MBEDTLS_SSL_PROTO_TLS1
-#define MBEDTLS_SSL_PROTO_TLS1_1
-#define MBEDTLS_SSL_PROTO_TLS1_2
-#define MBEDTLS_SSL_SERVER_NAME_INDICATION
+// Set MicroPython-specific options.
+#define MICROPY_MBEDTLS_CONFIG_BARE_METAL (1)
-// Use a smaller output buffer to reduce size of SSL context
-#define MBEDTLS_SSL_MAX_CONTENT_LEN (16384)
-#define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN)
-#define MBEDTLS_SSL_OUT_CONTENT_LEN (4096)
-
-// Enable mbedtls modules
-#define MBEDTLS_AES_C
-#define MBEDTLS_ASN1_PARSE_C
-#define MBEDTLS_BIGNUM_C
-#define MBEDTLS_CIPHER_C
-#define MBEDTLS_CTR_DRBG_C
-// #define MBEDTLS_ECP_C
-#define MBEDTLS_ENTROPY_C
-#define MBEDTLS_ERROR_C
-#define MBEDTLS_MD_C
-#define MBEDTLS_MD5_C
-#define MBEDTLS_OID_C
-#define MBEDTLS_PKCS5_C
-#define MBEDTLS_PK_C
-#define MBEDTLS_PK_PARSE_C
-#define MBEDTLS_PLATFORM_C
-#define MBEDTLS_RSA_C
-#define MBEDTLS_SHA1_C
-#define MBEDTLS_SHA256_C
-#define MBEDTLS_SHA512_C
-#define MBEDTLS_SSL_CLI_C
-#define MBEDTLS_SSL_SRV_C
-#define MBEDTLS_SSL_TLS_C
-#define MBEDTLS_X509_CRT_PARSE_C
-#define MBEDTLS_X509_USE_C
-
-// Memory allocation hooks
-#include
-#include
-void *m_tracked_calloc(size_t nmemb, size_t size);
-void m_tracked_free(void *ptr);
-#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc
-#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free
-#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
-
-#include "mbedtls/check_config.h"
+// Include common mbedtls configuration.
+#include "extmod/mbedtls/mbedtls_config_common.h"
#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */
diff --git a/ports/mimxrt/mbedtls/mbedtls_port.c b/ports/mimxrt/mbedtls/mbedtls_port.c
index e2002274b1c4..a9db174726ad 100644
--- a/ports/mimxrt/mbedtls/mbedtls_port.c
+++ b/ports/mimxrt/mbedtls/mbedtls_port.c
@@ -26,14 +26,14 @@
#ifdef MICROPY_SSL_MBEDTLS
-#include "fsl_trng.h"
#include "mbedtls_config.h"
+void trng_random_data(unsigned char *output, size_t len);
int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) {
// assumes that TRNG_Init was called during startup
*olen = len;
- TRNG_GetRandomData(TRNG, output, len);
+ trng_random_data(output, len);
return 0;
}
diff --git a/ports/mimxrt/mimxrt_flash.c b/ports/mimxrt/mimxrt_flash.c
index fd2e7558f9f8..d229367e8106 100644
--- a/ports/mimxrt/mimxrt_flash.c
+++ b/ports/mimxrt/mimxrt_flash.c
@@ -4,7 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020-2021 Damien P. George
- * Copyright (c) 2021 Philipp Ebensberger
+ * Copyright (c) 2021-2023 Philipp Ebensberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,23 +30,9 @@
#include "py/runtime.h"
#include "extmod/vfs.h"
#include "modmimxrt.h"
+#include "flash.h"
#include BOARD_FLASH_OPS_HEADER_H
-#define SECTOR_SIZE_BYTES (qspiflash_config.sectorSize)
-#define PAGE_SIZE_BYTES (qspiflash_config.pageSize)
-
-#ifndef MICROPY_HW_FLASH_STORAGE_BYTES
-#define MICROPY_HW_FLASH_STORAGE_BYTES (((uint32_t)&__vfs_end) - ((uint32_t)&__vfs_start))
-#endif
-
-#ifndef MICROPY_HW_FLASH_STORAGE_BASE
-#define MICROPY_HW_FLASH_STORAGE_BASE (((uint32_t)&__vfs_start) - ((uint32_t)&__flash_start))
-#endif
-
-// Linker symbols
-extern uint8_t __vfs_start;
-extern uint8_t __vfs_end;
-extern uint8_t __flash_start;
extern flexspi_nor_config_t qspiflash_config;
@@ -60,67 +46,11 @@ STATIC mimxrt_flash_obj_t mimxrt_flash_obj = {
.base = { &mimxrt_flash_type }
};
-// flash_erase_block(erase_addr_bytes)
-// erases the sector starting at addr. Sector size according to the flash properties.
-status_t flash_erase_block(uint32_t erase_addr) __attribute__((section(".ram_functions")));
-status_t flash_erase_block(uint32_t erase_addr) {
- status_t status;
- SCB_CleanInvalidateDCache();
- SCB_DisableDCache();
- __disable_irq();
- status = flexspi_nor_flash_erase_sector(FLEXSPI, erase_addr);
- __enable_irq();
- SCB_EnableDCache();
- return status;
-}
-
-// flash_write_block(flash_dest_addr_bytes, data_source, length_bytes)
-// writes length_byte data to the destination address
-// the vfs driver takes care for erasing the sector if required
-status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) __attribute__((section(".ram_functions")));
-status_t flash_write_block(uint32_t dest_addr, const uint8_t *src, uint32_t length) {
- status_t status = 0;
- uint32_t size;
- uint32_t next_addr;
-
- SCB_CleanInvalidateDCache();
- SCB_DisableDCache();
- // write data in chunks not crossing a page boundary
- while (length > 0) {
- next_addr = dest_addr - (dest_addr % PAGE_SIZE_BYTES) + PAGE_SIZE_BYTES; // next page boundary
- size = next_addr - dest_addr; // maximal chunk length
- if (size > length) { // compare against remaining data size
- size = length;
- }
- __disable_irq();
- status = flexspi_nor_flash_page_program(FLEXSPI, dest_addr, (uint32_t *)src, size);
- __enable_irq();
- if (status != kStatus_Success) {
- break;
- }
- length -= size;
- src += size;
- dest_addr += size;
- }
- SCB_EnableDCache();
- return status;
-}
-
STATIC mp_obj_t mimxrt_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
// Check args.
mp_arg_check_num(n_args, n_kw, 0, 0, false);
- // Upload the custom flash configuration
- // This should be performed by the boot ROM but for some reason it is not.
- FLEXSPI_UpdateLUT(FLEXSPI, 0,
- qspiflash_config.memConfig.lookupTable,
- ARRAY_SIZE(qspiflash_config.memConfig.lookupTable));
-
- // Configure FLEXSPI IP FIFO access.
- FLEXSPI->MCR0 &= ~(FLEXSPI_MCR0_ARDFEN_MASK);
- FLEXSPI->MCR0 &= ~(FLEXSPI_MCR0_ATDFEN_MASK);
- FLEXSPI->MCR0 |= FLEXSPI_MCR0_ARDFEN(0);
- FLEXSPI->MCR0 |= FLEXSPI_MCR0_ATDFEN(0);
+ flash_init();
// Update information based on linker symbols.
mimxrt_flash_obj.flash_base = MICROPY_HW_FLASH_STORAGE_BASE;
@@ -142,7 +72,8 @@ STATIC mp_obj_t mimxrt_flash_readblocks(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) {
offset += mp_obj_get_int(args[3]);
}
- memcpy(bufinfo.buf, (uint8_t *)(FlexSPI_AMBA_BASE + self->flash_base + offset), bufinfo.len);
+
+ flash_read_block((self->flash_base + offset), (uint8_t *)bufinfo.buf, (uint32_t)bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mimxrt_flash_readblocks_obj, 3, 4, mimxrt_flash_readblocks);
@@ -161,7 +92,7 @@ STATIC mp_obj_t mimxrt_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
uint32_t offset = mp_obj_get_int(args[1]) * SECTOR_SIZE_BYTES;
if (n_args == 3) {
- status = flash_erase_block(self->flash_base + offset);
+ status = flash_erase_sector(self->flash_base + offset);
if (status != kStatus_Success) {
mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("flash erase command failed with %d"), status);
@@ -199,7 +130,7 @@ STATIC mp_obj_t mimxrt_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t a
return MP_OBJ_NEW_SMALL_INT(SECTOR_SIZE_BYTES);
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
uint32_t offset = mp_obj_get_int(arg_in) * SECTOR_SIZE_BYTES;
- status = flash_erase_block(self->flash_base + offset);
+ status = flash_erase_sector(self->flash_base + offset);
return MP_OBJ_NEW_SMALL_INT(status != kStatus_Success);
}
default:
diff --git a/ports/mimxrt/mimxrt_sdram.c b/ports/mimxrt/mimxrt_sdram.c
index 8c336bb607ef..c6c1776a554c 100644
--- a/ports/mimxrt/mimxrt_sdram.c
+++ b/ports/mimxrt/mimxrt_sdram.c
@@ -29,123 +29,176 @@
#include "modmachine.h"
#include "fsl_semc.h"
#include "fsl_iomuxc.h"
+#include "fsl_clock.h"
// Linker symbols
extern uint8_t __sdram_start;
+#if defined(MIMXRT117x_SERIES)
+// Pull Up, High drive strength
+#define SDRAM_PIN_CONFIG (0x07UL)
+#else
+// Pull up 22K, high slew rate
+#define SDRAM_PIN_CONFIG (0xE1UL)
+#endif
void mimxrt_sdram_init(void) {
+
+ #if !defined(MIMXRT117x_SERIES)
// Set Clocks
CLOCK_InitSysPfd(kCLOCK_Pfd2, 29); // '29' PLL2 PFD2 frequency = 528MHz * 18 / 29 = 327.72MHz (with 528MHz = PLL2 frequency)
CLOCK_SetMux(kCLOCK_SemcAltMux, 0); // '0' PLL2 PFD2 will be selected as alternative clock for SEMC root clock
CLOCK_SetMux(kCLOCK_SemcMux, 1); // '1' SEMC alternative clock will be used as SEMC clock root
CLOCK_SetDiv(kCLOCK_SemcDiv, 1); // '1' divide by 2 -> SEMC clock = 163.86 MHz
+ #endif
// Set Pins
- // Data Pins
+ // Data Pins 0..15
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA00, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA00, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA00, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA01, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA01, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA01, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA02, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA02, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA02, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA03, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA03, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA03, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA04, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA04, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA04, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA05, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA05, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA05, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA06, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA06, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA06, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA07, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA07, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA07, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA08, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA08, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA08, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA09, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA09, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA09, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA10, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA10, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA10, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA11, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA11, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA11, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA12, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA12, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA12, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA13, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA13, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA13, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA14, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA14, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA14, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA15, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA15, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA15, SDRAM_PIN_CONFIG);
// Address Pins
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR00, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR00, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR00, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR01, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR01, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR01, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR02, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR02, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR02, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR03, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR03, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR03, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR04, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR04, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR04, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR05, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR05, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR05, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR06, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR06, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR06, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR07, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR07, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR07, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR08, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR08, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR08, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR09, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR09, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR09, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR10, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR10, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR10, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR11, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR11, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR11, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_ADDR12, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR12, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_ADDR12, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM00, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM00, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM00, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA0, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA0, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA0, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_BA1, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA1, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_BA1, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CAS, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CAS, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CAS, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_RAS, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_RAS, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_RAS, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CLK, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CLK, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CLK, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CKE, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CKE, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CKE, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_WE, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_WE, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_WE, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM01, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM01, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM01, SDRAM_PIN_CONFIG);
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DQS, 1UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DQS, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DQS, SDRAM_PIN_CONFIG);
+
+ #if defined(MIMXRT117x_SERIES)
+ // Data Pins 16..31
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA16, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA16, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA17, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA17, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA18, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA18, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA19, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA19, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA20, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA20, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA21, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA21, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA22, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA22, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA23, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA23, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA24, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA24, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA25, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA25, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA26, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA26, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA27, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA27, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA28, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA28, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA29, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA29, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA30, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA30, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DATA31, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DATA31, SDRAM_PIN_CONFIG);
+
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM02, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM02, SDRAM_PIN_CONFIG);
+ IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_DM03, 0UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_DM03, SDRAM_PIN_CONFIG);
+
+ #endif
// Chip Select Pins
#ifndef MIMXRT_IOMUXC_SEMC_CS0
#error No SEMC CS0 defined!
#endif
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS0, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS0, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS0, SDRAM_PIN_CONFIG);
#ifdef MIMXRT_IOMUXC_SEMC_CS1
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS1, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS1, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS1, SDRAM_PIN_CONFIG);
#endif
#ifdef MIMXRT_IOMUXC_SEMC_CS2
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS2, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS2, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS2, SDRAM_PIN_CONFIG);
#endif
#ifdef MIMXRT_IOMUXC_SEMC_CS3
IOMUXC_SetPinMux(MIMXRT_IOMUXC_SEMC_CS3, 0UL);
- IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS3, 0xE1UL);
+ IOMUXC_SetPinConfig(MIMXRT_IOMUXC_SEMC_CS3, SDRAM_PIN_CONFIG);
#endif
// Configure SEMC
@@ -155,6 +208,36 @@ void mimxrt_sdram_init(void) {
semc_cfg.dqsMode = kSEMC_Loopbackdqspad; // For more accurate timing.
SEMC_Init(SEMC, &semc_cfg);
+ #if defined(MIMXRT117x_SERIES)
+
+ uint32_t clock_freq = CLOCK_GetRootClockFreq(kCLOCK_Root_Semc);
+
+ semc_sdram_config_t sdram_cfg = {
+ .csxPinMux = kSEMC_MUXCSX0,
+ .address = 0x80000000,
+ .memsize_kbytes = (MICROPY_HW_SDRAM_SIZE >> 10),
+ .portSize = kSEMC_PortSize32Bit, // two 16-bit SDRAMs make up 32-bit portsize
+ .burstLen = kSEMC_Sdram_BurstLen8,
+ .columnAddrBitNum = kSEMC_SdramColunm_9bit,
+ .casLatency = kSEMC_LatencyThree,
+ .tPrecharge2Act_Ns = 15, // tRP 15ns
+ .tAct2ReadWrite_Ns = 15, // tRCD 15ns
+ .tRefreshRecovery_Ns = 70, // Use the maximum of the (Trfc , Txsr).
+ .tWriteRecovery_Ns = 2, // tWR 2ns
+ .tCkeOff_Ns = 42, // The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS.
+ .tAct2Prechage_Ns = 40, // tRAS 40ns
+ .tSelfRefRecovery_Ns = 70,
+ .tRefresh2Refresh_Ns = 60,
+ .tAct2Act_Ns = 2, // tRC/tRDD 2ns
+ .tPrescalePeriod_Ns = 160 * (1000000000 / clock_freq),
+ .refreshPeriod_nsPerRow = 64 * 1000000 / 8192, // 64ms/8192
+ .refreshUrgThreshold = sdram_cfg.refreshPeriod_nsPerRow,
+ .refreshBurstLen = 1,
+ .delayChain = 2,
+ };
+
+ #else
+
uint32_t clock_freq = CLOCK_GetFreq(kCLOCK_SemcClk);
semc_sdram_config_t sdram_cfg = {
.csxPinMux = kSEMC_MUXCSX0,
@@ -180,6 +263,8 @@ void mimxrt_sdram_init(void) {
.refreshBurstLen = 1
};
+ #endif
+
(status_t)SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdram_cfg, clock_freq);
}
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index ad4e4a59412e..423a67d6095f 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -26,6 +26,7 @@
*/
#include "py/runtime.h"
+#include "drivers/dht/dht.h"
#include "extmod/machine_bitstream.h"
#include "extmod/machine_mem.h"
#include "extmod/machine_i2c.h"
@@ -36,8 +37,10 @@
#include "led.h"
#include "pin.h"
#include "modmachine.h"
-#include "fsl_clock.h"
#include "fsl_wdog.h"
+#if FSL_FEATURE_BOOT_ROM_HAS_ROMAPI
+#include "fsl_romapi.h"
+#endif
#if MICROPY_PY_MACHINE
@@ -108,8 +111,26 @@ STATIC mp_obj_t machine_enable_irq(mp_obj_t state_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(machine_enable_irq_obj, machine_enable_irq);
+NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
+ #if defined(MICROPY_BOARD_ENTER_BOOTLOADER)
+ // If a board has a custom bootloader, call it first.
+ MICROPY_BOARD_ENTER_BOOTLOADER(n_args, args);
+ #elif FSL_ROM_HAS_RUNBOOTLOADER_API
+ // If not, enter ROM bootloader in serial downloader / USB mode.
+ uint32_t arg = 0xEB110000;
+ ROM_RunBootloader(&arg);
+ #else
+ // No custom bootloader, or run bootloader API, then just reset.
+ WDOG_TriggerSystemSoftwareReset(WDOG1);
+ #endif
+ while (1) {
+ ;
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
+
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
{ MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
@@ -118,7 +139,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
- #if NUM_LEDS
+ #if defined(MICROPY_HW_LED1_PIN)
{ MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&machine_led_type) },
#endif
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
@@ -144,11 +165,13 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
#if MICROPY_PY_MACHINE_BITSTREAM
{ MP_ROM_QSTR(MP_QSTR_bitstream), MP_ROM_PTR(&machine_bitstream_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_time_pulse_us), MP_ROM_PTR(&machine_time_pulse_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
// Reset reasons
{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) },
@@ -162,6 +185,6 @@ const mp_obj_module_t mp_module_machine = {
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_umachine, mp_module_machine);
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
#endif // MICROPY_PY_MACHINE
diff --git a/ports/mimxrt/modmimxrt.c b/ports/mimxrt/modmimxrt.c
index 9dd38ee07f30..4756efc0a27e 100644
--- a/ports/mimxrt/modmimxrt.c
+++ b/ports/mimxrt/modmimxrt.c
@@ -26,14 +26,11 @@
#include "py/mperrno.h"
#include "py/runtime.h"
-#include "drivers/dht/dht.h"
#include "modmimxrt.h"
STATIC const mp_rom_map_elem_t mimxrt_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mimxrt) },
{ MP_ROM_QSTR(MP_QSTR_Flash), MP_ROM_PTR(&mimxrt_flash_type) },
-
- { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mimxrt_module_globals, mimxrt_module_globals_table);
diff --git a/ports/mimxrt/modos.c b/ports/mimxrt/modos.c
new file mode 100644
index 000000000000..ecfc3712d78f
--- /dev/null
+++ b/ports/mimxrt/modos.c
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Damien P. George
+ *
+ * use of the TRNG by
+ * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
+ * Copyright (c) 2019 Artur Pacholec
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#if defined(MIMXRT117x_SERIES)
+#include "fsl_caam.h"
+#else
+#include "fsl_trng.h"
+#endif
+
+static bool initialized = false;
+
+#if defined(MIMXRT117x_SERIES)
+STATIC caam_handle_t caam_handle;
+STATIC caam_rng_state_handle_t caam_state_handle = kCAAM_RngStateHandle0;
+
+#if defined(FSL_FEATURE_HAS_L1CACHE) || defined(__DCACHE_PRESENT)
+AT_NONCACHEABLE_SECTION(static caam_job_ring_interface_t s_jrif0);
+#else
+static caam_job_ring_interface_t s_jrif0;
+#endif
+
+STATIC void trng_start(void) {
+ caam_config_t config;
+
+ if (!initialized) {
+ CAAM_GetDefaultConfig(&config);
+ config.jobRingInterface[0] = &s_jrif0;
+ CAAM_Init(CAAM, &config);
+ initialized = true;
+ }
+}
+
+void trng_random_data(unsigned char *output, size_t len) {
+ trng_start();
+ CAAM_RNG_GetRandomData(CAAM, &caam_handle, caam_state_handle, output, len,
+ kCAAM_RngDataAny, NULL);
+}
+
+#else
+
+STATIC void trng_start(void) {
+ trng_config_t trngConfig;
+
+ if (!initialized) {
+ TRNG_GetDefaultConfig(&trngConfig);
+ trngConfig.sampleMode = kTRNG_SampleModeVonNeumann;
+
+ TRNG_Init(TRNG, &trngConfig);
+ initialized = true;
+ }
+}
+
+void trng_random_data(unsigned char *output, size_t len) {
+ trng_start();
+ TRNG_GetRandomData(TRNG, output, len);
+}
+
+#endif
+
+uint32_t trng_random_u32(void) {
+ uint32_t rngval;
+
+ trng_start();
+ trng_random_data((uint8_t *)&rngval, 4);
+ return rngval;
+}
+
+#if MICROPY_PY_OS_URANDOM
+STATIC mp_obj_t mp_os_urandom(mp_obj_t num) {
+ mp_int_t n = mp_obj_get_int(num);
+ vstr_t vstr;
+ vstr_init_len(&vstr, n);
+
+ trng_start();
+ trng_random_data((uint8_t *)vstr.buf, n);
+
+ return mp_obj_new_bytes_from_vstr(&vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_urandom_obj, mp_os_urandom);
+#endif
+
+#if MICROPY_PY_OS_DUPTERM_NOTIFY
+STATIC mp_obj_t mp_os_dupterm_notify(mp_obj_t obj_in) {
+ (void)obj_in;
+ for (;;) {
+ int c = mp_os_dupterm_rx_chr();
+ if (c < 0) {
+ break;
+ }
+ ringbuf_put(&stdin_ringbuf, c);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_os_dupterm_notify_obj, mp_os_dupterm_notify);
+#endif
diff --git a/ports/mimxrt/modtime.c b/ports/mimxrt/modtime.c
new file mode 100644
index 000000000000..b0c927899f99
--- /dev/null
+++ b/ports/mimxrt/modtime.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019-2023 Damien P. George
+ * Copyright (c) 2020 Jim Mussared
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "shared/timeutils/timeutils.h"
+#include "fsl_snvs_lp.h"
+
+// Return the localtime as an 8-tuple.
+STATIC mp_obj_t mp_time_localtime_get(void) {
+ // Get current date and time.
+ snvs_lp_srtc_datetime_t t;
+ SNVS_LP_SRTC_GetDatetime(SNVS, &t);
+ mp_obj_t tuple[8] = {
+ mp_obj_new_int(t.year),
+ mp_obj_new_int(t.month),
+ mp_obj_new_int(t.day),
+ mp_obj_new_int(t.hour),
+ mp_obj_new_int(t.minute),
+ mp_obj_new_int(t.second),
+ mp_obj_new_int(timeutils_calc_weekday(t.year, t.month, t.day)),
+ mp_obj_new_int(timeutils_year_day(t.year, t.month, t.day)),
+ };
+ return mp_obj_new_tuple(8, tuple);
+}
+
+// Return the number of seconds since the Epoch.
+STATIC mp_obj_t mp_time_time_get(void) {
+ snvs_lp_srtc_datetime_t t;
+ SNVS_LP_SRTC_GetDatetime(SNVS, &t);
+ // EPOCH is 1970 for this port, which leads to the following trouble:
+ // timeutils_seconds_since_epoch() calls timeutils_seconds_since_2000(), and
+ // timeutils_seconds_since_2000() subtracts 2000 from year, but uses
+ // an unsigned number for seconds, That causes an underrun, which is not
+ // fixed by adding the TIMEUTILS_SECONDS_1970_TO_2000.
+ // Masking it to 32 bit for year < 2000 fixes it.
+ return mp_obj_new_int_from_ull(
+ timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second)
+ & (t.year < 2000 ? 0xffffffff : 0xffffffffffff)
+ );
+}
diff --git a/ports/mimxrt/moduos.c b/ports/mimxrt/moduos.c
deleted file mode 100644
index ddb4826db9cf..000000000000
--- a/ports/mimxrt/moduos.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Damien P. George
- *
- * use of the TRNG by
- * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
- * Copyright (c) 2019 Artur Pacholec
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/runtime.h"
-#include "py/mphal.h"
-#include "fsl_trng.h"
-
-static bool initialized = false;
-
-STATIC void trng_start(void) {
- trng_config_t trngConfig;
-
- if (!initialized) {
- TRNG_GetDefaultConfig(&trngConfig);
- trngConfig.sampleMode = kTRNG_SampleModeVonNeumann;
-
- TRNG_Init(TRNG, &trngConfig);
- initialized = true;
- }
-}
-
-uint32_t trng_random_u32(void) {
- uint32_t rngval;
-
- trng_start();
- TRNG_GetRandomData(TRNG, (uint8_t *)&rngval, 4);
- return rngval;
-}
-
-#if MICROPY_PY_UOS_URANDOM
-STATIC mp_obj_t mp_uos_urandom(mp_obj_t num) {
- mp_int_t n = mp_obj_get_int(num);
- vstr_t vstr;
- vstr_init_len(&vstr, n);
-
- trng_start();
- TRNG_GetRandomData(TRNG, vstr.buf, n);
-
- return mp_obj_new_bytes_from_vstr(&vstr);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_urandom_obj, mp_uos_urandom);
-#endif
-
-#if MICROPY_PY_UOS_DUPTERM_NOTIFY
-STATIC mp_obj_t mp_uos_dupterm_notify(mp_obj_t obj_in) {
- (void)obj_in;
- for (;;) {
- int c = mp_uos_dupterm_rx_chr();
- if (c < 0) {
- break;
- }
- ringbuf_put(&stdin_ringbuf, c);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_uos_dupterm_notify_obj, mp_uos_dupterm_notify);
-#endif
diff --git a/ports/mimxrt/modutime.c b/ports/mimxrt/modutime.c
deleted file mode 100644
index b1defff77b29..000000000000
--- a/ports/mimxrt/modutime.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2019 Damien P. George
- * Copyright (c) 2020 Jim Mussared
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/runtime.h"
-#include "shared/timeutils/timeutils.h"
-#include "extmod/utime_mphal.h"
-#include "fsl_snvs_lp.h"
-
-// localtime([secs])
-// Convert a time expressed in seconds since the Epoch into an 8-tuple which
-// contains: (year, month, mday, hour, minute, second, weekday, yearday)
-// If secs is not provided or None, then the current time from the RTC is used.
-STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) {
- if (n_args == 0 || args[0] == mp_const_none) {
- // Get current date and time.
- snvs_lp_srtc_datetime_t t;
- SNVS_LP_SRTC_GetDatetime(SNVS, &t);
- mp_obj_t tuple[8] = {
- mp_obj_new_int(t.year),
- mp_obj_new_int(t.month),
- mp_obj_new_int(t.day),
- mp_obj_new_int(t.hour),
- mp_obj_new_int(t.minute),
- mp_obj_new_int(t.second),
- mp_obj_new_int(timeutils_calc_weekday(t.year, t.month, t.day)),
- mp_obj_new_int(timeutils_year_day(t.year, t.month, t.day)),
- };
- return mp_obj_new_tuple(8, tuple);
- } else {
- // Convert given seconds to tuple.
- mp_int_t seconds = mp_obj_get_int(args[0]);
- timeutils_struct_time_t tm;
- timeutils_seconds_since_epoch_to_struct_time(seconds, &tm);
- mp_obj_t tuple[8] = {
- tuple[0] = mp_obj_new_int(tm.tm_year),
- tuple[1] = mp_obj_new_int(tm.tm_mon),
- tuple[2] = mp_obj_new_int(tm.tm_mday),
- tuple[3] = mp_obj_new_int(tm.tm_hour),
- tuple[4] = mp_obj_new_int(tm.tm_min),
- tuple[5] = mp_obj_new_int(tm.tm_sec),
- tuple[6] = mp_obj_new_int(tm.tm_wday),
- tuple[7] = mp_obj_new_int(tm.tm_yday),
- };
- return mp_obj_new_tuple(8, tuple);
- }
-}
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime);
-
-// mktime()
-// This is inverse function of localtime. It's argument is a full 8-tuple
-// which expresses a time as per localtime. It returns an integer which is
-// the number of seconds since the Epoch.
-STATIC mp_obj_t time_mktime(mp_obj_t tuple) {
- size_t len;
- mp_obj_t *elem;
- mp_obj_get_array(tuple, &len, &elem);
-
- // localtime generates a tuple of len 8. CPython uses 9, so we accept both.
- if (len < 8 || len > 9) {
- mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9"));
- }
-
- return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]),
- mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]),
- mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5])));
-}
-MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime);
-
-// time()
-// Return the number of seconds since the Epoch.
-STATIC mp_obj_t time_time(void) {
- snvs_lp_srtc_datetime_t t;
- SNVS_LP_SRTC_GetDatetime(SNVS, &t);
- // EPOCH is 1970 for this port, which leads to the following trouble:
- // timeutils_seconds_since_epoch() calls timeutils_seconds_since_2000(), and
- // timeutils_seconds_since_2000() subtracts 2000 from year, but uses
- // an unsigned number for seconds, That causes an underrun, which is not
- // fixed by adding the TIMEUTILS_SECONDS_1970_TO_2000.
- // Masking it to 32 bit for year < 2000 fixes it.
- return mp_obj_new_int_from_ull(
- timeutils_seconds_since_epoch(t.year, t.month, t.day, t.hour, t.minute, t.second)
- & (t.year < 2000 ? 0xffffffff : 0xffffffffffff)
- );
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
-
-STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
-
- { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) },
- { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
- { MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
- { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
-
-const mp_obj_module_t mp_module_utime = {
- .base = { &mp_type_module },
- .globals = (mp_obj_dict_t *)&time_module_globals,
-};
-
-MP_REGISTER_MODULE(MP_QSTR_utime, mp_module_utime);
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 8642d53ecc45..52054c5d4d6b 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -29,12 +29,19 @@
// Board specific definitions
#include "mpconfigboard.h"
#include "fsl_common.h"
+#include "lib/nxp_driver/sdk/CMSIS/Include/core_cm7.h"
uint32_t trng_random_u32(void);
+// Config level
+#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
+
// Memory allocation policies
+#if MICROPY_HW_SDRAM_AVAIL
+#define MICROPY_GC_STACK_ENTRY_TYPE uint32_t
+#else
#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t
-#define MICROPY_GC_ALLOC_THRESHOLD (0)
+#endif
#define MICROPY_ALLOC_PARSE_CHUNK_INIT (32)
#define MICROPY_ALLOC_PATH_MAX (256)
@@ -44,101 +51,38 @@ uint32_t trng_random_u32(void);
#define MICROPY_EMIT_INLINE_THUMB (1)
// Optimisations
-#define MICROPY_OPT_LOAD_ATTR_FAST_PATH (1)
-#define MICROPY_OPT_MAP_LOOKUP_CACHE (1)
// Python internal features
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS)
#define MICROPY_READER_VFS (1)
#define MICROPY_ENABLE_GC (1)
-#define MICROPY_ENABLE_FINALISER (1)
-#define MICROPY_STACK_CHECK (1)
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
-#define MICROPY_KBD_EXCEPTION (1)
-#define MICROPY_HELPER_REPL (1)
-#define MICROPY_REPL_AUTO_INDENT (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
-#define MICROPY_ENABLE_SOURCE_LINE (1)
-#define MICROPY_STREAMS_NON_BLOCK (1)
-#define MICROPY_MODULE_BUILTIN_INIT (1)
-#define MICROPY_MODULE_WEAK_LINKS (1)
-#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
-#define MICROPY_ENABLE_SCHEDULER (1)
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_VFS (1)
-#define MICROPY_MODULE_FROZEN_MPY (1)
-#define MICROPY_QSTR_EXTRA_POOL mp_qstr_frozen_const_pool
// Control over Python builtins
-#define MICROPY_PY_FUNCTION_ATTRS (1)
-#define MICROPY_PY_DESCRIPTORS (1)
-#define MICROPY_PY_DELATTR_SETATTR (1)
-#define MICROPY_PY_FSTRINGS (1)
-#define MICROPY_PY_BUILTINS_BYTES_HEX (1)
-#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
-#define MICROPY_PY_BUILTINS_STR_CENTER (1)
-#define MICROPY_PY_BUILTINS_STR_PARTITION (1)
-#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
-#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
-#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1)
-#define MICROPY_PY_BUILTINS_SLICE_INDICES (1)
-#define MICROPY_PY_BUILTINS_FROZENSET (1)
-#define MICROPY_PY_BUILTINS_ROUND_INT (1)
-#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
-#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1)
-#define MICROPY_PY_BUILTINS_COMPILE (1)
-#define MICROPY_PY_BUILTINS_INPUT (1)
-#define MICROPY_PY_BUILTINS_POW3 (1)
-#define MICROPY_PY_BUILTINS_HELP (1)
-#define MICROPY_PY_BUILTINS_HELP_MODULES (1)
#define MICROPY_PY_BUILTINS_HELP_TEXT mimxrt_help_text
-#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
-#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
-#define MICROPY_PY_COLLECTIONS_DEQUE (1)
-#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)
-#define MICROPY_PY_MATH_SPECIAL_FUNCTIONS (1)
-#define MICROPY_PY_MATH_FACTORIAL (1)
-#define MICROPY_PY_MATH_ISCLOSE (1)
-#define MICROPY_PY_CMATH (1)
-#define MICROPY_PY_IO_IOBASE (1)
-#define MICROPY_PY_SYS_MAXSIZE (1)
#define MICROPY_PY_SYS_PLATFORM "mimxrt"
-#define MICROPY_PY_SYS_STDFILES (1)
-#define MICROPY_PY_SYS_STDIO_BUFFER (1)
-#define MICROPY_PY_UERRNO (1)
// Extended modules
#define MICROPY_EPOCH_IS_1970 (1)
-#define MICROPY_PY_UASYNCIO (1)
-#define MICROPY_PY_UCTYPES (1)
-#define MICROPY_PY_UZLIB (1)
-#define MICROPY_PY_UJSON (1)
-#define MICROPY_PY_URE (1)
-#define MICROPY_PY_URE_MATCH_GROUPS (1)
-#define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
-#define MICROPY_PY_URE_SUB (1)
-#define MICROPY_PY_USSL_FINALISER (MICROPY_PY_USSL)
-#define MICROPY_PY_UHASHLIB (1)
-#define MICROPY_PY_UBINASCII (1)
-#define MICROPY_PY_UBINASCII_CRC32 (1)
-#define MICROPY_PY_UTIME_MP_HAL (1)
-#define MICROPY_PY_UOS (1)
-#define MICROPY_PY_UOS_INCLUDEFILE "ports/mimxrt/moduos.c"
+#define MICROPY_PY_SSL_FINALISER (MICROPY_PY_SSL)
+#define MICROPY_PY_TIME_GMTIME_LOCALTIME_MKTIME (1)
+#define MICROPY_PY_TIME_TIME_TIME_NS (1)
+#define MICROPY_PY_TIME_INCLUDEFILE "ports/mimxrt/modtime.c"
+#define MICROPY_PY_OS_INCLUDEFILE "ports/mimxrt/modos.c"
#define MICROPY_PY_OS_DUPTERM (3)
-#define MICROPY_PY_UOS_DUPTERM_NOTIFY (1)
-#define MICROPY_PY_UOS_UNAME (1)
-#define MICROPY_PY_UOS_URANDOM (1)
-#define MICROPY_PY_URANDOM (1)
-#define MICROPY_PY_URANDOM_EXTRA_FUNCS (1)
-#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
-#define MICROPY_PY_USELECT (1)
+#define MICROPY_PY_OS_DUPTERM_NOTIFY (1)
+#define MICROPY_PY_OS_SYNC (1)
+#define MICROPY_PY_OS_UNAME (1)
+#define MICROPY_PY_OS_URANDOM (1)
+#define MICROPY_PY_RANDOM_SEED_INIT_FUNC (trng_random_u32())
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
#define MICROPY_PY_MACHINE_PWM (1)
-#define MICROPY_PY_MACHINE_PWM_INIT (1)
-#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1)
#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/mimxrt/machine_pwm.c"
#define MICROPY_PY_MACHINE_I2C (1)
#ifndef MICROPY_PY_MACHINE_I2S
@@ -147,9 +91,9 @@ uint32_t trng_random_u32(void);
#define MICROPY_PY_MACHINE_SOFTI2C (1)
#define MICROPY_PY_MACHINE_SPI (1)
#define MICROPY_PY_MACHINE_SOFTSPI (1)
-#define MICROPY_PY_FRAMEBUF (1)
+#define MICROPY_PY_MACHINE_TIMER (1)
+#define MICROPY_SOFT_TIMER_TICKS_MS systick_ms
#define MICROPY_PY_ONEWIRE (1)
-#define MICROPY_PY_UPLATFORM (1)
// fatfs configuration used in ffconf.h
#define MICROPY_FATFS_ENABLE_LFN (1)
@@ -157,22 +101,27 @@ uint32_t trng_random_u32(void);
#define MICROPY_FATFS_MAX_SS (4096)
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
-// If MICROPY_PY_LWIP is defined, add network support
-#if MICROPY_PY_LWIP
-
+#ifndef MICROPY_PY_NETWORK
#define MICROPY_PY_NETWORK (1)
-#define MICROPY_PY_USOCKET (1)
-#define MICROPY_PY_UWEBSOCKET (1)
-#define MICROPY_PY_WEBREPL (1)
-#define MICROPY_PY_UHASHLIB_SHA1 (1)
-#define MICROPY_PY_LWIP_SOCK_RAW (1)
-#define MICROPY_HW_ETH_MDC (1)
+#endif
+#ifndef MICROPY_PY_SOCKET
+#define MICROPY_PY_SOCKET (1)
+#endif
+#define MICROPY_PY_WEBSOCKET (MICROPY_PY_LWIP)
+#define MICROPY_PY_WEBREPL (MICROPY_PY_LWIP)
+#define MICROPY_PY_LWIP_SOCK_RAW (MICROPY_PY_LWIP)
+#define MICROPY_PY_SSL_FINALISER (MICROPY_PY_SSL)
+// #define MICROPY_PY_HASHLIB_MD5 (MICROPY_PY_SSL)
+#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL)
+// #define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL)
// Prevent the "LWIP task" from running.
#define MICROPY_PY_LWIP_ENTER MICROPY_PY_PENDSV_ENTER
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_PENDSV_REENTER
#define MICROPY_PY_LWIP_EXIT MICROPY_PY_PENDSV_EXIT
+#ifndef MICROPY_PY_NETWORK_HOSTNAME_DEFAULT
+#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "mpy-mimxrt"
#endif
// For regular code that wants to prevent "background tasks" from running.
@@ -216,7 +165,7 @@ static inline void restore_irq_pri(uint32_t basepri) {
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
-#if defined(MICROPY_HW_ETH_MDC)
+#if defined(IOMUX_TABLE_ENET)
extern const struct _mp_obj_type_t network_lan_type;
#define MICROPY_HW_NIC_ETH { MP_ROM_QSTR(MP_QSTR_LAN), MP_ROM_PTR(&network_lan_type) },
#else
@@ -231,17 +180,26 @@ extern const struct _mp_obj_type_t network_lan_type;
MICROPY_HW_NIC_ETH \
MICROPY_BOARD_NETWORK_INTERFACES \
-#define MICROPY_HW_PIT_NUM_CHANNELS 3
+#ifndef MICROPY_BOARD_ROOT_POINTERS
+#define MICROPY_BOARD_ROOT_POINTERS
+#endif
+
+// Additional entries for use with pendsv_schedule_dispatch.
+#ifndef MICROPY_BOARD_PENDSV_ENTRIES
+#define MICROPY_BOARD_PENDSV_ENTRIES
+#endif
#define MP_STATE_PORT MP_STATE_VM
// Miscellaneous settings
-
+#ifndef MICROPY_EVENT_POLL_HOOK
#define MICROPY_EVENT_POLL_HOOK \
do { \
extern void mp_handle_pending(bool); \
mp_handle_pending(true); \
+ __WFE(); \
} while (0);
+#endif
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p) | 1))
diff --git a/ports/mimxrt/mphalport.c b/ports/mimxrt/mphalport.c
index 87741e0b5cf9..2114baaae4fd 100644
--- a/ports/mimxrt/mphalport.c
+++ b/ports/mimxrt/mphalport.c
@@ -86,8 +86,11 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
ret |= MP_STREAM_POLL_RD;
}
+ if ((poll_flags & MP_STREAM_POLL_WR) && tud_cdc_connected() && tud_cdc_write_available() > 0) {
+ ret |= MP_STREAM_POLL_WR;
+ }
#if MICROPY_PY_OS_DUPTERM
- ret |= mp_uos_dupterm_poll(poll_flags);
+ ret |= mp_os_dupterm_poll(poll_flags);
#endif
return ret;
}
@@ -100,7 +103,7 @@ int mp_hal_stdin_rx_chr(void) {
return c;
}
#if MICROPY_PY_OS_DUPTERM
- int dupterm_c = mp_uos_dupterm_rx_chr();
+ int dupterm_c = mp_os_dupterm_rx_chr();
if (dupterm_c >= 0) {
return dupterm_c;
}
@@ -116,16 +119,22 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
if (n > CFG_TUD_CDC_EP_BUFSIZE) {
n = CFG_TUD_CDC_EP_BUFSIZE;
}
- while (n > tud_cdc_write_available()) {
- __WFE();
+ uint64_t timeout = ticks_us64() + (uint64_t)(MICROPY_HW_USB_CDC_TX_TIMEOUT * 1000);
+ // Wait with a max of USC_CDC_TIMEOUT ms
+ while (n > tud_cdc_write_available() && ticks_us64() < timeout) {
+ MICROPY_EVENT_POLL_HOOK
+ }
+ if (ticks_us64() >= timeout) {
+ break;
}
+
uint32_t n2 = tud_cdc_write(str + i, n);
tud_cdc_write_flush();
i += n2;
}
}
#if MICROPY_PY_OS_DUPTERM
- mp_uos_dupterm_tx_strn(str, len);
+ mp_os_dupterm_tx_strn(str, len);
#endif
}
@@ -140,8 +149,13 @@ uint64_t mp_hal_time_ns(void) {
// MAC address
void mp_hal_get_unique_id(uint8_t id[]) {
+ #if defined CPU_MIMXRT1176_cm7
+ *(uint32_t *)id = OCOTP->FUSEN[0x10].FUSE;
+ *(uint32_t *)(id + 4) = OCOTP->FUSEN[0x11].FUSE;
+ #else
*(uint32_t *)id = OCOTP->CFG0;
*(uint32_t *)(id + 4) = OCOTP->CFG1;
+ #endif
}
// Generate a random locally administered MAC address (LAA)
diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h
index 124b905604d0..ba7e1cfa9416 100644
--- a/ports/mimxrt/mphalport.h
+++ b/ports/mimxrt/mphalport.h
@@ -35,9 +35,15 @@
#define MICROPY_HAL_VERSION "2.8.0"
+#define MICROPY_HW_USB_CDC_TX_TIMEOUT (500)
+
#define MP_HAL_PIN_FMT "%q"
extern ringbuf_t stdin_ringbuf;
+// Define an alias for systick_ms, because the shared softtimer.c uses
+// the symbol uwTick for the systick ms counter.
+#define uwTick systick_ms
+
#define mp_hal_pin_obj_t const machine_pin_obj_t *
#define mp_hal_get_pin_obj(o) pin_find(o)
#define mp_hal_pin_name(p) ((p)->name)
diff --git a/ports/mimxrt/network_lan.c b/ports/mimxrt/network_lan.c
index 0842cde82d00..355698e0b588 100644
--- a/ports/mimxrt/network_lan.c
+++ b/ports/mimxrt/network_lan.c
@@ -28,7 +28,7 @@
#include "py/mphal.h"
#include "extmod/modnetwork.h"
-#if defined(MICROPY_HW_ETH_MDC)
+#if defined(IOMUX_TABLE_ENET)
#include "fsl_phy.h"
#include "eth.h"
@@ -36,25 +36,36 @@
#include "hal/phy/device/phydp83825/fsl_phydp83825.h"
#include "hal/phy/device/phydp83848/fsl_phydp83848.h"
#include "hal/phy/device/phylan8720/fsl_phylan8720.h"
+#include "hal/phy/device/phyrtl8211f/fsl_phyrtl8211f.h"
#include "lwip/netif.h"
+#include "lwip/apps/mdns.h"
#ifndef ENET_TX_CLK_OUTPUT
#define ENET_TX_CLK_OUTPUT true
#endif
+#ifndef ENET_1_TX_CLK_OUTPUT
+#define ENET_1_TX_CLK_OUTPUT true
+#endif
+
typedef struct _network_lan_obj_t {
mp_obj_base_t base;
eth_t *eth;
} network_lan_obj_t;
-STATIC const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, ð_instance };
+
+STATIC const network_lan_obj_t network_lan_eth0 = { { &network_lan_type }, ð_instance0 };
+#if defined(ENET_DUAL_PORT)
+STATIC const network_lan_obj_t network_lan_eth1 = { { &network_lan_type }, ð_instance1 };
+#endif
STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
network_lan_obj_t *self = MP_OBJ_TO_PTR(self_in);
struct netif *netif = eth_netif(self->eth);
int status = eth_link_status(self->eth);
- mp_printf(print, "",
+ mp_printf(print, "",
+ self->eth == ð_instance0 ? 0 : 1,
status,
netif->ip_addr.addr & 0xff,
netif->ip_addr.addr >> 8 & 0xff,
@@ -64,18 +75,34 @@ STATIC void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
}
STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
- enum { ARG_id, ARG_phy_type, ARG_phy_addr, ARG_phy_clock};
+ enum { ARG_id, ARG_phy_type, ARG_phy_addr, ARG_ref_clk_mode};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
- { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_PHY_ADDRESS} },
- { MP_QSTR_phy_clock, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ENET_TX_CLK_OUTPUT} },
+ { MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_ref_clk_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- const phy_operations_t *phy_ops = &ENET_PHY_OPS;
+ const phy_operations_t *phy_ops;
+ int phy_addr;
+ bool phy_clock;
+
+ int mac_id = args[ARG_id].u_int;
+ // set default
+ if (mac_id == 0) {
+ phy_ops = &ENET_PHY_OPS;
+ phy_addr = ENET_PHY_ADDRESS;
+ phy_clock = ENET_TX_CLK_OUTPUT;
+ #if defined(ENET_DUAL_PORT)
+ } else {
+ phy_ops = &ENET_1_PHY_OPS;
+ phy_addr = ENET_1_PHY_ADDRESS;
+ phy_clock = ENET_1_TX_CLK_OUTPUT;
+ #endif
+ }
// Select PHY driver
int phy_type = args[ARG_phy_type].u_int;
@@ -88,28 +115,34 @@ STATIC mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, s
phy_ops = &phydp83848_ops;
} else if (phy_type == PHY_LAN8720) {
phy_ops = &phylan8720_ops;
+ } else if (phy_type == PHY_RTL8211F) {
+ phy_ops = &phyrtl8211f_ops;
} else {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid value %d for phy"), phy_type);
}
}
- int phy_addr = args[ARG_phy_addr].u_int;
+ if (args[ARG_phy_addr].u_int != -1) {
+ phy_addr = args[ARG_phy_addr].u_int;
+ }
- bool phy_clock = args[ARG_phy_clock].u_int;
+ if (args[ARG_ref_clk_mode].u_int != -1) {
+ phy_clock = args[ARG_ref_clk_mode].u_int;
+ }
// Prepare for two ETH interfaces.
const network_lan_obj_t *self;
- int mac_id = args[ARG_id].u_int;
if (mac_id == 0) {
self = &network_lan_eth0;
- mac_id = MP_HAL_MAC_ETH0;
+ eth_init_0(self->eth, MP_HAL_MAC_ETH0, phy_ops, phy_addr, phy_clock);
+ #if defined(ENET_DUAL_PORT)
} else if (mac_id == 1) {
- self = &network_lan_eth0;
- mac_id = MP_HAL_MAC_ETH1;
+ self = &network_lan_eth1;
+ eth_init_1(self->eth, MP_HAL_MAC_ETH1, phy_ops, phy_addr, phy_clock);
+ #endif
} else {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid LAN interface %d"), mac_id);
}
- eth_init(self->eth, mac_id, phy_ops, phy_addr, phy_clock);
// register with network module
mod_network_register_nic((mp_obj_t *)self);
return MP_OBJ_FROM_PTR(self);
@@ -215,6 +248,7 @@ STATIC const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(PHY_DP83825) },
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(PHY_DP83848) },
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(PHY_LAN8720) },
+ { MP_ROM_QSTR(MP_QSTR_PHY_RTL8211F), MP_ROM_INT(PHY_RTL8211F) },
{ MP_ROM_QSTR(MP_QSTR_IN), MP_ROM_INT(PHY_TX_CLK_IN) },
{ MP_ROM_QSTR(MP_QSTR_OUT), MP_ROM_INT(PHY_TX_CLK_OUT) },
};
@@ -230,4 +264,4 @@ MP_DEFINE_CONST_OBJ_TYPE(
);
-#endif // defined(MICROPY_HW_ETH_MDC)
+#endif // defined(IOMUX_TABLE_ENET)
diff --git a/ports/mimxrt/pendsv.c b/ports/mimxrt/pendsv.c
index 7638b160d861..11f2ef5e1c86 100644
--- a/ports/mimxrt/pendsv.c
+++ b/ports/mimxrt/pendsv.c
@@ -27,23 +27,16 @@
#include
#include "py/runtime.h"
-#include "shared/runtime/interrupt_char.h"
#include "pendsv.h"
-#include "lib/nxp_driver/sdk/CMSIS/Include/core_cm7.h"
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003)
#define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0)
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
-uint32_t pendsv_dispatch_active;
pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
#endif
void pendsv_init(void) {
- #if defined(PENDSV_DISPATCH_NUM_SLOTS)
- pendsv_dispatch_active = false;
- #endif
-
// set PendSV interrupt at lowest priority
NVIC_SetPriority(PendSV_IRQn, IRQ_PRI_PENDSV);
}
@@ -51,11 +44,10 @@ void pendsv_init(void) {
#if defined(PENDSV_DISPATCH_NUM_SLOTS)
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
pendsv_dispatch_table[slot] = f;
- pendsv_dispatch_active = true;
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
-void pendsv_dispatch_handler(void) {
+void PendSV_Handler(void) {
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
if (pendsv_dispatch_table[i] != NULL) {
pendsv_dispatch_t f = pendsv_dispatch_table[i];
@@ -64,10 +56,4 @@ void pendsv_dispatch_handler(void) {
}
}
}
-
-void PendSV_Handler(void) {
- if (pendsv_dispatch_active) {
- pendsv_dispatch_handler();
- }
-}
#endif
diff --git a/ports/mimxrt/pendsv.h b/ports/mimxrt/pendsv.h
index 64883c903137..e68f487fb4a1 100644
--- a/ports/mimxrt/pendsv.h
+++ b/ports/mimxrt/pendsv.h
@@ -31,6 +31,7 @@ enum {
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
PENDSV_DISPATCH_LWIP,
#endif
+ MICROPY_BOARD_PENDSV_ENTRIES
PENDSV_DISPATCH_MAX
};
diff --git a/ports/mimxrt/pin.h b/ports/mimxrt/pin.h
index 583d1c30231c..63db55f8a7c5 100644
--- a/ports/mimxrt/pin.h
+++ b/ports/mimxrt/pin.h
@@ -69,6 +69,7 @@ enum {
PIN_AF_MODE_ALT7,
PIN_AF_MODE_ALT8,
PIN_AF_MODE_ALT9,
+ PIN_AF_MODE_ALT10,
};
enum {
diff --git a/ports/mimxrt/sdcard.c b/ports/mimxrt/sdcard.c
index 20f76cc88f31..6dbd45303b63 100644
--- a/ports/mimxrt/sdcard.c
+++ b/ports/mimxrt/sdcard.c
@@ -31,10 +31,6 @@
#include "fsl_iomuxc.h"
#include "pin.h"
-#if FSL_USDHC_DRIVER_VERSION == 0x020208
-#define USHDC_USE_TRANSFER_NONBLOCKING_10XX (1)
-#endif
-
#define SDCARD_VOLTAGE_WINDOW_SD (0x80100000U)
#define SDCARD_HIGH_CAPACITY (0x40000000U)
#define SDCARD_SWITCH_1_8V_CAPACITY ((uint32_t)0x01000000U)
@@ -143,16 +139,6 @@ enum
SDCARD_STATE_DISCONNECT = 8U,
};
-// ---
-// SD Card transfer status
-// ---
-typedef enum
-{
- SDCARD_TRANSFER_SUCCESS = 0,
- SDCARD_TRANSFER_ERROR,
- SDCARD_TRANSFER_PENDING
-} sdcard_transfer_status_t;
-
// ---
// SD Card type definitions
// ---
@@ -220,9 +206,6 @@ mimxrt_sdcard_obj_t mimxrt_sdcard_objs[] =
#endif
};
-volatile status_t sdcard_transfer_status;
-volatile bool sdcard_transfer_done;
-
// ---
// Local function declarations
// ---
@@ -240,7 +223,7 @@ void sdcard_card_removed_callback(USDHC_Type *base, void *userData);
void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData);
void sdcard_dummy_callback(USDHC_Type *base, void *userData);
-// SD Card commmands
+// SD Card commands
static bool sdcard_cmd_go_idle_state(mimxrt_sdcard_obj_t *card);
static bool sdcard_cmd_oper_cond(mimxrt_sdcard_obj_t *card);
static bool sdcard_cmd_app_cmd(mimxrt_sdcard_obj_t *card);
@@ -251,7 +234,7 @@ static bool sdcard_cmd_set_rel_add(mimxrt_sdcard_obj_t *card);
static bool sdcard_cmd_send_csd(mimxrt_sdcard_obj_t *card, csd_t *csd);
static bool sdcard_cmd_select_card(mimxrt_sdcard_obj_t *sdcard);
static bool sdcard_cmd_set_blocklen(mimxrt_sdcard_obj_t *sdcard);
-static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *sdcard, uint8_t bus_width);
+static bool sdcard_cmd_set_bus_width(mimxrt_sdcard_obj_t *sdcard, usdhc_data_bus_width_t bus_width);
void sdcard_card_inserted_callback(USDHC_Type *base, void *userData) {
#if defined MICROPY_USDHC1 && USDHC1_AVAIL
@@ -286,16 +269,6 @@ void sdcard_card_removed_callback(USDHC_Type *base, void *userData) {
USDHC_ClearInterruptStatusFlags(base, kUSDHC_CardRemovalFlag);
}
-#if USHDC_USE_TRANSFER_NONBLOCKING_10XX
-
-void sdcard_transfer_complete_callback(USDHC_Type *base, usdhc_handle_t *handle, status_t status, void *userData) {
- sdcard_transfer_status = status;
- sdcard_transfer_done = true;
- USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandCompleteFlag | kUSDHC_DataCompleteFlag);
-}
-
-#endif
-
void sdcard_dummy_callback(USDHC_Type *base, void *userData) {
return;
}
@@ -331,36 +304,12 @@ static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handl
dma_config.admaTable = sdcard_adma_descriptor_table;
dma_config.admaTableWords = DMA_DESCRIPTOR_BUFFER_SIZE;
- #if USHDC_USE_TRANSFER_NONBLOCKING_10XX
-
- uint32_t retry_ctr = 0UL;
-
- do {
- status = USDHC_TransferNonBlocking(base, handle, &dma_config, transfer);
- retry_ctr++;
- } while (!(status == kStatus_Success) && (retry_ctr < 1000000UL));
-
- if (status == kStatus_Success) {
- for (int i = 0; i < timeout_ms * 100; i++) {
- if ((sdcard_transfer_done == true) && (sdcard_transfer_status == kStatus_Success)) {
- sdcard_transfer_done = false;
- return kStatus_Success;
- }
- ticks_delay_us64(10);
- }
- return kStatus_Timeout;
- } else {
- sdcard_error_recovery(base);
- return status;
- }
-
- #else // USHDC_USE_TRANSFER_NONBLOCKING_10XX
-
// Wait while the card is busy before a transfer
status = kStatus_Timeout;
for (int i = 0; i < timeout_ms * 100; i++) {
// Wait until Data0 is low any more. Low indicates "Busy".
- if ((transfer->data->txData == NULL) || (USDHC_GetPresentStatusFlags(base) & (uint32_t)kUSDHC_Data0LineLevelFlag) != 0) {
+ if (((transfer->data->txData == NULL) && (transfer->data->rxData == NULL)) ||
+ (USDHC_GetPresentStatusFlags(base) & (uint32_t)kUSDHC_Data0LineLevelFlag) != 0) {
// Not busy anymore or no TX-Data
status = USDHC_TransferBlocking(base, &dma_config, transfer);
if (status != kStatus_Success) {
@@ -372,7 +321,6 @@ static status_t sdcard_transfer_blocking(USDHC_Type *base, usdhc_handle_t *handl
}
return status;
- #endif // USHDC_USE_TRANSFER_NONBLOCKING_11XX
}
static void sdcard_decode_csd(mimxrt_sdcard_obj_t *card, csd_t *csd) {
@@ -770,18 +718,15 @@ void sdcard_init(mimxrt_sdcard_obj_t *card, uint32_t base_clk) {
(void)sdcard_reset(card);
card->base_clk = base_clk;
- #if USHDC_USE_TRANSFER_NONBLOCKING_10XX
usdhc_transfer_callback_t callbacks = {
.CardInserted = sdcard_card_inserted_callback,
.CardRemoved = sdcard_card_removed_callback,
.SdioInterrupt = sdcard_dummy_callback,
.BlockGap = sdcard_dummy_callback,
- .TransferComplete = sdcard_transfer_complete_callback,
.ReTuning = sdcard_dummy_callback,
};
USDHC_TransferCreateHandle(card->usdhc_inst, &card->handle, &callbacks, NULL);
- #endif // USHDC_USE_TRANSFER_NONBLOCKING_10XX
}
void sdcard_deinit(mimxrt_sdcard_obj_t *card) {
@@ -1052,8 +997,6 @@ bool sdcard_power_off(mimxrt_sdcard_obj_t *card) {
bool sdcard_detect(mimxrt_sdcard_obj_t *card) {
bool detect = false;
- #if USHDC_USE_TRANSFER_NONBLOCKING_10XX
-
#if defined MICROPY_USDHC1 && USDHC1_AVAIL
if ((card->usdhc_inst == USDHC1) && (sdcard_usdhc1_state.inserted == true)) {
return true;
@@ -1065,8 +1008,6 @@ bool sdcard_detect(mimxrt_sdcard_obj_t *card) {
}
#endif
- #endif // USHDC_USE_TRANSFER_NONBLOCKING_10XX
-
if (card->pins->cd_b.pin) {
detect = USDHC_DetectCardInsert(card->usdhc_inst);
} else {
diff --git a/ports/mimxrt/systick.c b/ports/mimxrt/systick.c
index 086bf1670161..8b0f5eb7b2de 100644
--- a/ports/mimxrt/systick.c
+++ b/ports/mimxrt/systick.c
@@ -28,6 +28,9 @@
#include "py/mphal.h"
#include "systick.h"
+#include "pendsv.h"
+#include "shared/runtime/softtimer.h"
+
volatile uint32_t systick_ms = 0;
systick_dispatch_t systick_dispatch_table[SYSTICK_DISPATCH_NUM_SLOTS];
@@ -44,6 +47,10 @@ void SysTick_Handler(void) {
if (f != NULL) {
f(uw_tick);
}
+
+ if (soft_timer_next == uw_tick) {
+ pendsv_schedule_dispatch(PENDSV_DISPATCH_SOFT_TIMER, soft_timer_handler);
+ }
}
bool systick_has_passed(uint32_t start_tick, uint32_t delay_ms) {
diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c
index 0fc9babc04b4..858a5c574f82 100644
--- a/ports/mimxrt/ticks.c
+++ b/ports/mimxrt/ticks.c
@@ -41,7 +41,11 @@ void ticks_init(void) {
ticks_ms_upper = 0;
gpt_config_t config;
+ #if defined MIMXRT117x_SERIES
+ config.clockSource = kGPT_ClockSource_HighFreq;
+ #else
config.clockSource = kGPT_ClockSource_Osc;
+ #endif
config.divider = 24; // XTAL is 24MHz
config.enableFreeRun = true;
config.enableRunInWait = true;
diff --git a/ports/mimxrt/tusb_port.c b/ports/mimxrt/tusb_port.c
index 55855674c629..f359d44e4d27 100644
--- a/ports/mimxrt/tusb_port.c
+++ b/ports/mimxrt/tusb_port.c
@@ -35,8 +35,8 @@
#define MICROPY_HW_USB_PID (0x9802)
#endif
-#ifndef MICROPY_HW_USB_STR_MANUF
-#define MICROPY_HW_USB_STR_MANUF ("MicroPython")
+#ifndef MICROPY_HW_USB_MANUFACTURER_STRING
+#define MICROPY_HW_USB_MANUFACTURER_STRING ("MicroPython")
#endif
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
@@ -85,7 +85,7 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
};
static const char *const usbd_desc_str[] = {
- [USBD_STR_MANUF] = MICROPY_HW_USB_STR_MANUF,
+ [USBD_STR_MANUF] = MICROPY_HW_USB_MANUFACTURER_STRING,
[USBD_STR_PRODUCT] = MICROPY_HW_BOARD_NAME,
[USBD_STR_SERIAL] = "00000000000000000000",
[USBD_STR_CDC] = "Board CDC",
diff --git a/ports/minimal/Makefile b/ports/minimal/Makefile
index 1a20412e0da5..050c4ddf526a 100644
--- a/ports/minimal/Makefile
+++ b/ports/minimal/Makefile
@@ -26,7 +26,7 @@ CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mcpu=cortex-m4 -msoft-float -fsingl
CFLAGS += $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_CORTEX_M4) $(COPT)
LDFLAGS += -nostdlib -T stm32f405.ld -Map=$@.map --cref --gc-sections
else
-LD = gcc
+LD = $(CC)
CFLAGS += $(INC) -Wall -Werror -Wdouble-promotion -Wfloat-conversion -std=c99 $(COPT)
LDFLAGS += -Wl,-Map=$@.map,--cref -Wl,--gc-sections
endif
diff --git a/ports/minimal/main.c b/ports/minimal/main.c
index 289327658626..499099753184 100644
--- a/ports/minimal/main.c
+++ b/ports/minimal/main.c
@@ -29,7 +29,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
static char *stack_top;
#if MICROPY_ENABLE_GC
-static char heap[2048];
+static char heap[MICROPY_HEAP_SIZE];
#endif
int main(int argc, char **argv) {
@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
// do_str("print('hello world!', list(x+1 for x in range(10)), end='eol\\n')", MP_PARSE_SINGLE_INPUT);
// do_str("for i in range(10):\r\n print(i)", MP_PARSE_FILE_INPUT);
#else
- pyexec_frozen_module("frozentest.py");
+ pyexec_frozen_module("frozentest.py", false);
#endif
mp_deinit();
return 0;
@@ -69,7 +69,7 @@ void gc_collect(void) {
gc_collect_start();
gc_collect_root(&dummy, ((mp_uint_t)stack_top - (mp_uint_t)&dummy) / sizeof(mp_uint_t));
gc_collect_end();
- gc_dump_info();
+ gc_dump_info(&mp_plat_print);
}
#endif
diff --git a/ports/minimal/mpconfigport.h b/ports/minimal/mpconfigport.h
index 02312e2e400e..0f50f8d389cd 100644
--- a/ports/minimal/mpconfigport.h
+++ b/ports/minimal/mpconfigport.h
@@ -33,11 +33,13 @@ typedef long mp_off_t;
#ifdef __linux__
#define MICROPY_MIN_USE_STDOUT (1)
+#define MICROPY_HEAP_SIZE (25600) // heap size 25 kilobytes
#endif
#ifdef __thumb__
#define MICROPY_MIN_USE_CORTEX_CPU (1)
#define MICROPY_MIN_USE_STM32_MCU (1)
+#define MICROPY_HEAP_SIZE (2048) // heap size 2 kilobytes
#endif
#define MP_STATE_PORT MP_STATE_VM
diff --git a/ports/minimal/stm32f405.ld b/ports/minimal/stm32f405.ld
index a202294a54ee..6a275440cf2a 100644
--- a/ports/minimal/stm32f405.ld
+++ b/ports/minimal/stm32f405.ld
@@ -28,7 +28,7 @@ SECTIONS
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
- _sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
+ _sidata = _etext; /* This is used by the startup in order to initialize the .data section */
} >FLASH
/* This is the initialized data section
diff --git a/ports/nrf/Makefile b/ports/nrf/Makefile
index a80a37e1fb46..3a4b0ef23d50 100644
--- a/ports/nrf/Makefile
+++ b/ports/nrf/Makefile
@@ -1,12 +1,18 @@
-# Select the board to build for: if not given on the command line,
-# then default to pca10040.
+# Select the board to build for:
+ifdef BOARD_DIR
+# Custom board path - remove trailing slash and get the final component of
+# the path as the board name.
+BOARD ?= $(notdir $(BOARD_DIR:/=))
+else
+# If not given on the command line, then default to pca10040.
BOARD ?= pca10040
+BOARD_DIR ?= boards/$(BOARD)
+endif
+
ifeq ($(wildcard boards/$(BOARD)/.),)
$(error Invalid BOARD specified)
endif
-BOARD_DIR ?= boards/$(BOARD)
-
# If SoftDevice is selected, try to use that one.
SD ?=
SD_LOWER = $(shell echo $(SD) | tr '[:upper:]' '[:lower:]')
@@ -227,11 +233,6 @@ SRC_LIB_C += $(addprefix lib/,\
libm/roundf.c \
)
-SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\
- nrfx_uarte.c \
- nrfx_twim.c \
- )
-
include drivers/secureboot/secureboot.mk
endif
@@ -242,7 +243,7 @@ SRC_SHARED_C += $(addprefix shared/,\
runtime/pyexec.c \
runtime/sys_stdio_mphal.c \
runtime/interrupt_char.c \
- runtime/tinyusb_helpers.c \
+ tinyusb/mp_cdc_common.c \
timeutils/timeutils.c \
)
@@ -257,11 +258,13 @@ endif
SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\
prs/nrfx_prs.c \
nrfx_uart.c \
+ nrfx_uarte.c \
nrfx_adc.c \
nrfx_saadc.c \
nrfx_temp.c \
nrfx_rng.c \
nrfx_twi.c \
+ nrfx_twim.c \
nrfx_spi.c \
nrfx_spim.c \
nrfx_rtc.c \
@@ -313,6 +316,7 @@ SRC_C += $(addprefix lib/tinyusb/src/,\
tusb.c \
portable/nordic/nrf5x/dcd_nrf5x.c \
)
+
endif
DRIVERS_SRC_C += $(addprefix modules/,\
@@ -324,11 +328,9 @@ DRIVERS_SRC_C += $(addprefix modules/,\
machine/pin.c \
machine/timer.c \
machine/rtcounter.c \
- machine/pwm.c \
machine/temp.c \
- uos/moduos.c \
- uos/microbitfs.c \
- utime/modutime.c \
+ os/modos.c \
+ os/microbitfs.c \
board/modboard.c \
board/led.c \
ubluepy/modubluepy.c \
@@ -509,6 +511,15 @@ nrfutil_dfu_deploy: $(BUILD)/$(OUTPUT_FILENAME).hex
$(Q)nrfutil dfu usb-serial -pkg $(BUILD)/$(OUTPUT_FILENAME)_dfu.zip -p $(NRFUTIL_PORT) -t 0
deploy: nrfutil_dfu_deploy
+
+else ifeq ($(FLASHER), bossac)
+
+BOSSAC_PORT ?= /dev/ttyACM0
+BOSSAC_OFFSET ?= 0x16000
+
+deploy: $(BUILD)/$(OUTPUT_FILENAME).bin
+ $(Q)bossac -e -w --offset=$(BOSSAC_OFFSET) --port=$(BOSSAC_PORT) -i -d -U -R $<
+
endif
flash: deploy
@@ -541,12 +552,6 @@ $(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qst
$(GEN_PINS_SRC:.c=.o): $(GEN_PINS_SRC)
$(call compile_c)
-ifneq ($(FROZEN_MANIFEST),)
-CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
-endif
-
$(PY_BUILD)/nlr%.o: CFLAGS += -Os -fno-lto
include ../../py/mkrules.mk
diff --git a/ports/nrf/README.md b/ports/nrf/README.md
index a833f0f17c42..fde04e61f101 100644
--- a/ports/nrf/README.md
+++ b/ports/nrf/README.md
@@ -98,7 +98,7 @@ Note: further tuning of features to include in bluetooth or even setting up the
## Compile with freeze manifest
-Freeze manifests can be used by definining `FROZEN_MANIFEST` pointing to a
+Freeze manifests can be used by defining `FROZEN_MANIFEST` pointing to a
`manifest.py`. This can either be done by a `make` invocation or by defining
it in the specific target board's `mpconfigboard.mk`.
@@ -132,8 +132,8 @@ For example:
## Set file system size
The size of the file system on the internal flash is configured by the linker
-script parameter `_fs_size`. This can either be overriden by the linker script
-or dynamically through the makefile. By seting a value to the `FS_SIZE`.
+script parameter `_fs_size`. This can either be overridden by the linker script
+or dynamically through the makefile. By setting a value to the `FS_SIZE`.
The number will be passed directly to the linker scripts in order to calculate
the start and end of the file system. Note that the parameter value must be in
linker script syntax as it is passed directly.
@@ -215,7 +215,7 @@ Install the necessary Python packages that will be used for flashing using the b
The `intelhex` provides the `hexmerge.py` utility which is used by the Makefile
to trim of the MBR in case SoftDevice flashing is requested.
-`nrfutil` as flashing backend also requires a serial port paramter to be defined
+`nrfutil` as flashing backend also requires a serial port parameter to be defined
in addition to the `deploy` target of make. For example:
make BOARD=nrf52840-mdk-usb-dongle NRFUTIL_PORT=/dev/ttyACM0 deploy
diff --git a/ports/nrf/boards/actinius_icarus/mpconfigboard.h b/ports/nrf/boards/actinius_icarus/mpconfigboard.h
index e99d731df941..46960cab83bb 100644
--- a/ports/nrf/boards/actinius_icarus/mpconfigboard.h
+++ b/ports/nrf/boards/actinius_icarus/mpconfigboard.h
@@ -33,7 +33,6 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_PWM (0)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (0)
diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/board.json b/ports/nrf/boards/arduino_nano_33_ble_sense/board.json
index 9488c75f8419..65a8e2435059 100644
--- a/ports/nrf/boards/arduino_nano_33_ble_sense/board.json
+++ b/ports/nrf/boards/arduino_nano_33_ble_sense/board.json
@@ -17,7 +17,7 @@
"images": [
"ABX00031_01.iso_998x749.jpg"
],
- "mcu": "nRF52840",
+ "mcu": "nrf52",
"product": "Arduino Nano 33 BLE Sense",
"thumbnail": "",
"url": "https://store.arduino.cc/products/arduino-nano-33-ble-sense",
diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py b/ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py
index 8396e0249cbc..1e35ae8c4dd3 100644
--- a/ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py
+++ b/ports/nrf/boards/arduino_nano_33_ble_sense/manifest.py
@@ -2,3 +2,7 @@
require("hts221")
require("lps22h")
require("lsm9ds1")
+require("bmm150")
+require("bmi270")
+require("hs3003")
+freeze("./modules")
diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/modules/imu.py b/ports/nrf/boards/arduino_nano_33_ble_sense/modules/imu.py
new file mode 100644
index 000000000000..821795e17c8e
--- /dev/null
+++ b/ports/nrf/boards/arduino_nano_33_ble_sense/modules/imu.py
@@ -0,0 +1,45 @@
+"""
+IMU module for Arduino Nano BLE 33 SENSE (REV1 and REV2).
+
+Example usage:
+
+import time
+import imu
+from machine import Pin, I2C
+
+bus = I2C(1, scl=Pin(15), sda=Pin(14))
+imu = imu.IMU(bus)
+
+while (True):
+ print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.accel()))
+ print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.gyro()))
+ print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet()))
+ print("")
+ time.sleep_ms(100)
+"""
+
+import time
+
+
+class IMU:
+ def __init__(self, bus):
+ """Initializes Gyro, Accelerometer and Magnetometer using default values."""
+ if 0x68 in bus.scan():
+ from bmm150 import BMM150
+ from bmi270 import BMI270
+
+ magnet = BMM150(bus)
+ self.imu = BMI270(bus, bmm_magnet=magnet)
+ else:
+ from lsm9ds1 import LSM9DS1
+
+ self.imu = LSM9DS1(bus)
+
+ def gyro(self):
+ return self.imu.gyro()
+
+ def accel(self):
+ return self.imu.accel()
+
+ def magnet(self):
+ return self.imu.magnet()
diff --git a/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h b/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h
index 4a16b6110bc9..71349e08c4c8 100644
--- a/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h
+++ b/ports/nrf/boards/arduino_nano_33_ble_sense/mpconfigboard.h
@@ -14,9 +14,9 @@
#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) NANO33_board_enter_bootloader()
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/arduino_primo/mpconfigboard.h b/ports/nrf/boards/arduino_primo/mpconfigboard.h
index 639b6869c098..271cef0323df 100644
--- a/ports/nrf/boards/arduino_primo/mpconfigboard.h
+++ b/ports/nrf/boards/arduino_primo/mpconfigboard.h
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -32,9 +32,9 @@
#define MICROPY_PY_MUSIC (1)
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h
index 2ceeadf8eb93..0ca3ca16127a 100644
--- a/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h
+++ b/ports/nrf/boards/blueio_tag_evim/mpconfigboard.h
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -32,9 +32,9 @@
#define MICROPY_PY_MUSIC (1)
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/dvk_bl652/mpconfigboard.h b/ports/nrf/boards/dvk_bl652/mpconfigboard.h
index d0b19a318453..e83e555178ff 100644
--- a/ports/nrf/boards/dvk_bl652/mpconfigboard.h
+++ b/ports/nrf/boards/dvk_bl652/mpconfigboard.h
@@ -31,7 +31,6 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/evk_nina_b1/mpconfigboard.h b/ports/nrf/boards/evk_nina_b1/mpconfigboard.h
index f0629b3a2303..72aeb449285f 100644
--- a/ports/nrf/boards/evk_nina_b1/mpconfigboard.h
+++ b/ports/nrf/boards/evk_nina_b1/mpconfigboard.h
@@ -32,7 +32,6 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/evk_nina_b3/mpconfigboard.h b/ports/nrf/boards/evk_nina_b3/mpconfigboard.h
index eaca796be4d6..d4ce93a0aca1 100644
--- a/ports/nrf/boards/evk_nina_b3/mpconfigboard.h
+++ b/ports/nrf/boards/evk_nina_b3/mpconfigboard.h
@@ -41,14 +41,14 @@
#define MICROPY_EMIT_INLINE_THUMB (1)
// Enable optional modules
-#define MICROPY_PY_UERRNO (1)
-#define MICROPY_PY_UHASHLIB (1)
+#define MICROPY_PY_ERRNO (1)
+#define MICROPY_PY_HASHLIB (1)
// Peripherals Config
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/feather52/mpconfigboard.h b/ports/nrf/boards/feather52/mpconfigboard.h
index 10e0d999cebc..cef44ca4032f 100644
--- a/ports/nrf/boards/feather52/mpconfigboard.h
+++ b/ports/nrf/boards/feather52/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "nrf52"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h
index 4897471ea56c..63d2944f6c25 100644
--- a/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h
+++ b/ports/nrf/boards/ibk_blyst_nano/mpconfigboard.h
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -32,9 +32,9 @@
#define MICROPY_PY_MUSIC (1)
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h
index 06c16477387c..73b1c6ff7459 100644
--- a/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h
+++ b/ports/nrf/boards/idk_blyst_nano/mpconfigboard.h
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -32,9 +32,9 @@
#define MICROPY_PY_MUSIC (1)
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/make-pins.py b/ports/nrf/boards/make-pins.py
index 347ed15b21b3..720df6e49ee8 100644
--- a/ports/nrf/boards/make-pins.py
+++ b/ports/nrf/boards/make-pins.py
@@ -13,7 +13,7 @@
def parse_pin(name_str):
"""Parses a string and returns a pin-num."""
if len(name_str) < 1:
- raise ValueError("Expecting pin name to be at least 4 charcters.")
+ raise ValueError("Expecting pin name to be at least 4 characters.")
if name_str[0] != "P":
raise ValueError("Expecting pin name to start with P")
pin_str = name_str[1:].split("/")[0]
diff --git a/ports/nrf/boards/microbit/modules/iters.c b/ports/nrf/boards/microbit/modules/iters.c
index e6762421eb57..b16a4c665837 100644
--- a/ports/nrf/boards/microbit/modules/iters.c
+++ b/ports/nrf/boards/microbit/modules/iters.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.c b/ports/nrf/boards/microbit/modules/microbitconstimage.c
index fa079845974d..d6f6ab0a9d80 100644
--- a/ports/nrf/boards/microbit/modules/microbitconstimage.c
+++ b/ports/nrf/boards/microbit/modules/microbitconstimage.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
diff --git a/ports/nrf/boards/microbit/modules/microbitconstimage.h b/ports/nrf/boards/microbit/modules/microbitconstimage.h
index ca67b5c467ff..45d58c4a094f 100644
--- a/ports/nrf/boards/microbit/modules/microbitconstimage.h
+++ b/ports/nrf/boards/microbit/modules/microbitconstimage.h
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
diff --git a/ports/nrf/boards/microbit/modules/microbitdisplay.c b/ports/nrf/boards/microbit/modules/microbitdisplay.c
index e4e4d13fe449..ff3c499fa325 100644
--- a/ports/nrf/boards/microbit/modules/microbitdisplay.c
+++ b/ports/nrf/boards/microbit/modules/microbitdisplay.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
diff --git a/ports/nrf/boards/microbit/modules/microbitimage.c b/ports/nrf/boards/microbit/modules/microbitimage.c
index 17d737dba5e5..08ef4babcf46 100644
--- a/ports/nrf/boards/microbit/modules/microbitimage.c
+++ b/ports/nrf/boards/microbit/modules/microbitimage.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
@@ -219,7 +219,7 @@ STATIC mp_obj_t microbit_image_make_new(const mp_obj_type_t *type_in, mp_uint_t
const char *str = mp_obj_str_get_data(args[0], &len);
// make image from string
if (len == 1) {
- /* For a single charater, return the font glyph */
+ /* For a single character, return the font glyph */
return microbit_image_for_char(str[0]);
} else {
/* Otherwise parse the image description string */
@@ -305,7 +305,7 @@ STATIC void image_blit(microbit_image_obj_t *src, greyscale_t *dest, mp_int_t x,
greyscaleSetPixelValue(dest, i+xdest-x, j+ydest-y, val);
}
}
- // Adjust intersection rectange to dest
+ // Adjust intersection rectangle to dest
intersect_x0 += xdest-x;
intersect_y0 += ydest-y;
intersect_x1 += xdest-x;
diff --git a/ports/nrf/boards/microbit/modules/modmicrobit.c b/ports/nrf/boards/microbit/modules/modmicrobit.c
index c6aa445b1c9a..06b3e5f6ab91 100644
--- a/ports/nrf/boards/microbit/modules/modmicrobit.c
+++ b/ports/nrf/boards/microbit/modules/modmicrobit.c
@@ -1,5 +1,5 @@
/*
- * This file is part of the Micro Python project, http://micropython.org/
+ * This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
diff --git a/ports/nrf/boards/microbit/mpconfigboard.h b/ports/nrf/boards/microbit/mpconfigboard.h
index f05317fb5910..4c6e05120db8 100644
--- a/ports/nrf/boards/microbit/mpconfigboard.h
+++ b/ports/nrf/boards/microbit/mpconfigboard.h
@@ -30,9 +30,9 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MUSIC (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_SOFT_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h b/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h
index f048c39e0efd..feafe8a14314 100644
--- a/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h
+++ b/ports/nrf/boards/nrf52840-mdk-usb-dongle/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "nrf52840-MDK-USB-Dongle"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/particle_xenon/mpconfigboard.h b/ports/nrf/boards/particle_xenon/mpconfigboard.h
index 7c814e377f60..012a04458eeb 100644
--- a/ports/nrf/boards/particle_xenon/mpconfigboard.h
+++ b/ports/nrf/boards/particle_xenon/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "PARTICLE-XENON"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/pca10000/mpconfigboard.h b/ports/nrf/boards/pca10000/mpconfigboard.h
index f61405d0480b..e56e0edf8373 100644
--- a/ports/nrf/boards/pca10000/mpconfigboard.h
+++ b/ports/nrf/boards/pca10000/mpconfigboard.h
@@ -30,12 +30,14 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (0)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (0)
#define MICROPY_PY_MACHINE_ADC (0)
#define MICROPY_PY_MACHINE_TEMP (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_SOFT_PWM (1)
+
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_HAS_LED (1)
diff --git a/ports/nrf/boards/pca10001/mpconfigboard.h b/ports/nrf/boards/pca10001/mpconfigboard.h
index c101b0886aad..a2e845539847 100644
--- a/ports/nrf/boards/pca10001/mpconfigboard.h
+++ b/ports/nrf/boards/pca10001/mpconfigboard.h
@@ -30,12 +30,14 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (0)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
#define MICROPY_PY_MACHINE_TEMP (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_SOFT_PWM (1)
+
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_HAS_LED (1)
diff --git a/ports/nrf/boards/pca10028/mpconfigboard.h b/ports/nrf/boards/pca10028/mpconfigboard.h
index 5488b4ba534c..7abb5845e3f8 100644
--- a/ports/nrf/boards/pca10028/mpconfigboard.h
+++ b/ports/nrf/boards/pca10028/mpconfigboard.h
@@ -30,12 +30,14 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
#define MICROPY_PY_MACHINE_TEMP (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_SOFT_PWM (1)
+
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_HAS_LED (1)
diff --git a/ports/nrf/boards/pca10031/mpconfigboard.h b/ports/nrf/boards/pca10031/mpconfigboard.h
index f16ffd7057ff..f162366233fd 100644
--- a/ports/nrf/boards/pca10031/mpconfigboard.h
+++ b/ports/nrf/boards/pca10031/mpconfigboard.h
@@ -30,12 +30,14 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
#define MICROPY_PY_MACHINE_TEMP (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_SOFT_PWM (1)
+
#define MICROPY_HW_ENABLE_RNG (1)
#define MICROPY_HW_HAS_LED (1)
diff --git a/ports/nrf/boards/pca10040/mpconfigboard.h b/ports/nrf/boards/pca10040/mpconfigboard.h
index 1dd01d66a048..00a56c2ea2c5 100644
--- a/ports/nrf/boards/pca10040/mpconfigboard.h
+++ b/ports/nrf/boards/pca10040/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "nrf52-DK"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/pca10056/mpconfigboard.h b/ports/nrf/boards/pca10056/mpconfigboard.h
index c037e2ecf5b2..fa39764a7eb9 100644
--- a/ports/nrf/boards/pca10056/mpconfigboard.h
+++ b/ports/nrf/boards/pca10056/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "nrf52840-PDK"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/pca10059/mpconfigboard.h b/ports/nrf/boards/pca10059/mpconfigboard.h
index 3db599f2c35d..904a0871e4da 100644
--- a/ports/nrf/boards/pca10059/mpconfigboard.h
+++ b/ports/nrf/boards/pca10059/mpconfigboard.h
@@ -29,9 +29,9 @@
#define MICROPY_PY_SYS_PLATFORM "nrf52840-Dongle"
#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
#define MICROPY_PY_MACHINE_HW_PWM (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/boards/pca10090/mpconfigboard.h b/ports/nrf/boards/pca10090/mpconfigboard.h
index 28381c40d1e6..95cf8d6544b0 100644
--- a/ports/nrf/boards/pca10090/mpconfigboard.h
+++ b/ports/nrf/boards/pca10090/mpconfigboard.h
@@ -33,7 +33,7 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_PWM (0)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (0)
+#define MICROPY_PY_MACHINE_TIMER_NRF (0)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (0)
diff --git a/ports/nrf/boards/s140_7.3.0.ld b/ports/nrf/boards/s140_7.3.0.ld
new file mode 100644
index 000000000000..47b7665c95ff
--- /dev/null
+++ b/ports/nrf/boards/s140_7.3.0.ld
@@ -0,0 +1,4 @@
+/* GNU linker script for s140 SoftDevice version 7.3.0 */
+
+_sd_size = 0x00027000;
+_sd_ram = 0x0000e000;
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/XIAO_bootloader.ld b/ports/nrf/boards/seeed_xiao_nrf52/XIAO_bootloader.ld
new file mode 100644
index 000000000000..0ff02f2182c2
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/XIAO_bootloader.ld
@@ -0,0 +1,4 @@
+/* GNU linker script for Adafruit nrf52840 Bootloader */
+
+_bootloader_head_size = 0x1000; /* MBR */
+_bootloader_tail_size = 0xC000; /* Bootloader start address 0x000F4000 */
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/board.c b/ports/nrf/boards/seeed_xiao_nrf52/board.c
new file mode 100644
index 000000000000..25c9e1721598
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/board.c
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Arduino SA
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "nrf.h"
+#include "nrf_gpio.h"
+#include "nrf_rtc.h"
+
+#define PIN_ENABLE_SENSORS_3V3 (40)
+#define DFU_MAGIC_SERIAL_ONLY_RESET 0x4e
+#define DFU_MAGIC_UF2_RESET 0x57
+#define DFU_MAGIC_OTA_RESET 0xA8
+
+void XIAO_board_early_init(void) {
+ // Errata XIAOBLE - I2C pullup is on SWO line, need to disable TRACE
+ // was being enabled by nrfx_clock_anomaly_132
+ CoreDebug->DEMCR = 0;
+ NRF_CLOCK->TRACECONFIG = 0;
+
+ // Bootloader enables interrupt on COMPARE[0], which we don't handle
+ // Disable it here to avoid getting stuck when OVERFLOW irq is triggered
+ nrf_rtc_event_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
+ nrf_rtc_int_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
+
+ // Always enable IMU power and I2C Pull-up on startup
+ nrf_gpio_cfg(PIN_ENABLE_SENSORS_3V3,
+ NRF_GPIO_PIN_DIR_OUTPUT,
+ NRF_GPIO_PIN_INPUT_DISCONNECT,
+ NRF_GPIO_PIN_NOPULL,
+ GPIO_PIN_CNF_DRIVE_S0H1,
+ NRF_GPIO_PIN_NOSENSE);
+
+ nrf_gpio_pin_set(PIN_ENABLE_SENSORS_3V3);
+}
+
+void XIAO_board_deinit(void) {
+ nrf_gpio_cfg_output(PIN_ENABLE_SENSORS_3V3);
+
+ nrf_gpio_pin_clear(PIN_ENABLE_SENSORS_3V3);
+}
+
+void XIAO_board_enter_bootloader(void) {
+ __disable_irq();
+ NRF_POWER->GPREGRET = DFU_MAGIC_UF2_RESET;
+ NVIC_SystemReset();
+}
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/board.json b/ports/nrf/boards/seeed_xiao_nrf52/board.json
new file mode 100644
index 000000000000..619a7c23b9e8
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/board.json
@@ -0,0 +1,24 @@
+{
+ "deploy": [
+ "deploy.md"
+ ],
+ "docs": "",
+ "features": [
+ "Bluetooth 5.0",
+ "IMU LSM6DS3TR",
+ "Microphone MSM261D3526H1CPM",
+ "USB-C",
+ "Breadboard Friendly",
+ "Battery Management",
+ "RGB LED",
+ "QSPI Flash"
+ ],
+ "images": [
+ "XIAO_nrf52840_front.jpg"
+ ],
+ "mcu": "nrf52",
+ "product": "SEEED XIAO nRF52840 Sense",
+ "thumbnail": "",
+ "url": "https://www.seeedstudio.com",
+ "vendor": "Seeed Studio"
+}
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/deploy.md b/ports/nrf/boards/seeed_xiao_nrf52/deploy.md
new file mode 100644
index 000000000000..a66731c30946
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/deploy.md
@@ -0,0 +1,31 @@
+The steps below let you create and install the firmware file. For
+a .uf2 type file taken from the MicroPython downloads source only
+step 4 is needed. For the .hex version of the firmware file, steps
+1, 3 and 4 are required.
+
+1. Download and install u2fconv.py. It is available e.g. in the tools
+ directory of MicroPython.
+
+2. Create a firmware for the SEEED nrf52840 if needed, with the command
+
+ `make BOARD=SEEED_XIAO_NRF52 -j5`
+
+ in the directory build-SEEED_XIAO_NRF52-s140. The firmware file will have the
+ name firmware.uf2.
+
+3. Create the .uf2 file if needed in the build directory with the command:
+
+ `uf2conv.py -c -f 0xADA52840 -o firmware.uf2 firmware.hex`
+
+ It must report the start address as 0x27000. If you omit the -o option,
+ the output file will have the name flash.uf2.
+
+4. Enable the upload mode by pushing reset twice or calling
+ machine.bootloader() and copy the file firmware.uf2 to the board drive,
+ which will pop up on your PC.
+
+In case the XIAO bootloader is lost or overwritten, it can be found
+at https://github.com/Seeed-Studio/Adafruit_nRF52_Arduino.git in different
+formats. Using a JLINK adapter or interface, it can be uploaded as hex version.
+The bootloader is as well available through the Arduino IDE.
+
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.h b/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.h
new file mode 100644
index 000000000000..18fbe327d08c
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Glenn Ruben Bakke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#define MICROPY_HW_BOARD_NAME "XIAO nRF52840 Sense"
+#define MICROPY_HW_MCU_NAME "NRF52840"
+#define MICROPY_PY_SYS_PLATFORM "nrf52"
+
+#define MICROPY_BOARD_EARLY_INIT XIAO_board_early_init
+#define MICROPY_BOARD_DEINIT XIAO_board_deinit
+#define MICROPY_BOARD_ENTER_BOOTLOADER(nargs, args) XIAO_board_enter_bootloader()
+
+#define MICROPY_HW_USB_CDC (1)
+#define MICROPY_PY_MACHINE_UART (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_HW_PWM (1)
+#define MICROPY_PY_MACHINE_HW_SPI (1)
+#define MICROPY_PY_MACHINE_RTCOUNTER (1)
+#define MICROPY_PY_MACHINE_I2C (1)
+#define MICROPY_PY_MACHINE_ADC (1)
+#define MICROPY_PY_MACHINE_TEMP (1)
+#define MICROPY_HW_HAS_FLASH (1)
+
+#define MICROPY_HW_ENABLE_RNG (1)
+
+#define MICROPY_HW_HAS_LED (1)
+#define MICROPY_HW_LED_COUNT (4)
+#define MICROPY_HW_LED_PULLUP (1)
+
+#define MICROPY_HW_LED1 (17) // LED1
+#define MICROPY_HW_LED2 (26) // LED2
+#define MICROPY_HW_LED3 (30) // LED3
+#define MICROPY_HW_LED4 (6) // LED4
+
+// UART config
+#define MICROPY_HW_UART1_TX (32 + 11)
+#define MICROPY_HW_UART1_RX (32 + 12)
+
+// SPI0 config
+#define MICROPY_HW_SPI0_NAME "SPI0"
+
+#define MICROPY_HW_SPI0_SCK (32 + 13)
+#define MICROPY_HW_SPI0_MISO (32 + 14)
+#define MICROPY_HW_SPI0_MOSI (32 + 15)
+
+#define MICROPY_HW_PWM0_NAME "PWM0"
+#define MICROPY_HW_PWM1_NAME "PWM1"
+#define MICROPY_HW_PWM2_NAME "PWM2"
+
+#define HELP_TEXT_BOARD_LED "1,2,3,4"
+
+// Enabling these VID/PID values require to include mpconfigboard.h into usb_descriptors.c.
+// But there is an open discussion on whether specific VID/PID values are wanted.
+// 1200BPS touch is not supported at the moment in the USB driver, but at least the flag is set.
+#define MICROPY_HW_USB_VID (0x2886)
+#define MICROPY_HW_USB_PID (0x0045)
+#define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1)
+
+void XIAO_board_early_init(void);
+void XIAO_board_deinit(void);
+void XIAO_board_enter_bootloader(void);
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk b/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk
new file mode 100644
index 000000000000..c2fc219187e3
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/mpconfigboard.mk
@@ -0,0 +1,16 @@
+MCU_SERIES = m4
+MCU_VARIANT = nrf52
+MCU_SUB_VARIANT = nrf52840
+SOFTDEV_VERSION = 7.3.0
+SD=s140
+LD_FILES += boards/seeed_xiao_nrf52/XIAO_bootloader.ld boards/nrf52840_1M_256k.ld
+
+NRF_DEFINES += -DNRF52840_XXAA
+
+MICROPY_VFS_LFS2 = 1
+FS_SIZE = 256k
+
+# DEBUG ?= 1
+
+uf2: hex
+ python3 $(TOP)/tools/uf2conv.py -c -o $(BUILD)/firmware.uf2 -f 0xADA52840 $(BUILD)/firmware.hex
diff --git a/ports/nrf/boards/seeed_xiao_nrf52/pins.csv b/ports/nrf/boards/seeed_xiao_nrf52/pins.csv
new file mode 100644
index 000000000000..6cb050c578a5
--- /dev/null
+++ b/ports/nrf/boards/seeed_xiao_nrf52/pins.csv
@@ -0,0 +1,48 @@
+P0,P0
+P1,P1
+D0_A0,P2
+D1_A1,P3
+D4_A4,P4
+D5_A5,P5
+P6,P6
+IMU_SDA,P7
+P8,P8
+NFC1,P9
+NFC2,P10
+IMU_INT1,P11
+P12,P12
+P13,P13
+READ_BAT,P14
+P15,P15
+PDM_DATA,P16
+P17,P17
+P18,P18
+P19,P19
+QSPI_D0,P20
+QSPI_SCK,P21
+QSPI_D2,P22
+QSPI_D3,P23
+QSPI_D1,P24
+QSPI_CS,P25
+P26,P26
+IMU_SCL,P27
+D2_A2,P28
+D3_A3,P29
+P30,P30
+ADC0_BAT,P31
+PDM_CLK,P32
+P33,P33
+P34,P34
+P35,P35
+P36,P36
+P37,P37
+P38,P38
+P39,P39
+IMU_PWR,P40
+P41,P41
+P42,P42
+UART1_TX,P43
+UART1_RX,P44
+SPI0_SCK,P45
+SPI0_MISO,P46
+SPI0_MOSI,P47
diff --git a/ports/nrf/boards/wt51822_s4at/mpconfigboard.h b/ports/nrf/boards/wt51822_s4at/mpconfigboard.h
index 8117bbd2a6c1..7997aa2697dc 100644
--- a/ports/nrf/boards/wt51822_s4at/mpconfigboard.h
+++ b/ports/nrf/boards/wt51822_s4at/mpconfigboard.h
@@ -32,7 +32,6 @@
#define MICROPY_PY_MACHINE_UART (1)
#define MICROPY_PY_MACHINE_HW_SPI (1)
-#define MICROPY_PY_MACHINE_TIMER (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_ADC (1)
diff --git a/ports/nrf/drivers/bluetooth/ble_drv.c b/ports/nrf/drivers/bluetooth/ble_drv.c
index 173d3eda0152..078c7d995bc0 100644
--- a/ports/nrf/drivers/bluetooth/ble_drv.c
+++ b/ports/nrf/drivers/bluetooth/ble_drv.c
@@ -480,7 +480,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
// do encoding into the adv buffer
if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't encode UUID into advertisment packet"));
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't encode UUID into advertisement packet"));
}
BLE_DRIVER_LOG("encoded uuid for service %u: ", 0);
@@ -528,7 +528,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
// do encoding into the adv buffer
if (sd_ble_uuid_encode(&uuid, &encoded_size, &adv_data[byte_pos]) != 0) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't encode UUID into advertisment packet"));
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't encode UUID into advertisement packet"));
}
BLE_DRIVER_LOG("encoded uuid for service %u: ", 0);
@@ -552,7 +552,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
if ((p_adv_params->data_len > 0) && (p_adv_params->p_data != NULL)) {
if (p_adv_params->data_len + byte_pos > BLE_GAP_ADV_MAX_SIZE) {
- mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't fit data into advertisment packet"));
+ mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("can't fit data into advertisement packet"));
}
memcpy(adv_data, p_adv_params->p_data, p_adv_params->data_len);
@@ -590,12 +590,12 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
#if (BLUETOOTH_SD == 110)
m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
- m_adv_params.timeout = 0; // infinite advertisment
+ m_adv_params.timeout = 0; // infinite advertisement
#else
m_adv_params.properties.anonymous = 0;
m_adv_params.properties.include_tx_power = 0;
m_adv_params.filter_policy = 0;
- m_adv_params.max_adv_evts = 0; // infinite advertisment
+ m_adv_params.max_adv_evts = 0; // infinite advertisement
m_adv_params.primary_phy = BLE_GAP_PHY_AUTO;
m_adv_params.secondary_phy = BLE_GAP_PHY_AUTO;
m_adv_params.scan_req_notification = 0; // Do not raise scan request notifications when scanned.
@@ -606,12 +606,12 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
#if (BLUETOOTH_SD == 110)
if ((err_code = sd_ble_gap_adv_data_set(adv_data, byte_pos, NULL, 0)) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
- MP_ERROR_TEXT("Can not apply advertisment data. status: 0x" HEX2_FMT), (uint16_t)err_code);
+ MP_ERROR_TEXT("Can not apply advertisement data. status: 0x" HEX2_FMT), (uint16_t)err_code);
}
#else
if ((err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &m_adv_params)) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
- MP_ERROR_TEXT("Can not apply advertisment data. status: 0x" HEX2_FMT), (uint16_t)err_code);
+ MP_ERROR_TEXT("Can not apply advertisement data. status: 0x" HEX2_FMT), (uint16_t)err_code);
}
#endif
BLE_DRIVER_LOG("Set Adv data size: " UINT_FMT "\n", byte_pos);
@@ -626,7 +626,7 @@ bool ble_drv_advertise_data(ubluepy_advertise_data_t * p_adv_params) {
#endif
if (err_code != 0) {
mp_raise_msg_varg(&mp_type_OSError,
- MP_ERROR_TEXT("Can not start advertisment. status: 0x" HEX2_FMT), (uint16_t)err_code);
+ MP_ERROR_TEXT("Can not start advertisement. status: 0x" HEX2_FMT), (uint16_t)err_code);
}
m_adv_in_progress = true;
@@ -641,12 +641,12 @@ void ble_drv_advertise_stop(void) {
#if (BLUETOOTH_SD == 110)
if ((err_code = sd_ble_gap_adv_stop()) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
- MP_ERROR_TEXT("Can not stop advertisment. status: 0x" HEX2_FMT), (uint16_t)err_code);
+ MP_ERROR_TEXT("Can not stop advertisement. status: 0x" HEX2_FMT), (uint16_t)err_code);
}
#else
if ((err_code = sd_ble_gap_adv_stop(m_adv_handle)) != 0) {
mp_raise_msg_varg(&mp_type_OSError,
- MP_ERROR_TEXT("Can not stop advertisment. status: 0x" HEX2_FMT), (uint16_t)err_code);
+ MP_ERROR_TEXT("Can not stop advertisement. status: 0x" HEX2_FMT), (uint16_t)err_code);
}
#endif
}
diff --git a/ports/nrf/drivers/bluetooth/ble_uart.c b/ports/nrf/drivers/bluetooth/ble_uart.c
index 3020f1af6267..320657370335 100644
--- a/ports/nrf/drivers/bluetooth/ble_uart.c
+++ b/ports/nrf/drivers/bluetooth/ble_uart.c
@@ -164,6 +164,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
&& !isBufferEmpty(mp_rx_ring_buffer)) {
ret |= MP_STREAM_POLL_RD;
}
+ if ((poll_flags & MP_STREAM_POLL_WR) && ble_uart_enabled()) {
+ ret |= MP_STREAM_POLL_WR;
+ }
return ret;
}
#endif
diff --git a/ports/nrf/drivers/bluetooth/download_ble_stack.sh b/ports/nrf/drivers/bluetooth/download_ble_stack.sh
index 2c3201858399..6498278f496c 100755
--- a/ports/nrf/drivers/bluetooth/download_ble_stack.sh
+++ b/ports/nrf/drivers/bluetooth/download_ble_stack.sh
@@ -57,6 +57,25 @@ function download_s140_nrf52_6_1_1
cd -
}
+function download_s140_nrf52_7_3_0
+{
+ echo ""
+ echo "####################################"
+ echo "### Downloading s140_nrf52_7.3.0 ###"
+ echo "####################################"
+ echo ""
+
+ mkdir -p $1/s140_nrf52_7.3.0
+ cd $1/s140_nrf52_7.3.0
+ wget --post-data="fileName=DeviceDownload&ids=59452FDD13BA46EEAD0810A57359F294" https://www.nordicsemi.com/api/sitecore/Products/MedialibraryZipDownload2
+ mv MedialibraryZipDownload2 temp.zip
+ unzip -u temp.zip
+ unzip -u s140_nrf52_7.3.0.zip
+ rm s140_nrf52_7.3.0.zip
+ rm temp.zip
+ cd -
+}
+
SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ $# -eq 0 ]; then
@@ -64,6 +83,7 @@ if [ $# -eq 0 ]; then
download_s110_nrf51_8_0_0 ${SCRIPT_DIR}
download_s132_nrf52_6_1_1 ${SCRIPT_DIR}
download_s140_nrf52_6_1_1 ${SCRIPT_DIR}
+ download_s140_nrf52_7_3_0 ${SCRIPT_DIR}
else
case $1 in
"s110_nrf51" )
@@ -72,6 +92,8 @@ else
download_s132_nrf52_6_1_1 ${SCRIPT_DIR} ;;
"s140_nrf52_6_1_1" )
download_s140_nrf52_6_1_1 ${SCRIPT_DIR} ;;
+ "s140_nrf52_7_3_0" )
+ download_s140_nrf52_7_3_0 ${SCRIPT_DIR} ;;
esac
fi
diff --git a/ports/nrf/drivers/ticker.c b/ports/nrf/drivers/ticker.c
index 46cc783c4803..c2fa31e7c207 100644
--- a/ports/nrf/drivers/ticker.c
+++ b/ports/nrf/drivers/ticker.c
@@ -137,7 +137,7 @@ int set_ticker_callback(uint32_t index, ticker_callback_ptr func, int32_t initia
ticker->INTENCLR = masks[index];
ticker->TASKS_CAPTURE[index] = 1;
uint32_t t = FastTicker->CC[index];
- // Need to make sure that set tick is aligned to lastest tick
+ // Need to make sure that set tick is aligned to latest tick
// Use CC[3] as a reference, as that is always up-to-date.
int32_t cc3 = FastTicker->CC[3];
int32_t delta = t+initial_delay_us-cc3;
diff --git a/ports/nrf/drivers/usb/usb_cdc.c b/ports/nrf/drivers/usb/usb_cdc.c
index 16d69fff66a3..e33a42548271 100644
--- a/ports/nrf/drivers/usb/usb_cdc.c
+++ b/ports/nrf/drivers/usb/usb_cdc.c
@@ -213,6 +213,9 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
ret |= MP_STREAM_POLL_RD;
}
}
+ if (poll_flags & MP_STREAM_POLL_WR) {
+ ret |= MP_STREAM_POLL_WR;
+ }
return ret;
}
diff --git a/ports/nrf/examples/powerup.py b/ports/nrf/examples/powerup.py
index 2ecc63971c40..156193d002f8 100644
--- a/ports/nrf/examples/powerup.py
+++ b/ports/nrf/examples/powerup.py
@@ -120,13 +120,13 @@ def battery_level(self):
return int(self.char_batt_lvl.read()[0])
def speed(self, new_speed=None):
- if new_speed == None:
+ if new_speed is None:
return int(self.char_control_speed.read()[0])
else:
self.char_control_speed.write(bytearray([new_speed]))
def angle(self, new_angle=None):
- if new_angle == None:
+ if new_angle is None:
return int(self.char_control_angle.read()[0])
else:
self.char_control_angle.write(bytearray([new_angle]))
@@ -187,7 +187,6 @@ def loop(self):
self.old_speed = 0
while True:
-
time.sleep_ms(100)
# read out new angle
diff --git a/ports/nrf/examples/seeed_tft.py b/ports/nrf/examples/seeed_tft.py
index bf246bed4f06..fc0617f20b2d 100644
--- a/ports/nrf/examples/seeed_tft.py
+++ b/ports/nrf/examples/seeed_tft.py
@@ -216,8 +216,6 @@ def show(self):
self.write_cmd(0x2C)
- num_of_pixels = self.height * self.width
-
for row in range(0, self.pages):
for pixel_pos in range(0, 8):
for col in range(0, self.width):
diff --git a/ports/nrf/examples/ubluepy_eddystone.py b/ports/nrf/examples/ubluepy_eddystone.py
index 1ebb2364d541..96818d01c253 100644
--- a/ports/nrf/examples/ubluepy_eddystone.py
+++ b/ports/nrf/examples/ubluepy_eddystone.py
@@ -53,7 +53,7 @@ def generate_eddystone_adv_packet(url):
constants.ad_types.AD_TYPE_SERVICE_DATA, service_data
)
- # generate advertisment packet
+ # generate advertisement packet
packet = bytearray([])
packet.extend(packet_flags)
packet.extend(packet_uuid16)
diff --git a/ports/nrf/examples/ubluepy_temp.py b/ports/nrf/examples/ubluepy_temp.py
index f841849dee81..79c32a9da3b9 100644
--- a/ports/nrf/examples/ubluepy_temp.py
+++ b/ports/nrf/examples/ubluepy_temp.py
@@ -42,7 +42,7 @@ def event_handler(id, handle, data):
rtc.stop()
# indicate 'disconnected'
LED(1).off()
- # restart advertisment
+ # restart advertisement
periph.advertise(device_name="micr_temp", services=[serv_env_sense])
elif id == constants.EVT_GATTS_WRITE:
diff --git a/ports/nrf/help.c b/ports/nrf/help.c
index afc979130f4e..b9ab16da62a6 100644
--- a/ports/nrf/help.c
+++ b/ports/nrf/help.c
@@ -34,7 +34,7 @@
const char nrf5_help_text[] =
"Welcome to MicroPython!\n"
"\n"
- "For online help please visit http://micropython.org/help/.\n"
+ "For online docs please visit http://docs.micropython.org/\n"
"\n"
"Quick overview of commands for the board:\n"
#if MICROPY_HW_HAS_LED
diff --git a/ports/nrf/main.c b/ports/nrf/main.c
index bcfaafd39c7e..7f35c7f1b34b 100644
--- a/ports/nrf/main.c
+++ b/ports/nrf/main.c
@@ -43,7 +43,7 @@
#include "gccollect.h"
#include "modmachine.h"
#include "modmusic.h"
-#include "modules/uos/microbitfs.h"
+#include "modules/os/microbitfs.h"
#include "led.h"
#include "uart.h"
#include "nrf.h"
@@ -156,7 +156,7 @@ int main(int argc, char **argv) {
rtc_init0();
#endif
- #if MICROPY_PY_MACHINE_TIMER
+ #if MICROPY_PY_MACHINE_TIMER_NRF
timer_init0();
#endif
@@ -170,7 +170,7 @@ int main(int argc, char **argv) {
MP_OBJ_NEW_SMALL_INT(0),
MP_OBJ_NEW_SMALL_INT(115200),
};
- MP_STATE_PORT(board_stdio_uart) = MP_OBJ_TYPE_GET_SLOT(&machine_hard_uart_type, make_new)((mp_obj_t)&machine_hard_uart_type, MP_ARRAY_SIZE(args), 0, args);
+ MP_STATE_PORT(board_stdio_uart) = MP_OBJ_TYPE_GET_SLOT(&machine_uart_type, make_new)((mp_obj_t)&machine_uart_type, MP_ARRAY_SIZE(args), 0, args);
}
#endif
@@ -184,7 +184,7 @@ int main(int argc, char **argv) {
int ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point);
if ((ret == -MP_ENODEV) || (ret == -MP_EIO)) {
- pyexec_frozen_module("_mkfs.py"); // Frozen script for formatting flash filesystem.
+ pyexec_frozen_module("_mkfs.py", false); // Frozen script for formatting flash filesystem.
ret = mp_vfs_mount_and_chdir_protected((mp_obj_t)&nrf_flash_obj, mount_point);
}
@@ -280,6 +280,10 @@ int main(int argc, char **argv) {
}
}
+ #if MICROPY_PY_MACHINE_HW_PWM
+ pwm_deinit_all();
+ #endif
+
mp_deinit();
printf("MPY: soft reboot\n");
@@ -297,15 +301,15 @@ int main(int argc, char **argv) {
#if MICROPY_MBFS
// Use micro:bit filesystem
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
- return uos_mbfs_new_reader(filename);
+ return os_mbfs_new_reader(filename);
}
mp_import_stat_t mp_import_stat(const char *path) {
- return uos_mbfs_import_stat(path);
+ return os_mbfs_import_stat(path);
}
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
- return uos_mbfs_open(n_args, args);
+ return os_mbfs_open(n_args, args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
diff --git a/ports/nrf/modules/machine/i2c.c b/ports/nrf/modules/machine/i2c.c
index c16c3669ec57..fad1b7336c95 100644
--- a/ports/nrf/modules/machine/i2c.c
+++ b/ports/nrf/modules/machine/i2c.c
@@ -48,6 +48,7 @@
#define nrfx_twi_config_t nrfx_twim_config_t
#define nrfx_twi_init nrfx_twim_init
+#define nrfx_twi_uninit nrfx_twim_uninit
#define nrfx_twi_enable nrfx_twim_enable
#define nrfx_twi_xfer nrfx_twim_xfer
#define nrfx_twi_disable nrfx_twim_disable
@@ -59,6 +60,8 @@
#define NRFX_TWI_INSTANCE NRFX_TWIM_INSTANCE
+#define NRF_TWI_FREQ_100K NRF_TWIM_FREQ_100K
+#define NRF_TWI_FREQ_250K NRF_TWIM_FREQ_250K
#define NRF_TWI_FREQ_400K NRF_TWIM_FREQ_400K
#endif
@@ -69,8 +72,8 @@ typedef struct _machine_hard_i2c_obj_t {
} machine_hard_i2c_obj_t;
STATIC const machine_hard_i2c_obj_t machine_hard_i2c_obj[] = {
- {{&machine_hard_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(0)},
- {{&machine_hard_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(1)},
+ {{&machine_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(0)},
+ {{&machine_i2c_type}, .p_twi = NRFX_TWI_INSTANCE(1)},
};
void i2c_init0(void) {
@@ -96,11 +99,12 @@ STATIC void machine_hard_i2c_print(const mp_print_t *print, mp_obj_t self_in, mp
mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
MP_MACHINE_I2C_CHECK_FOR_LEGACY_SOFTI2C_CONSTRUCTION(n_args, n_kw, all_args);
- enum { ARG_id, ARG_scl, ARG_sda };
+ enum { ARG_id, ARG_scl, ARG_sda, ARG_freq };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
};
// parse args
@@ -115,10 +119,21 @@ mp_obj_t machine_hard_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz
config.scl = mp_hal_get_pin_obj(args[ARG_scl].u_obj)->pin;
config.sda = mp_hal_get_pin_obj(args[ARG_sda].u_obj)->pin;
- config.frequency = NRF_TWI_FREQ_400K;
+ int freq = NRF_TWI_FREQ_400K;
+ if (args[ARG_freq].u_int != -1) {
+ if (args[ARG_freq].u_int <= 150000) {
+ freq = NRF_TWI_FREQ_100K;
+ } else if (args[ARG_freq].u_int < 320000) {
+ freq = NRF_TWI_FREQ_250K;
+ }
+ }
+ config.frequency = freq;
config.hold_bus_uninit = false;
+ // First reset the TWI
+ nrfx_twi_uninit(&self->p_twi);
+
// Set context to this object.
nrfx_twi_init(&self->p_twi, &config, NULL, (void *)self);
@@ -162,7 +177,7 @@ STATIC const mp_machine_i2c_p_t machine_hard_i2c_p = {
};
MP_DEFINE_CONST_OBJ_TYPE(
- machine_hard_i2c_type,
+ machine_i2c_type,
MP_QSTR_I2C,
MP_TYPE_FLAG_NONE,
make_new, machine_hard_i2c_make_new,
diff --git a/ports/nrf/modules/machine/i2c.h b/ports/nrf/modules/machine/i2c.h
index 1dfb1f077a44..5c5befc28535 100644
--- a/ports/nrf/modules/machine/i2c.h
+++ b/ports/nrf/modules/machine/i2c.h
@@ -29,7 +29,7 @@
#include "extmod/machine_i2c.h"
-extern const mp_obj_type_t machine_hard_i2c_type;
+extern const mp_obj_type_t machine_i2c_type;
void i2c_init0(void);
diff --git a/ports/nrf/modules/machine/modmachine.c b/ports/nrf/modules/machine/modmachine.c
index d322e450671f..616757a96aea 100644
--- a/ports/nrf/modules/machine/modmachine.c
+++ b/ports/nrf/modules/machine/modmachine.c
@@ -42,7 +42,7 @@
#include "spi.h"
#include "i2c.h"
#include "timer.h"
-#if MICROPY_PY_MACHINE_HW_PWM
+#if MICROPY_PY_MACHINE_HW_PWM || MICROPY_PY_MACHINE_SOFT_PWM
#include "pwm.h"
#endif
#if MICROPY_PY_MACHINE_ADC
@@ -133,7 +133,7 @@ STATIC mp_obj_t machine_info(mp_uint_t n_args, const mp_obj_t *args) {
if (n_args == 1) {
// arg given means dump gc allocation table
- gc_dump_alloc_table();
+ gc_dump_alloc_table(&mp_plat_print);
}
return mp_const_none;
@@ -160,6 +160,12 @@ NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_bootloader_obj, 0, 1, machine_bootloader);
+STATIC mp_obj_t machine_idle(void) {
+ MICROPY_EVENT_POLL_HOOK;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
+
STATIC mp_obj_t machine_lightsleep(void) {
__WFE();
return mp_const_none;
@@ -199,14 +205,14 @@ STATIC mp_obj_t machine_disable_irq(void) {
MP_DEFINE_CONST_FUN_OBJ_0(machine_disable_irq_obj, machine_disable_irq);
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
- { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&machine_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&machine_soft_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_irq), MP_ROM_PTR(&machine_enable_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
- { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_lightsleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_lightsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_lightsleep), MP_ROM_PTR(&machine_lightsleep_obj) },
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
@@ -217,13 +223,13 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
#if MICROPY_PY_MACHINE_UART
- { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_hard_uart_type) },
+ { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
#endif
#if MICROPY_PY_MACHINE_HW_SPI
- { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_hard_spi_type) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
#endif
#if MICROPY_PY_MACHINE_I2C
- { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_hard_i2c_type) },
+ { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
#endif
#if MICROPY_PY_MACHINE_ADC
@@ -232,11 +238,11 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_RTCOUNTER
{ MP_ROM_QSTR(MP_QSTR_RTCounter), MP_ROM_PTR(&machine_rtcounter_type) },
#endif
-#if MICROPY_PY_MACHINE_TIMER
+#if MICROPY_PY_MACHINE_TIMER_NRF
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) },
#endif
-#if MICROPY_PY_MACHINE_HW_PWM
- { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_hard_pwm_type) },
+#if MICROPY_PY_MACHINE_HW_PWM || MICROPY_PY_MACHINE_SOFT_PWM
+ { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
#endif
#if MICROPY_PY_MACHINE_TEMP
{ MP_ROM_QSTR(MP_QSTR_Temp), MP_ROM_PTR(&machine_temp_type) },
@@ -260,6 +266,6 @@ const mp_obj_module_t mp_module_machine = {
.globals = (mp_obj_dict_t*)&machine_module_globals,
};
-MP_REGISTER_MODULE(MP_QSTR_umachine, mp_module_machine);
+MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_machine, mp_module_machine);
#endif // MICROPY_PY_MACHINE
diff --git a/ports/nrf/modules/machine/pin.c b/ports/nrf/modules/machine/pin.c
index db5cc9cbb136..974074fc9126 100644
--- a/ports/nrf/modules/machine/pin.c
+++ b/ports/nrf/modules/machine/pin.c
@@ -618,7 +618,7 @@ MP_DEFINE_CONST_OBJ_TYPE(
/// x3 = machine.Pin.board.X3
/// x3_af = x3.af_list()
///
-/// x3_af will now contain an array of PinAF objects which are availble on
+/// x3_af will now contain an array of PinAF objects which are available on
/// pin X3.
///
/// For the pyboard, x3_af would contain:
diff --git a/ports/nrf/modules/machine/pwm.c b/ports/nrf/modules/machine/pwm.c
index 862e1907cbf3..96917769eed4 100644
--- a/ports/nrf/modules/machine/pwm.c
+++ b/ports/nrf/modules/machine/pwm.c
@@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2016-2018 Glenn Ruben Bakke
+ * Copyright (c) 2023 Robert Hammelrath
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -42,310 +43,355 @@
#include "nrfx_pwm.h"
#endif
+#define PWM_MAX_BASE_FREQ (16000000)
+#define PWM_MIN_BASE_FREQ (125000)
+#define PWM_MAX_PERIOD (32768)
+
typedef enum {
- MODE_LOW_HIGH,
- MODE_HIGH_LOW
+ MODE_HIGH_LOW = 0,
+ MODE_LOW_HIGH
} pwm_mode_t;
+typedef enum {
+ DUTY_NOT_SET = 0,
+ DUTY_PERCENT,
+ DUTY_U16,
+ DUTY_NS
+} pwm_duty_t;
+
+typedef enum {
+ FREE = 0,
+ STOPPED,
+ RUNNING
+} pwm_run_t;
+
typedef struct {
- uint8_t pwm_pin;
- uint8_t duty;
- uint16_t pulse_width;
- uint16_t period;
- nrf_pwm_clk_t freq;
- pwm_mode_t mode;
+ uint8_t pwm_pin[NRF_PWM_CHANNEL_COUNT];
+ pwm_mode_t mode[NRF_PWM_CHANNEL_COUNT];
+ pwm_duty_t duty_mode[NRF_PWM_CHANNEL_COUNT];
+ uint32_t duty[NRF_PWM_CHANNEL_COUNT];
+ uint16_t pwm_seq[4];
+ pwm_run_t active;
+ bool defer_start;
+ int8_t freq_div;
+ uint32_t freq;
} machine_pwm_config_t;
-typedef struct _machine_hard_pwm_obj_t {
- mp_obj_base_t base;
- const nrfx_pwm_t * p_pwm;
- machine_pwm_config_t * p_config;
-} machine_hard_pwm_obj_t;
+typedef struct _machine_pwm_obj_t {
+ mp_obj_base_t base;
+ const nrfx_pwm_t *p_pwm;
+ machine_pwm_config_t *p_config;
+ uint8_t id;
+ uint8_t channel;
+} machine_pwm_obj_t;
STATIC const nrfx_pwm_t machine_hard_pwm_instances[] = {
-#if defined(NRF52_SERIES)
+ #if defined(NRF52_SERIES)
NRFX_PWM_INSTANCE(0),
NRFX_PWM_INSTANCE(1),
NRFX_PWM_INSTANCE(2),
-#if NRF52840
+ #if NRF52840
NRFX_PWM_INSTANCE(3),
-#endif
-#endif
+ #endif
+ #endif
};
STATIC machine_pwm_config_t hard_configs[MP_ARRAY_SIZE(machine_hard_pwm_instances)];
-STATIC const machine_hard_pwm_obj_t machine_hard_pwm_obj[] = {
-#if defined(NRF52_SERIES)
- {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0]},
- {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1]},
- {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2]},
-#if NRF52840
- {{&machine_hard_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3]},
-#endif
-#endif
+STATIC const machine_pwm_obj_t machine_hard_pwm_obj[] = {
+ #if defined(NRF52_SERIES)
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0], 0, 0},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0], 0, 1},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0], 0, 2},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[0], .p_config = &hard_configs[0], 0, 3},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1], 1, 0},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1], 1, 1},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1], 1, 2},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[1], .p_config = &hard_configs[1], 1, 3},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2], 2, 0},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2], 2, 1},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2], 2, 2},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[2], .p_config = &hard_configs[2], 2, 3},
+ #if NRF52840
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3], 3, 0},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3], 3, 1},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3], 3, 2},
+ {{&machine_pwm_type}, .p_pwm = &machine_hard_pwm_instances[3], .p_config = &hard_configs[3], 3, 3},
+ #endif
+ #endif
};
void pwm_init0(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(hard_configs); i++) {
+ hard_configs[i].active = FREE;
+ hard_configs[i].freq_div = -1;
+ hard_configs[i].freq = 0;
+ memset(hard_configs[i].duty_mode, DUTY_NOT_SET, NRF_PWM_CHANNEL_COUNT);
+ }
}
-
-STATIC int hard_pwm_find(mp_obj_t id) {
- if (mp_obj_is_int(id)) {
- // given an integer id
- int pwm_id = mp_obj_get_int(id);
- if (pwm_id >= 0 && pwm_id < MP_ARRAY_SIZE(machine_hard_pwm_obj)) {
- return pwm_id;
+// Find a free PWM object
+STATIC int hard_pwm_find() {
+ // look for a free module.
+ for (int j = 0; j < MP_ARRAY_SIZE(hard_configs); j++) {
+ if (hard_configs[j].active == FREE) {
+ return j * NRF_PWM_CHANNEL_COUNT;
}
- mp_raise_ValueError(MP_ERROR_TEXT("PWM doesn't exist"));
}
- return -1;
+ mp_raise_ValueError(MP_ERROR_TEXT("all PWM devices in use"));
}
-STATIC void machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
- machine_hard_pwm_obj_t *self = self_in;
- mp_printf(print, "PWM(%u)", self->p_pwm->drv_inst_idx);
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_pwm_obj_t *self = self_in;
+ static char *duty_suffix[] = { "", "", "_u16", "_ns" };
+ mp_printf(print, "",
+ self->p_config->pwm_pin[self->channel], self->p_config->freq,
+ duty_suffix[self->p_config->duty_mode[self->channel]], self->p_config->duty[self->channel],
+ self->p_config->mode[self->channel], self->id, self->channel);
}
/******************************************************************************/
/* MicroPython bindings for machine API */
-STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args);
-STATIC void machine_hard_pwm_init(mp_obj_t self, mp_arg_val_t *args);
-STATIC void machine_hard_pwm_deinit(mp_obj_t self);
-STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self, mp_arg_val_t *args);
-
-/* common code for both soft and hard implementations *************************/
-
-STATIC mp_obj_t machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
- enum { ARG_id, ARG_pin, ARG_freq, ARG_period, ARG_duty, ARG_pulse_width, ARG_mode };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} },
- { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_period, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_pulse_width, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- { MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
- };
-
- // parse args
- mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
-
- if (args[ARG_id].u_obj == MP_OBJ_NEW_SMALL_INT(-1)) {
- // TODO: implement soft PWM
- // return machine_soft_pwm_make_new(args);
- return mp_const_none;
- } else {
- // hardware peripheral id given
- return machine_hard_pwm_make_new(args);
- }
-}
+STATIC void machine_hard_pwm_start(const machine_pwm_obj_t *self);
+STATIC void mp_machine_pwm_deinit(const machine_pwm_obj_t *self);
+STATIC void mp_machine_pwm_freq_set(const machine_pwm_obj_t *self, mp_int_t freq);
+STATIC void mp_machine_pwm_duty_set(const machine_pwm_obj_t *self, mp_int_t duty);
+STATIC void mp_machine_pwm_duty_set_u16(const machine_pwm_obj_t *self, mp_int_t duty_u16);
+STATIC void mp_machine_pwm_duty_set_ns(const machine_pwm_obj_t *self, mp_int_t duty_ns);
+
+static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pin, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty_u16, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_duty_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_device, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+};
-STATIC mp_obj_t machine_pwm_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_INIT_pin };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }
- };
+STATIC void mp_machine_pwm_init_helper(const machine_pwm_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_pin, ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns, ARG_invert, ARG_device, ARG_channel };
- // parse args
- mp_obj_t self = pos_args[0];
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- // dispatch to specific implementation
- if (mp_obj_get_type(self) == &machine_hard_pwm_type) {
- machine_hard_pwm_init(self, args);
+ self->p_config->defer_start = true;
+ if (args[ARG_freq].u_int != -1) {
+ mp_machine_pwm_freq_set(self, args[ARG_freq].u_int);
+ }
+ if (args[ARG_duty].u_int != -1) {
+ mp_machine_pwm_duty_set(self, args[ARG_duty].u_int);
+ }
+ if (args[ARG_duty_u16].u_int != -1) {
+ mp_machine_pwm_duty_set_u16(self, args[ARG_duty_u16].u_int);
}
+ if (args[ARG_duty_ns].u_int != -1) {
+ mp_machine_pwm_duty_set_ns(self, args[ARG_duty_ns].u_int);
+ }
+ if (args[ARG_invert].u_int != -1) {
+ self->p_config->mode[self->channel] = args[ARG_invert].u_int ? MODE_LOW_HIGH : MODE_HIGH_LOW;
+ }
+ self->p_config->defer_start = false;
- return mp_const_none;
+ machine_hard_pwm_start(self);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_pwm_init_obj, 1, machine_pwm_init);
-STATIC mp_obj_t machine_pwm_deinit(mp_obj_t self) {
- // dispatch to specific implementation
- if (mp_obj_get_type(self) == &machine_hard_pwm_type) {
- machine_hard_pwm_deinit(self);
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pwm_deinit_obj, machine_pwm_deinit);
-STATIC mp_obj_t machine_pwm_freq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
- enum { ARG_FREQ_freq };
- static const mp_arg_t allowed_args[] = {
- { MP_QSTR_freq, MP_ARG_INT, {.u_int = -1} },
- };
+STATIC mp_obj_t mp_machine_pwm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_pin, ARG_freq, ARG_duty, ARG_duty_u16, ARG_duty_ns, ARG_invert, ARG_device, ARG_channel };
- mp_obj_t self = pos_args[0];
+ // parse args
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
- mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- if (mp_obj_get_type(self) == &machine_hard_pwm_type) {
- machine_hard_pwm_freq(self, args);
+ // check if the PWM pin is given.
+ int pwm_pin;
+ if (args[ARG_pin].u_obj != MP_OBJ_NULL) {
+ pwm_pin = mp_hal_get_pin_obj(args[ARG_pin].u_obj)->pin;
} else {
- // soft pwm
+ mp_raise_ValueError(MP_ERROR_TEXT("Pin missing"));
}
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mp_machine_pwm_freq_obj, 1, machine_pwm_freq);
+ // Get the PWM object number
+ // If just the ID is given, use channel 0
+ // If none is given, attempt to find an unused object.
+ int pwm_id = -1;
+ if (args[ARG_device].u_int != -1) {
+ if (args[ARG_device].u_int >= 0 && args[ARG_device].u_int < MP_ARRAY_SIZE(machine_hard_pwm_instances)) {
+ pwm_id = args[ARG_device].u_int * NRF_PWM_CHANNEL_COUNT;
+ if (args[ARG_channel].u_int != -1) {
+ if (args[ARG_channel].u_int >= 0 && args[ARG_channel].u_int < NRF_PWM_CHANNEL_COUNT) {
+ pwm_id += args[ARG_channel].u_int;
+ }
+ }
+ }
+ } else {
+ // no ID given, search for a free ID.
+ pwm_id = hard_pwm_find();
+ }
+ if (pwm_id < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid PWM id"));
+ }
+ const machine_pwm_obj_t *self = &machine_hard_pwm_obj[pwm_id];
+ int pwm_channel = pwm_id % NRF_PWM_CHANNEL_COUNT;
+ self->p_config->pwm_pin[pwm_channel] = pwm_pin;
+ self->p_config->duty_mode[pwm_channel] = DUTY_NOT_SET;
+ self->p_config->duty[pwm_channel] = 0;
+ self->p_config->mode[pwm_channel] = MODE_HIGH_LOW;
+ self->p_config->defer_start = false;
+
+ // start the PWM running for this channel
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
+ mp_machine_pwm_init_helper(self, n_args, all_args, &kw_args);
-STATIC mp_obj_t machine_pwm_period(size_t n_args, const mp_obj_t *args) {
- return mp_const_none;
+ return MP_OBJ_FROM_PTR(self);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_period_obj, 1, 2, machine_pwm_period);
-STATIC mp_obj_t machine_pwm_duty(size_t n_args, const mp_obj_t *args) {
- return mp_const_none;
+// Stop all PWM modules and release them
+void pwm_deinit_all(void) {
+ for (int i = 0; i < MP_ARRAY_SIZE(machine_hard_pwm_instances); i++) {
+ mp_machine_pwm_deinit(&machine_hard_pwm_obj[i * NRF_PWM_CHANNEL_COUNT]);
+ }
+ pwm_init0();
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_pwm_duty_obj, 1, 2, machine_pwm_duty);
-
-STATIC const mp_rom_map_elem_t machine_pwm_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_pwm_init_obj) },
- { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_pwm_deinit_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&mp_machine_pwm_freq_obj) },
- { MP_ROM_QSTR(MP_QSTR_period), MP_ROM_PTR(&mp_machine_pwm_period_obj) },
- { MP_ROM_QSTR(MP_QSTR_duty), MP_ROM_PTR(&mp_machine_pwm_duty_obj) },
-
- { MP_ROM_QSTR(MP_QSTR_FREQ_16MHZ), MP_ROM_INT(NRF_PWM_CLK_16MHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_8MHZ), MP_ROM_INT(NRF_PWM_CLK_8MHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_4MHZ), MP_ROM_INT(NRF_PWM_CLK_4MHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_2MHZ), MP_ROM_INT(NRF_PWM_CLK_2MHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_1MHZ), MP_ROM_INT(NRF_PWM_CLK_1MHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_500KHZ), MP_ROM_INT(NRF_PWM_CLK_500kHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_250KHZ), MP_ROM_INT(NRF_PWM_CLK_250kHz) },
- { MP_ROM_QSTR(MP_QSTR_FREQ_125KHZ), MP_ROM_INT(NRF_PWM_CLK_125kHz) },
-
- { MP_ROM_QSTR(MP_QSTR_MODE_LOW_HIGH), MP_ROM_INT(MODE_LOW_HIGH) },
- { MP_ROM_QSTR(MP_QSTR_MODE_HIGH_LOW), MP_ROM_INT(MODE_HIGH_LOW) },
-};
-STATIC MP_DEFINE_CONST_DICT(machine_pwm_locals_dict, machine_pwm_locals_dict_table);
+// Stop the PWM module, but do not release it.
+STATIC void mp_machine_pwm_deinit(const machine_pwm_obj_t *self) {
+ self->p_config->active = STOPPED;
+ nrfx_pwm_stop(self->p_pwm, true);
+ nrfx_pwm_uninit(self->p_pwm);
+}
-/* code for hard implementation ***********************************************/
+STATIC mp_obj_t mp_machine_pwm_freq_get(const machine_pwm_obj_t *self) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->freq);
+}
-STATIC mp_obj_t machine_hard_pwm_make_new(mp_arg_val_t *args) {
- enum { ARG_id, ARG_pin, ARG_freq, ARG_period, ARG_duty, ARG_pulse_width, ARG_mode };
- // get static peripheral object
- int pwm_id = hard_pwm_find(args[ARG_id].u_obj);
- const machine_hard_pwm_obj_t *self = &machine_hard_pwm_obj[pwm_id];
+STATIC void mp_machine_pwm_freq_set(const machine_pwm_obj_t *self, mp_int_t freq) {
- // check if PWM pin is set
- if (args[ARG_pin].u_obj != MP_OBJ_NULL) {
- self->p_config->pwm_pin = mp_hal_get_pin_obj(args[ARG_pin].u_obj)->pin;
- } else {
- // TODO: raise exception.
+ uint8_t div = 0;
+ if (freq > (PWM_MAX_BASE_FREQ / 3) || freq <= (PWM_MIN_BASE_FREQ / PWM_MAX_PERIOD)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("frequency out of range"));
}
-
- if (args[ARG_freq].u_obj != MP_OBJ_NULL) {
- self->p_config->freq = mp_obj_get_int(args[ARG_freq].u_obj);
- } else {
- self->p_config->freq = 50; // 50 Hz by default.
+ for (div = 0; div < 8; div++) {
+ if (PWM_MAX_BASE_FREQ / (1 << div) / freq < PWM_MAX_PERIOD) {
+ break;
+ }
}
+ self->p_config->freq_div = div;
+ self->p_config->freq = freq;
+ machine_hard_pwm_start(self);
+}
- if (args[ARG_period].u_obj != MP_OBJ_NULL) {
- self->p_config->period = mp_obj_get_int(args[ARG_period].u_obj);
+STATIC mp_obj_t mp_machine_pwm_duty_get(const machine_pwm_obj_t *self) {
+ if (self->p_config->duty_mode[self->channel] == DUTY_PERCENT) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->duty[self->channel]);
+ } else if (self->p_config->duty_mode[self->channel] == DUTY_U16) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->duty[self->channel] * 100 / 65536);
} else {
- mp_raise_ValueError(MP_ERROR_TEXT("PWM period must be within 16000 cycles"));
+ return MP_OBJ_NEW_SMALL_INT(-1);
}
+}
- if (args[ARG_duty].u_obj != MP_OBJ_NULL) {
- self->p_config->duty = mp_obj_get_int(args[ARG_duty].u_obj);
- } else {
- self->p_config->duty = 50; // 50% by default.
- }
+STATIC void mp_machine_pwm_duty_set(const machine_pwm_obj_t *self, mp_int_t duty) {
+ self->p_config->duty[self->channel] = duty;
+ self->p_config->duty_mode[self->channel] = DUTY_PERCENT;
+ machine_hard_pwm_start(self);
+}
- if (args[ARG_pulse_width].u_obj != MP_OBJ_NULL) {
- self->p_config->pulse_width = mp_obj_get_int(args[ARG_pulse_width].u_obj);
+STATIC mp_obj_t mp_machine_pwm_duty_get_u16(const machine_pwm_obj_t *self) {
+ if (self->p_config->duty_mode[self->channel] == DUTY_U16) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->duty[self->channel]);
+ } else if (self->p_config->duty_mode[self->channel] == DUTY_PERCENT) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->duty[self->channel] * 65536 / 100);
} else {
- self->p_config->pulse_width = 0;
+ return MP_OBJ_NEW_SMALL_INT(-1);
}
+}
+
+STATIC void mp_machine_pwm_duty_set_u16(const machine_pwm_obj_t *self, mp_int_t duty) {
+ self->p_config->duty[self->channel] = duty;
+ self->p_config->duty_mode[self->channel] = DUTY_U16;
+ machine_hard_pwm_start(self);
+}
- if (args[ARG_mode].u_obj != MP_OBJ_NULL) {
- self->p_config->mode = mp_obj_get_int(args[ARG_mode].u_obj);
+STATIC mp_obj_t mp_machine_pwm_duty_get_ns(const machine_pwm_obj_t *self) {
+ if (self->p_config->duty_mode[self->channel] == DUTY_NS) {
+ return MP_OBJ_NEW_SMALL_INT(self->p_config->duty[self->channel]);
} else {
- self->p_config->mode = MODE_HIGH_LOW;
+ return MP_OBJ_NEW_SMALL_INT(-1);
}
+}
- return MP_OBJ_FROM_PTR(self);
+STATIC void mp_machine_pwm_duty_set_ns(const machine_pwm_obj_t *self, mp_int_t duty) {
+ self->p_config->duty[self->channel] = duty;
+ self->p_config->duty_mode[self->channel] = DUTY_NS;
+ machine_hard_pwm_start(self);
}
-STATIC void machine_hard_pwm_init(mp_obj_t self_in, mp_arg_val_t *args) {
- machine_hard_pwm_obj_t *self = self_in;
+/* code for hard implementation ***********************************************/
+
+STATIC void machine_hard_pwm_start(const machine_pwm_obj_t *self) {
nrfx_pwm_config_t config;
- config.output_pins[0] = self->p_config->pwm_pin;
- config.output_pins[1] = NRFX_PWM_PIN_NOT_USED;
- config.output_pins[2] = NRFX_PWM_PIN_NOT_USED;
- config.output_pins[3] = NRFX_PWM_PIN_NOT_USED;
+ // check if ready to go
+ if (self->p_config->defer_start == true || self->p_config->freq_div < 0 || self->p_config->duty_mode[self->channel] == DUTY_NOT_SET) {
+ return; // Not ready yet.
+ }
- config.irq_priority = 6;
- config.base_clock = self->p_config->freq;
- config.count_mode = NRF_PWM_MODE_UP;
- config.top_value = self->p_config->period;
- config.load_mode = NRF_PWM_LOAD_INDIVIDUAL;
- config.step_mode = NRF_PWM_STEP_AUTO;
+ self->p_config->active = RUNNING;
- nrfx_pwm_init(self->p_pwm, &config, NULL, NULL);
+ config.output_pins[0] = self->p_config->duty_mode[0] != DUTY_NOT_SET ? self->p_config->pwm_pin[0] : NRFX_PWM_PIN_NOT_USED;
+ config.output_pins[1] = self->p_config->duty_mode[1] != DUTY_NOT_SET ? self->p_config->pwm_pin[1] : NRFX_PWM_PIN_NOT_USED;
+ config.output_pins[2] = self->p_config->duty_mode[2] != DUTY_NOT_SET ? self->p_config->pwm_pin[2] : NRFX_PWM_PIN_NOT_USED;
+ config.output_pins[3] = self->p_config->duty_mode[3] != DUTY_NOT_SET ? self->p_config->pwm_pin[3] : NRFX_PWM_PIN_NOT_USED;
- uint16_t pulse_width = ((self->p_config->period * self->p_config->duty) / 100);
+ uint32_t tick_freq = PWM_MAX_BASE_FREQ / (1 << self->p_config->freq_div);
+ uint32_t period = tick_freq / self->p_config->freq;
- // If manual period has been set, override duty-cycle.
- if (self->p_config->pulse_width > 0) {
- pulse_width = self->p_config->pulse_width;
- }
+ config.irq_priority = 6;
+ config.base_clock = self->p_config->freq_div;
+ config.count_mode = NRF_PWM_MODE_UP;
+ config.top_value = period;
+ config.load_mode = NRF_PWM_LOAD_INDIVIDUAL;
+ config.step_mode = NRF_PWM_STEP_AUTO;
- // TODO: Move DMA buffer to global memory.
- volatile static uint16_t pwm_seq[4];
+ nrfx_pwm_stop(self->p_pwm, true);
+ nrfx_pwm_uninit(self->p_pwm);
- if (self->p_config->mode == MODE_HIGH_LOW) {
- pwm_seq[0] = self->p_config->period - pulse_width;
- pwm_seq[1] = self->p_config->period - pulse_width;
- } else {
- pwm_seq[0] = self->p_config->period - pulse_width;
- pwm_seq[1] = self->p_config->period - pulse_width;
- }
+ nrfx_pwm_init(self->p_pwm, &config, NULL, NULL);
- pwm_seq[2] = self->p_config->period - pulse_width;
- pwm_seq[3] = self->p_config->period - pulse_width;
+ for (int i = 0; i < NRF_PWM_CHANNEL_COUNT; i++) {
+ uint16_t pulse_width = 0;
+ if (self->p_config->duty_mode[i] == DUTY_PERCENT) {
+ pulse_width = ((period * self->p_config->duty[i]) / 100);
+ } else if (self->p_config->duty_mode[i] == DUTY_U16) {
+ pulse_width = ((period * self->p_config->duty[i]) / 65536);
+ } else if (self->p_config->duty_mode[i] == DUTY_NS) {
+ pulse_width = (uint64_t)self->p_config->duty[i] * tick_freq / 1000000000ULL;
+ }
+
+ if (self->p_config->mode[i] == MODE_HIGH_LOW) {
+ self->p_config->pwm_seq[i] = 0x8000 | pulse_width;
+ } else {
+ self->p_config->pwm_seq[i] = pulse_width;
+ }
+ }
const nrf_pwm_sequence_t pwm_sequence = {
- .values.p_raw = (const uint16_t *)&pwm_seq,
+ .values.p_raw = (const uint16_t *)&self->p_config->pwm_seq,
.length = 4,
.repeats = 0,
.end_delay = 0
};
nrfx_pwm_simple_playback(self->p_pwm,
- &pwm_sequence,
- 0, // Loop disabled.
- 0);
-}
-
-STATIC void machine_hard_pwm_deinit(mp_obj_t self_in) {
- machine_hard_pwm_obj_t *self = self_in;
- (void)self;
- nrfx_pwm_stop(self->p_pwm, true);
- nrfx_pwm_uninit(self->p_pwm);
+ &pwm_sequence,
+ 0, // Loop disabled.
+ 0);
}
-STATIC mp_obj_t machine_hard_pwm_freq(mp_obj_t self_in, mp_arg_val_t *args) {
- machine_hard_pwm_obj_t *self = self_in;
- (void)self;
- return mp_const_none;
-}
-
-MP_DEFINE_CONST_OBJ_TYPE(
- machine_hard_pwm_type,
- MP_QSTR_PWM,
- MP_TYPE_FLAG_NONE,
- make_new, machine_pwm_make_new,
- print, machine_pwm_print,
- locals_dict, &machine_pwm_locals_dict
- );
-
#endif // MICROPY_PY_MACHINE_HW_PWM
diff --git a/ports/nrf/modules/machine/pwm.h b/ports/nrf/modules/machine/pwm.h
index 7a5b72e0e84f..4c0528fb4cf3 100644
--- a/ports/nrf/modules/machine/pwm.h
+++ b/ports/nrf/modules/machine/pwm.h
@@ -25,5 +25,6 @@
*/
void pwm_init0(void);
+void pwm_deinit_all(void);
-extern const mp_obj_type_t machine_hard_pwm_type;
+extern const mp_obj_type_t machine_pwm_type;
diff --git a/ports/nrf/modules/machine/soft_pwm.c b/ports/nrf/modules/machine/soft_pwm.c
new file mode 100644
index 000000000000..27783328eb8c
--- /dev/null
+++ b/ports/nrf/modules/machine/soft_pwm.c
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2023 Robert Hammelrath
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include
+#include "py/runtime.h"
+#include "py/mphal.h"
+
+#if MICROPY_PY_MACHINE_SOFT_PWM
+
+#include "softpwm.h"
+
+typedef enum {
+ DUTY_NOT_SET = 0,
+ DUTY,
+ DUTY_U16,
+ DUTY_NS
+} pwm_duty_t;
+
+typedef struct _machine_pwm_obj_t {
+ mp_obj_base_t base;
+ uint8_t pwm_pin;
+ bool defer_start;
+ uint8_t duty_mode;
+ uint32_t duty;
+ uint32_t freq;
+} machine_pwm_obj_t;
+
+#define SOFT_PWM_BASE_FREQ (1000000)
+#define DUTY_FULL_SCALE (1024)
+
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_pwm_obj_t *self = self_in;
+ static char *duty_suffix[] = { "", "", "_u16", "_ns" };
+ mp_printf(print, "